| // |
| // Copyright 2025 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. |
| // |
| // FrameCaptureCL.cpp: |
| // ANGLE CL Frame capture implementation. |
| // |
| #include "libANGLE/capture/FrameCapture.h" |
| |
| #include "common/angle_version_info.h" |
| #include "common/frame_capture_utils.h" |
| #include "common/serializer/JsonSerializer.h" |
| #include "common/string_utils.h" |
| #include "common/system_utils.h" |
| #include "libANGLE/CLBuffer.h" |
| #include "libANGLE/CLCommandQueue.h" |
| #include "libANGLE/CLContext.h" |
| #include "libANGLE/CLImage.h" |
| #include "libANGLE/CLProgram.h" |
| #include "libANGLE/capture/capture_cl_autogen.h" |
| #include "libANGLE/capture/serialize.h" |
| #include "libANGLE/cl_utils.h" |
| #include "libGLESv2/cl_stubs_autogen.h" |
| |
| #if !ANGLE_CAPTURE_ENABLED |
| # error Frame capture must be enabled to include this file. |
| #endif // !ANGLE_CAPTURE_ENABLED |
| |
| #ifndef ANGLE_ENABLE_CL |
| # error OpenCL must be enabled to include this file. |
| #endif // !ANGLE_ENABLE_CL |
| |
| namespace angle |
| { |
| |
| // Some replay functions can get quite large. If over a certain size, this method breaks up the |
| // function into parts to avoid overflowing the stack and causing slow compilation. |
| void WriteCppReplayFunctionWithPartsCL(ReplayFunc replayFunc, |
| ReplayWriter &replayWriter, |
| uint32_t frameIndex, |
| std::vector<uint8_t> *binaryData, |
| const std::vector<CallCapture> &calls, |
| std::stringstream &header, |
| std::stringstream &out) |
| { |
| out << "void " |
| << FmtFunction(replayFunc, kNoContextId, FuncUsage::Definition, frameIndex, kNoPartId) |
| << "\n" |
| << "{\n"; |
| |
| for (const CallCapture &call : calls) |
| { |
| // Process active calls for Setup and inactive calls for SetupInactive |
| if ((call.isActive && replayFunc != ReplayFunc::SetupInactive) || |
| (!call.isActive && replayFunc == ReplayFunc::SetupInactive)) |
| { |
| out << " "; |
| WriteCppReplayForCallCL(call, replayWriter, out, header, binaryData); |
| out << ";\n"; |
| } |
| } |
| out << "}\n"; |
| } |
| |
| void WriteCppReplayForCallCL(const CallCapture &call, |
| ReplayWriter &replayWriter, |
| std::ostream &out, |
| std::ostream &header, |
| std::vector<uint8_t> *binaryData) |
| { |
| if (call.customFunctionName == "Comment") |
| { |
| // Just write it directly to the file and move on |
| WriteComment(out, call); |
| return; |
| } |
| |
| std::ostringstream callOut; |
| std::ostringstream postCallAdditions; |
| |
| const ParamCapture &returnValue = call.params.getReturnValue(); |
| switch (returnValue.type) |
| { |
| case ParamType::Tcl_context: |
| callOut << "clContextsMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| &returnValue.value.cl_contextVal) |
| << "] = "; |
| break; |
| case ParamType::Tcl_command_queue: |
| callOut << "clCommandQueuesMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| &returnValue.value.cl_command_queueVal) |
| << "] = "; |
| break; |
| case ParamType::Tcl_mem: |
| callOut << "clMemMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| &returnValue.value.cl_memVal) |
| << "] = "; |
| break; |
| case ParamType::Tcl_sampler: |
| callOut << "clSamplerMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| &returnValue.value.cl_samplerVal) |
| << "] = "; |
| break; |
| case ParamType::Tcl_program: |
| callOut << "clProgramsMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| &returnValue.value.cl_programVal) |
| << "] = "; |
| break; |
| case ParamType::Tcl_kernel: |
| callOut << "clKernelsMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| &returnValue.value.cl_kernelVal) |
| << "] = "; |
| break; |
| case ParamType::Tcl_event: |
| callOut << "clEventsMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| &returnValue.value.cl_eventVal) |
| << "] = "; |
| break; |
| case ParamType::TvoidPointer: |
| if (cl::Platform::GetDefault()->getFrameCaptureShared()->getCLVoidIndex( |
| returnValue.value.voidPointerVal) != SIZE_MAX) |
| { |
| callOut << "clVoidMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getCLVoidIndex( |
| returnValue.value.voidPointerVal) |
| << "] = "; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| callOut << call.name() << "("; |
| |
| bool first = true; |
| for (const ParamCapture ¶m : call.params.getParamCaptures()) |
| { |
| if (!first) |
| { |
| callOut << ", "; |
| } |
| |
| if (param.arrayClientPointerIndex != -1 && param.value.voidConstPointerVal != nullptr) |
| { |
| callOut << "gClientArrays[" << param.arrayClientPointerIndex << "]"; |
| } |
| else if (param.readBufferSizeBytes > 0) |
| { |
| callOut << "(" << ParamTypeToString(param.type) << ")gReadBuffer"; |
| } |
| else if (param.data.empty()) |
| { |
| if (param.type == ParamType::Tcl_platform_idPointer && |
| param.value.cl_platform_idPointerVal) |
| { |
| callOut << "clPlatformsMap"; |
| } |
| else if (param.type == ParamType::Tcl_platform_id) |
| { |
| callOut << "clPlatformsMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_platform_idVal) |
| << "]"; |
| } |
| else if (param.type == ParamType::Tcl_device_idPointer && |
| param.value.cl_device_idPointerVal) |
| { |
| std::vector<size_t> tempDeviceIndices = |
| cl::Platform::GetDefault()->getFrameCaptureShared()->getCLObjVector(¶m); |
| |
| cl_uint numDevices = call.params.getParamCaptures()[2].value.cl_uintVal; |
| out << "temporaryDevicesList.clear();\n temporaryDevicesList.resize(" |
| << numDevices << ");\n "; |
| callOut << "temporaryDevicesList.data()"; |
| for (cl_uint i = 0; i < numDevices; ++i) |
| { |
| postCallAdditions << ";\n clDevicesMap[" << tempDeviceIndices[i] |
| << "] = temporaryDevicesList[" << i << "]"; |
| } |
| } |
| else if (param.type == ParamType::Tcl_device_id) |
| { |
| callOut << "clDevicesMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_device_idVal) |
| << "]"; |
| } |
| else if (param.type == ParamType::Tcl_context) |
| { |
| callOut << "clContextsMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_contextVal) |
| << "]"; |
| } |
| else if (param.type == ParamType::Tcl_command_queue) |
| { |
| callOut << "clCommandQueuesMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_command_queueVal) |
| << "]"; |
| } |
| else if (param.type == ParamType::Tcl_mem) |
| { |
| callOut << "clMemMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_memVal) |
| << "]"; |
| } |
| else if (param.type == ParamType::Tcl_sampler) |
| { |
| callOut << "clSamplerMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_samplerVal) |
| << "]"; |
| } |
| else if (param.type == ParamType::Tcl_program) |
| { |
| callOut << "clProgramsMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_programVal) |
| << "]"; |
| } |
| else if (param.type == ParamType::Tcl_kernel) |
| { |
| callOut << "clKernelsMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_kernelVal) |
| << "]"; |
| } |
| else if (param.type == ParamType::Tcl_event) |
| { |
| callOut << "clEventsMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_eventVal) |
| << "]"; |
| } |
| else if (param.type == ParamType::Tcl_eventPointer) |
| { |
| if (param.value.cl_eventPointerVal) |
| { |
| callOut << "&clEventsMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_eventVal) |
| << "]"; |
| } |
| else |
| { |
| callOut << "NULL"; |
| } |
| } |
| else if (param.type == ParamType::TvoidConstPointer) |
| { |
| if (cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_memVal) != SIZE_MAX) |
| { |
| callOut << "(const void *)" << "&clMemMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_memVal) |
| << "]"; |
| } |
| else if (cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_samplerVal) != SIZE_MAX) |
| { |
| callOut << "(const void *)" << "&clSamplerMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_samplerVal) |
| << "]"; |
| } |
| else if (cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_command_queueVal) != SIZE_MAX) |
| { |
| callOut << "(const void *)" << "&clCommandQueuesMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| ¶m.value.cl_command_queueVal) |
| << "]"; |
| } |
| else if (cl::Platform::GetDefault()->getFrameCaptureShared()->getCLVoidIndex( |
| param.value.voidConstPointerVal) != SIZE_MAX) |
| { |
| callOut << "clVoidMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getCLVoidIndex( |
| param.value.voidConstPointerVal) |
| << "]"; |
| } |
| else |
| { |
| WriteParamCaptureReplay(callOut, call, param); |
| } |
| } |
| else if (param.type == ParamType::TvoidPointer) |
| { |
| if (cl::Platform::GetDefault()->getFrameCaptureShared()->getCLVoidIndex( |
| param.value.voidPointerVal) != SIZE_MAX) |
| { |
| callOut << "clVoidMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getCLVoidIndex( |
| param.value.voidPointerVal) |
| << "]"; |
| } |
| else |
| { |
| WriteParamCaptureReplay(callOut, call, param); |
| } |
| } |
| else if (param.type == ParamType::Tcl_mem_destructor_func_type || |
| param.type == ParamType::Tcl_callback_func_type || |
| param.type == ParamType::Tcl_svm_free_callback_func_type || |
| param.type == ParamType::Tcl_program_func_type || |
| param.type == ParamType::Tcl_context_destructor_func_type || |
| param.type == ParamType::Tcl_context_func_type || |
| param.type == ParamType::Tcl_void_func_type) |
| { |
| callOut << "NULL"; |
| } |
| else if (param.type == ParamType::Tcl_memConstPointer && cl::Platform::GetDefault() |
| ->getFrameCaptureShared() |
| ->getCLObjVector(¶m) |
| .size()) |
| { |
| std::vector<size_t> tempBufferIndices = |
| cl::Platform::GetDefault()->getFrameCaptureShared()->getCLObjVector(¶m); |
| out << "temporaryBuffersList = {"; |
| for (uint32_t i = 0; i < tempBufferIndices.size(); ++i) |
| { |
| out << (i != 0 ? ", " : "") << "clMemMap[" << tempBufferIndices.at(i) << "]"; |
| } |
| out << "};\n "; |
| callOut << "temporaryBuffersList.data()"; |
| } |
| else if (param.type == ParamType::Tcl_eventConstPointer) |
| { |
| std::vector<size_t> tempEventIndices = |
| cl::Platform::GetDefault()->getFrameCaptureShared()->getCLObjVector(¶m); |
| if (tempEventIndices.empty()) |
| { |
| callOut << "NULL"; |
| } |
| else |
| { |
| out << "temporaryEventsList = {"; |
| for (uint32_t i = 0; i < tempEventIndices.size(); ++i) |
| { |
| out << (i != 0 ? ", " : "") << "clEventsMap[" << tempEventIndices.at(i) |
| << "]"; |
| } |
| out << "};\n "; |
| callOut << "temporaryEventsList.data()"; |
| } |
| } |
| else if (param.type == ParamType::Tcl_device_idConstPointer) |
| { |
| std::vector<size_t> tempDeviceIndices = |
| cl::Platform::GetDefault()->getFrameCaptureShared()->getCLObjVector(¶m); |
| if (tempDeviceIndices.empty()) |
| { |
| callOut << "NULL"; |
| } |
| else |
| { |
| out << "temporaryDevicesList = {"; |
| for (uint32_t i = 0; i < tempDeviceIndices.size(); ++i) |
| { |
| if (i != 0) |
| { |
| out << ", "; |
| } |
| out << "clDevicesMap[" << tempDeviceIndices.at(i) << "]"; |
| } |
| out << "};\n "; |
| callOut << "temporaryDevicesList.data()"; |
| } |
| } |
| else if (param.type == ParamType::Tcl_kernelPointer) |
| { |
| std::vector<size_t> tempKernelIndices = |
| cl::Platform::GetDefault()->getFrameCaptureShared()->getCLObjVector(¶m); |
| cl_uint numKernels = call.params.getParamCaptures()[1].value.cl_uintVal; |
| out << "temporaryKernelsList.clear();\ntemporaryKernelsList.resize(" << numKernels |
| << ");\n "; |
| callOut << "temporaryKernelsList.data()"; |
| for (cl_uint i = 0; i < numKernels; ++i) |
| { |
| postCallAdditions << ";\n clKernelsMap[" << tempKernelIndices[i] |
| << "] = temporaryKernelsList[" << i << "]"; |
| } |
| } |
| else if (param.type == ParamType::TvoidConstPointerPointer && |
| cl::Platform::GetDefault() |
| ->getFrameCaptureShared() |
| ->getCLObjVector(¶m) |
| .size()) |
| { |
| std::vector<size_t> offsets = |
| cl::Platform::GetDefault()->getFrameCaptureShared()->getCLObjVector(¶m); |
| out << "temporaryVoidPtrList = {"; |
| for (size_t i = 0; i < offsets.size(); ++i) |
| { |
| out << (i != 0 ? ", " : "") << "&((char*)temporaryVoidPtr)[" << offsets.at(i) |
| << "]"; |
| } |
| out << "};\n "; |
| callOut << "temporaryVoidPtrList.data()"; |
| } |
| else if (param.type == ParamType::TvoidPointerPointer || |
| param.type == ParamType::TvoidConstPointerPointer) |
| { |
| std::vector<size_t> tempVoidIndices = |
| cl::Platform::GetDefault()->getFrameCaptureShared()->getCLObjVector(¶m); |
| out << "temporaryVoidPtrList = {"; |
| for (uint32_t i = 0; i < tempVoidIndices.size(); ++i) |
| { |
| out << (i != 0 ? ", " : "") << "clVoidMap[" << tempVoidIndices.at(i) << "]"; |
| } |
| out << "};\n "; |
| callOut << "temporaryVoidPtrList.data()"; |
| } |
| else if (param.type == ParamType::Tcl_programConstPointer && param.value.size_tVal) |
| { |
| std::vector<size_t> tempProgramIndices = |
| cl::Platform::GetDefault()->getFrameCaptureShared()->getCLObjVector(¶m); |
| out << "temporaryProgramsList = {"; |
| for (uint32_t i = 0; i < tempProgramIndices.size(); ++i) |
| { |
| out << (i != 0 ? ", " : "") << "clProgramsMap[" << tempProgramIndices.at(i) |
| << "]"; |
| } |
| out << "};\n "; |
| callOut << "temporaryProgramsList.data()"; |
| } |
| else if (param.type == ParamType::Tcl_context_propertiesConstPointer) |
| { |
| if (param.value.cl_context_propertiesConstPointerVal) |
| { |
| callOut << "temporaryContextProps.data()"; |
| } |
| else |
| { |
| WriteParamCaptureReplay(callOut, call, param); |
| } |
| } |
| else |
| { |
| WriteParamCaptureReplay(callOut, call, param); |
| } |
| } |
| else |
| { |
| switch (param.type) |
| { |
| case ParamType::TcharConstPointerPointer: |
| WriteStringPointerParamReplay(replayWriter, callOut, header, call, param); |
| break; |
| case ParamType::Tcl_device_idPointer: |
| callOut << "clDevicesMap"; |
| break; |
| case ParamType::TcharUnsignedConstPointerPointer: |
| { |
| std::string tempStructureName = "temporaryCharPointerList"; |
| std::string tempStructureType = "(const char *)"; |
| if (param.type == ParamType::TcharUnsignedConstPointerPointer) |
| { |
| tempStructureName = "temporaryUnsignedCharPointerList"; |
| tempStructureType = "(const unsigned char *)"; |
| } |
| const std::vector<uint8_t> *data; |
| out << tempStructureName << " = {"; |
| for (size_t i = 0; i < param.data.size(); ++i) |
| { |
| if (i != 0) |
| { |
| out << ", "; |
| } |
| data = ¶m.data[i]; |
| size_t offset = rx::roundUpPow2(binaryData->size(), kBinaryAlignment); |
| binaryData->resize(offset + data->size()); |
| memcpy(binaryData->data() + offset, data->data(), data->size()); |
| out << tempStructureType << "&gBinaryData[" << offset << "]"; |
| } |
| out << "};\n "; |
| callOut << tempStructureName << ".data()"; |
| break; |
| } |
| case ParamType::Tcl_image_descConstPointer: |
| cl_image_desc tempImageDesc; |
| std::memcpy(&tempImageDesc, param.data[0].data(), sizeof(cl_image_desc)); |
| if (tempImageDesc.mem_object) |
| { |
| out << " std::memcpy(&temporaryImageDesc, "; |
| WriteBinaryParamReplay(replayWriter, out, header, call, param, binaryData); |
| out << ", sizeof(cl_image_desc));\ntemporaryImageDesc.mem_object = " |
| "clMemMap[" |
| << cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex( |
| &tempImageDesc.mem_object) |
| << "];\n "; |
| callOut << "&temporaryImageDesc"; |
| } |
| else |
| { |
| WriteBinaryParamReplay(replayWriter, callOut, header, call, param, |
| binaryData); |
| } |
| break; |
| case ParamType::TvoidPointer: |
| { |
| // For clEnqueueNativeKernel |
| if (call.entryPoint == EntryPoint::CLEnqueueNativeKernel) |
| { |
| std::vector<size_t> bufferIndices = |
| cl::Platform::GetDefault()->getFrameCaptureShared()->getCLObjVector( |
| ¶m); |
| size_t totalSize = call.params.getParamCaptures()[3].value.size_tVal; |
| out << "temporaryVoidPtr = (void *)std::malloc(" << totalSize |
| << ");\nstd::memcpy(&temporaryVoidPtr, "; |
| WriteBinaryParamReplay(replayWriter, out, header, call, param, binaryData); |
| out << ", " << totalSize << ");\n "; |
| callOut << "temporaryVoidPtr"; |
| } |
| else |
| { |
| WriteBinaryParamReplay(replayWriter, callOut, header, call, param, |
| binaryData); |
| } |
| break; |
| } |
| default: |
| WriteBinaryParamReplay(replayWriter, callOut, header, call, param, binaryData); |
| break; |
| } |
| } |
| |
| first = false; |
| } |
| |
| callOut << ")"; |
| |
| out << callOut.str() << postCallAdditions.str(); |
| } |
| |
| void WriteInitReplayCallCL(bool compression, |
| std::ostream &out, |
| const std::string &captureLabel, |
| size_t maxClientArraySize, |
| size_t readBufferSize, |
| const std::map<ParamType, uint32_t> &maxCLParamsSize) |
| { |
| std::string binaryDataFileName = GetBinaryDataFilePath(compression, captureLabel); |
| out << " // binaryDataFileName = " << binaryDataFileName << "\n"; |
| out << " // maxClientArraySize = " << maxClientArraySize << "\n"; |
| out << " // readBufferSize = " << readBufferSize << "\n"; |
| out << " // clPlatformsMapSize = " << maxCLParamsSize.at(ParamType::Tcl_platform_idPointer) |
| << "\n"; |
| out << " // clDevicesMapSize = " << maxCLParamsSize.at(ParamType::Tcl_device_idPointer) |
| << "\n"; |
| out << " // clContextsMapSize = " << maxCLParamsSize.at(ParamType::Tcl_context) << "\n"; |
| out << " // clCommandQueuesMapSize = " << maxCLParamsSize.at(ParamType::Tcl_command_queue) |
| << "\n"; |
| out << " // clMemMapSize = " << maxCLParamsSize.at(ParamType::Tcl_mem) << "\n"; |
| out << " // clEventsMapSize = " << maxCLParamsSize.at(ParamType::Tcl_eventPointer) << "\n"; |
| out << " // clProgramsMapSize = " << maxCLParamsSize.at(ParamType::Tcl_program) << "\n"; |
| out << " // clKernelsMapSize = " << maxCLParamsSize.at(ParamType::Tcl_kernel) << "\n"; |
| out << " // clSamplerMapSize = " << maxCLParamsSize.at(ParamType::Tcl_sampler) << "\n"; |
| out << " // clVoidMapSize = " << maxCLParamsSize.at(ParamType::TvoidPointer) << "\n"; |
| out << " InitializeReplayCL(\"" << binaryDataFileName << "\", " << maxClientArraySize << ", " |
| << readBufferSize << ", " << maxCLParamsSize.at(ParamType::Tcl_platform_idPointer) << ", " |
| << maxCLParamsSize.at(ParamType::Tcl_device_idPointer) << ", " |
| << maxCLParamsSize.at(ParamType::Tcl_context) << ", " |
| << maxCLParamsSize.at(ParamType::Tcl_command_queue) << ", " |
| << maxCLParamsSize.at(ParamType::Tcl_mem) << ", " |
| << maxCLParamsSize.at(ParamType::Tcl_eventPointer) << ", " |
| << maxCLParamsSize.at(ParamType::Tcl_program) << ", " |
| << maxCLParamsSize.at(ParamType::Tcl_kernel) << ", " |
| << maxCLParamsSize.at(ParamType::Tcl_sampler) << ", " |
| << maxCLParamsSize.at(ParamType::TvoidPointer) << ");\n"; |
| } |
| |
| void FrameCaptureShared::trackCLMemUpdate(const cl_mem *mem, bool referenced) |
| { |
| std::vector<cl_mem> &mCLDirtyMem = mResourceTrackerCL.mCLDirtyMem; |
| // retained or created cl mem object |
| if (referenced) |
| { |
| // Potentially mark as dirty |
| auto it = std::find(mCLDirtyMem.begin(), mCLDirtyMem.end(), *mem); |
| if (it == mCLDirtyMem.end()) |
| { |
| mCLDirtyMem.push_back(*mem); |
| } |
| } |
| else |
| { |
| std::unordered_map<cl_mem, cl_mem> &mCLSubBufferToParent = |
| mResourceTrackerCL.mCLSubBufferToParent; |
| if ((*mem)->cast<cl::Memory>().getRefCount() == 1) |
| { |
| auto it = std::find(mCLDirtyMem.begin(), mCLDirtyMem.end(), *mem); |
| if (it != mCLDirtyMem.end()) |
| { |
| mCLDirtyMem.erase(it); |
| } |
| |
| if (removeUnneededOpenCLCalls) |
| { |
| removeCLMemOccurrences(mem, &mFrameCalls); |
| } |
| mCLSubBufferToParent.erase(*mem); |
| (*mem)->cast<cl::Memory>().release(); |
| } |
| if (mCLSubBufferToParent.find(*mem) != mCLSubBufferToParent.end()) |
| { |
| trackCLMemUpdate(&mCLSubBufferToParent[*mem], false); |
| } |
| } |
| } |
| |
| void FrameCaptureShared::trackCLProgramUpdate(const cl_program *program, |
| bool referenced, |
| cl_uint numLinkedPrograms, |
| const cl_program *linkedPrograms) |
| { |
| std::unordered_map<cl_program, cl_uint> &mCLProgramLinkCounter = |
| mResourceTrackerCL.mCLProgramLinkCounter; |
| std::unordered_map<cl_program, std::vector<cl_program>> &mCLLinkedPrograms = |
| mResourceTrackerCL.mCLLinkedPrograms; |
| // retained or created cl program object |
| if (referenced) |
| { |
| // Increment link count for this program |
| if (mCLProgramLinkCounter.find(*program) == mCLProgramLinkCounter.end()) |
| { |
| mCLProgramLinkCounter[*program] = 0; |
| } |
| ++mCLProgramLinkCounter[*program]; |
| |
| // Setup the linked programs if this call is from capturing clCompileProgram or |
| // clLinkProgram |
| if (numLinkedPrograms) |
| { |
| mCLLinkedPrograms[*program] = std::vector<cl_program>(); |
| for (cl_uint i = 0; i < numLinkedPrograms; ++i) |
| { |
| mCLLinkedPrograms[*program].push_back(linkedPrograms[i]); |
| } |
| } |
| |
| // Go through the linked programs and increment their link counts |
| for (size_t i = 0; mCLLinkedPrograms.find(*program) != mCLLinkedPrograms.end() && |
| i < mCLLinkedPrograms[*program].size(); |
| ++i) |
| { |
| trackCLProgramUpdate(&mCLLinkedPrograms[*program].at(i), true, 0, nullptr); |
| } |
| } |
| else |
| { |
| // Decrement link count for this program and the linked programs |
| --mCLProgramLinkCounter[*program]; |
| for (size_t i = 0; mCLLinkedPrograms.find(*program) != mCLLinkedPrograms.end() && |
| i < mCLLinkedPrograms[*program].size(); |
| ++i) |
| { |
| trackCLProgramUpdate(&mCLLinkedPrograms[*program].at(i), false, 0, nullptr); |
| } |
| |
| // Remove the calls containing this object if the link count is 0 |
| if (mCLProgramLinkCounter[*program] == 0) |
| { |
| mCLProgramLinkCounter.erase(*program); |
| if (mCLLinkedPrograms.find(*program) != mCLLinkedPrograms.end()) |
| { |
| mCLLinkedPrograms.erase(*program); |
| } |
| |
| if (removeUnneededOpenCLCalls) |
| { |
| removeCLProgramOccurrences(program, &mFrameCalls); |
| } |
| } |
| } |
| } |
| |
| void FrameCaptureShared::injectMemcpy(void *src, |
| void *dest, |
| size_t size, |
| std::vector<CallCapture> *calls) |
| { |
| // Inject memcpy call before unmap |
| |
| // Create param buffer |
| ParamBuffer paramBuffer; |
| |
| // Create dest parameter |
| ParamCapture destParam("dest", ParamType::TvoidConstPointer); |
| InitParamValue(ParamType::TvoidPointer, dest, &destParam.value); |
| paramBuffer.addParam(std::move(destParam)); |
| |
| // Create src param |
| ParamCapture updateMemory("src", ParamType::TvoidConstPointer); |
| CaptureMemory(src, size, &updateMemory); |
| paramBuffer.addParam(std::move(updateMemory)); |
| |
| paramBuffer.addValueParam<size_t>("size", ParamType::Tsize_t, size); |
| |
| calls->emplace(calls->end() - 1, "std::memcpy", std::move(paramBuffer)); |
| } |
| |
| void FrameCaptureShared::captureUpdateCLObjs(std::vector<CallCapture> *calls) |
| { |
| std::vector<cl_mem> &mCLDirtyMem = mResourceTrackerCL.mCLDirtyMem; |
| std::vector<void *> &mCLDirtySVM = mResourceTrackerCL.mCLDirtySVM; |
| cl_command_queue &mCLCurrentCommandQueue = mResourceTrackerCL.mCLCurrentCommandQueue; |
| for (uint32_t i = 0; i < mCLDirtyMem.size(); ++i) |
| { |
| cl_mem_object_type memType; |
| if (IsError(mCLDirtyMem.at(i)->cast<cl::Memory>().getInfo( |
| cl::MemInfo::Type, sizeof(cl_mem_object_type), &memType, nullptr))) |
| { |
| continue; |
| } |
| if (memType == CL_MEM_OBJECT_BUFFER) |
| { |
| void *ptr; |
| |
| if (calls->back().entryPoint == EntryPoint::CLEnqueueUnmapMemObject) |
| { |
| CallCapture *mapCall = &mResourceTrackerCL.mCLMapCall.at( |
| calls->back() |
| .params.getParam("mapped_ptr", ParamType::TvoidPointer, 2) |
| .value.voidPointerVal); |
| size_t offset = |
| mapCall->params.getParam("offset", ParamType::Tsize_t, 4).value.size_tVal; |
| size_t size = |
| mapCall->params.getParam("size", ParamType::Tsize_t, 5).value.size_tVal; |
| ptr = malloc(size); |
| |
| // Call clEnqueueReadBuffer to get the current data in the buffer |
| EnqueueReadBuffer(mCLCurrentCommandQueue, mCLDirtyMem.at(i), true, offset, size, |
| ptr, 0, nullptr, nullptr); |
| |
| // Inject memcpy call BEFORE unmap |
| injectMemcpy(ptr, |
| calls->back() |
| .params.getParam("mapped_ptr", ParamType::TvoidPointer, 2) |
| .value.voidPointerVal, |
| size, calls); |
| } |
| else |
| { |
| size_t bufferSize = mCLDirtyMem.at(i)->cast<cl::Buffer>().getSize(); |
| ptr = malloc(bufferSize); |
| |
| // Call clEnqueueReadBuffer to get the current data in the buffer |
| EnqueueReadBuffer(mCLCurrentCommandQueue, mCLDirtyMem.at(i), true, 0, bufferSize, |
| ptr, 0, nullptr, nullptr); |
| |
| // Pretend that a "clEnqueueWriteBuffer" was called with the above data retrieved |
| calls->push_back(CaptureEnqueueWriteBuffer(true, mCLCurrentCommandQueue, |
| mCLDirtyMem.at(i), true, 0, bufferSize, |
| ptr, 0, nullptr, nullptr, CL_SUCCESS)); |
| |
| // Implicit release, so going into the starting frame the buffer has the correct |
| // reference count |
| mCLDirtyMem.at(i)->cast<cl::Memory>().release(); |
| } |
| free(ptr); |
| } |
| else if (memType == CL_MEM_OBJECT_PIPE) |
| { |
| UNIMPLEMENTED(); |
| } |
| else |
| { |
| cl::Image *clImg = &mCLDirtyMem.at(i)->cast<cl::Image>(); |
| void *ptr; |
| |
| if (calls->back().entryPoint == EntryPoint::CLEnqueueUnmapMemObject) |
| { |
| CallCapture *mapCall = &mResourceTrackerCL.mCLMapCall.at( |
| calls->back() |
| .params.getParam("mapped_ptr", ParamType::TvoidPointer, 2) |
| .value.voidPointerVal); |
| const size_t *origin = (const size_t *)mapCall->params |
| .getParam("origin", ParamType::Tsize_tConstPointer, 4) |
| .data.back() |
| .data(); |
| const size_t *region = (const size_t *)mapCall->params |
| .getParam("region", ParamType::Tsize_tConstPointer, 5) |
| .data.back() |
| .data(); |
| |
| size_t rowPitch = mapCall->params.getParam("image_row_pitch", ParamType::Tsize_t, 6) |
| .value.size_tVal; |
| size_t slicePitch = |
| mapCall->params.getParam("image_slice_pitch", ParamType::Tsize_t, 7) |
| .value.size_tVal; |
| |
| // Get the image size to allocate the size of ptr |
| size_t totalSize = (region[2] - 1) * slicePitch + (region[1] - 1) * rowPitch + |
| region[0] * clImg->getElementSize(); |
| ptr = malloc(totalSize); |
| |
| // Call clEnqueueReadBuffer to get the current data in the image |
| EnqueueReadImage(mCLCurrentCommandQueue, mCLDirtyMem.at(i), true, origin, region, |
| rowPitch, slicePitch, ptr, 0, nullptr, nullptr); |
| |
| // Inject memcpy call BEFORE unmap |
| injectMemcpy(ptr, |
| calls->back() |
| .params.getParam("mapped_ptr", ParamType::TvoidPointer, 2) |
| .value.voidPointerVal, |
| totalSize, calls); |
| } |
| else |
| { |
| ptr = malloc(clImg->getSize()); |
| size_t origin[3] = {0, 0, 0}; |
| size_t region[3] = {clImg->getWidth(), clImg->getHeight(), clImg->getDepth()}; |
| |
| // Call clEnqueueReadBuffer to get the current data in the image |
| EnqueueReadImage(mCLCurrentCommandQueue, mCLDirtyMem.at(i), true, origin, region, |
| clImg->getRowSize(), clImg->getSliceSize(), ptr, 0, nullptr, |
| nullptr); |
| |
| // Pretend that a "clEnqueueWriteImage" was called with the above data retrieved |
| calls->push_back(CaptureEnqueueWriteImage( |
| true, mCLCurrentCommandQueue, mCLDirtyMem.at(i), true, origin, region, |
| clImg->getRowSize(), clImg->getSliceSize(), ptr, 0, nullptr, nullptr, |
| CL_SUCCESS)); |
| |
| // Implicit release, so going into the starting frame the buffer has the correct |
| // reference count |
| mCLDirtyMem.at(i)->cast<cl::Memory>().release(); |
| } |
| |
| free(ptr); |
| } |
| } |
| for (uint32_t i = 0; i < mCLDirtySVM.size(); ++i) |
| { |
| size_t SVMSize = mResourceTrackerCL.SVMToSize[mCLDirtySVM.at(i)]; |
| |
| // Call clEnqueueSVMMap to get the current data in the SVM pointer |
| cl::MemFlags flags; |
| flags.set(CL_MAP_READ); |
| EnqueueSVMMap(mCLCurrentCommandQueue, true, flags, mCLDirtySVM.at(i), SVMSize, 0, nullptr, |
| nullptr); |
| |
| // Pretend that a "clEnqueueSVMMemcpy" was called with the above data retrieved |
| calls->push_back(CaptureEnqueueSVMMemcpy(true, mCLCurrentCommandQueue, true, |
| mCLDirtySVM.at(i), mCLDirtySVM.at(i), SVMSize, 0, |
| nullptr, nullptr, CL_SUCCESS)); |
| |
| // Call clEnqueueSVMUnmap to get the current data in the SVM pointer |
| EnqueueSVMUnmap(mCLCurrentCommandQueue, mResourceTrackerCL.mCLDirtySVM.at(i), 0, nullptr, |
| nullptr); |
| } |
| mCLDirtyMem.clear(); |
| mCLDirtySVM.clear(); |
| } |
| |
| void FrameCaptureShared::removeCLMemOccurrences(const cl_mem *mem, std::vector<CallCapture> *calls) |
| { |
| // This function gets called when it captures a clReleaseMemObj prior to the starting frame |
| // that sets the reference count to 0, meaning that this cl_mem object isn't necessary for |
| // the wanted frames. So, we can remove the calls that use it. |
| |
| for (size_t i = 0; i < calls->size(); ++i) |
| { |
| CallCapture *call = &calls->at(i); |
| cl_mem foundMem; |
| switch (call->entryPoint) |
| { |
| case EntryPoint::CLCreateBuffer: |
| case EntryPoint::CLCreateBufferWithProperties: |
| case EntryPoint::CLCreateImage: |
| case EntryPoint::CLCreateImageWithProperties: |
| case EntryPoint::CLCreateImage2D: |
| case EntryPoint::CLCreateImage3D: |
| case EntryPoint::CLCreatePipe: |
| { |
| foundMem = call->params.getReturnValue().value.cl_memVal; |
| break; |
| } |
| case EntryPoint::CLCreateSubBuffer: |
| { |
| foundMem = call->params.getReturnValue().value.cl_memVal; |
| if (foundMem != *mem) |
| { |
| foundMem = |
| call->params.getParam("buffer", ParamType::Tcl_mem, 0).value.cl_memVal; |
| } |
| break; |
| } |
| case EntryPoint::CLEnqueueReadBuffer: |
| case EntryPoint::CLEnqueueWriteBuffer: |
| case EntryPoint::CLEnqueueReadBufferRect: |
| case EntryPoint::CLEnqueueWriteBufferRect: |
| case EntryPoint::CLEnqueueMapBuffer: |
| { |
| // Can get rid of these calls because the buffer is no longer needed |
| foundMem = call->params.getParam("buffer", ParamType::Tcl_mem, 1).value.cl_memVal; |
| break; |
| } |
| case EntryPoint::CLEnqueueReadImage: |
| case EntryPoint::CLEnqueueWriteImage: |
| case EntryPoint::CLEnqueueMapImage: |
| { |
| // Can get rid of these calls because the image is no longer needed |
| foundMem = call->params.getParam("image", ParamType::Tcl_mem, 1).value.cl_memVal; |
| break; |
| } |
| case EntryPoint::CLEnqueueCopyBuffer: |
| case EntryPoint::CLEnqueueCopyBufferRect: |
| case EntryPoint::CLEnqueueCopyImage: |
| case EntryPoint::CLEnqueueCopyBufferToImage: |
| case EntryPoint::CLEnqueueCopyImageToBuffer: |
| { |
| // Can get rid of these calls because the obj is no longer needed |
| std::string srcType = "src_"; |
| srcType += ((call->entryPoint == EntryPoint::CLEnqueueCopyImage || |
| call->entryPoint == EntryPoint::CLEnqueueCopyImageToBuffer) |
| ? "image" |
| : "buffer"); |
| std::string dstType = "dst_"; |
| dstType += ((call->entryPoint == EntryPoint::CLEnqueueCopyImage || |
| call->entryPoint == EntryPoint::CLEnqueueCopyBufferToImage) |
| ? "image" |
| : "buffer"); |
| foundMem = |
| call->params.getParam(srcType.c_str(), ParamType::Tcl_mem, 1).value.cl_memVal; |
| if (foundMem != *mem) |
| { |
| foundMem = call->params.getParam(dstType.c_str(), ParamType::Tcl_mem, 2) |
| .value.cl_memVal; |
| } |
| break; |
| } |
| case EntryPoint::CLReleaseMemObject: |
| case EntryPoint::CLRetainMemObject: |
| case EntryPoint::CLGetMemObjectInfo: |
| case EntryPoint::CLSetMemObjectDestructorCallback: |
| case EntryPoint::CLEnqueueUnmapMemObject: |
| { |
| foundMem = |
| call->params |
| .getParam("memobj", ParamType::Tcl_mem, |
| call->entryPoint == EntryPoint::CLEnqueueUnmapMemObject ? 1 : 0) |
| .value.cl_memVal; |
| break; |
| } |
| case EntryPoint::CLGetImageInfo: |
| { |
| foundMem = call->params.getParam("image", ParamType::Tcl_mem, 0).value.cl_memVal; |
| break; |
| } |
| case EntryPoint::CLSetKernelArg: |
| { |
| foundMem = call->params.getParam("arg_value", ParamType::TvoidConstPointer, 3) |
| .value.cl_memVal; |
| if (cl::Platform::GetDefault()->getFrameCaptureShared()->getIndex(&foundMem) == |
| SIZE_MAX) |
| { |
| continue; |
| } |
| break; |
| } |
| // Leave commented until external memory is upstream |
| // case EntryPoint::CLEnqueueAcquireExternalMemObjectsKHR: |
| // case EntryPoint::CLEnqueueReleaseExternalMemObjectsKHR: |
| case EntryPoint::CLEnqueueMigrateMemObjects: |
| { |
| const cl_mem *memObjs = |
| call->params.getParam("mem_objects", ParamType::Tcl_memConstPointer, 2) |
| .value.cl_memConstPointerVal; |
| cl_uint numMemObjs = |
| call->params.getParam("num_mem_objects", ParamType::Tcl_uint, 1) |
| .value.cl_uintVal; |
| |
| std::vector<cl_mem> newMemObjs; |
| for (cl_uint memObjIndex = 0; i < numMemObjs; ++i) |
| { |
| if (memObjs[memObjIndex] != *mem) |
| { |
| newMemObjs.push_back(memObjs[memObjIndex]); |
| } |
| } |
| |
| // If all the mem objects used in this array are released, I can remove this call |
| if (newMemObjs.empty()) |
| { |
| foundMem = *mem; |
| } |
| else |
| { |
| call->params.setValueParamAtIndex("num_mem_objects", ParamType::Tcl_uint, |
| newMemObjs.size(), 1); |
| setCLObjVectorMap( |
| newMemObjs.data(), newMemObjs.size(), |
| &call->params.getParam("mem_objects", ParamType::Tcl_memConstPointer, 2), |
| &angle::FrameCaptureShared::getIndex); |
| continue; |
| } |
| break; |
| } |
| default: |
| continue; |
| } |
| |
| if (foundMem == *mem) |
| { |
| removeCLCall(calls, i); |
| --i; |
| } |
| } |
| } |
| |
| void FrameCaptureShared::removeCLKernelOccurrences(const cl_kernel *kernel, |
| std::vector<CallCapture> *calls) |
| { |
| // This function gets called when it captures a clReleaseProgram prior to the starting frame |
| // that sets the program's reference count to 0. This ensures that the kernels in that program |
| // are/should be released as well, meaning that this cl_kernel object isn't necessary for |
| // the wanted frames. So, we can remove the calls that use it. |
| // We cannot remove cl_kernel occurrences at the time of clReleaseKernel because the kernel may |
| // be an input to clCloneKernel and clCreateKernelsInProgram. |
| |
| for (size_t i = 0; i < calls->size(); ++i) |
| { |
| CallCapture *call = &calls->at(i); |
| cl_kernel foundKernel; |
| switch (call->entryPoint) |
| { |
| case EntryPoint::CLCreateKernel: |
| { |
| foundKernel = call->params.getReturnValue().value.cl_kernelVal; |
| break; |
| } |
| case EntryPoint::CLCloneKernel: |
| { |
| foundKernel = call->params.getReturnValue().value.cl_kernelVal; |
| if (foundKernel != *kernel) |
| { |
| foundKernel = call->params.getParam("source_kernel", ParamType::Tcl_kernel, 0) |
| .value.cl_kernelVal; |
| } |
| break; |
| } |
| case EntryPoint::CLRetainKernel: |
| case EntryPoint::CLReleaseKernel: |
| case EntryPoint::CLSetKernelArg: |
| case EntryPoint::CLSetKernelArgSVMPointer: |
| case EntryPoint::CLSetKernelExecInfo: |
| case EntryPoint::CLGetKernelInfo: |
| case EntryPoint::CLGetKernelArgInfo: |
| case EntryPoint::CLGetKernelWorkGroupInfo: |
| case EntryPoint::CLGetKernelSubGroupInfo: |
| { |
| foundKernel = |
| call->params.getParam("kernel", ParamType::Tcl_kernel, 0).value.cl_kernelVal; |
| break; |
| } |
| case EntryPoint::CLEnqueueNDRangeKernel: |
| case EntryPoint::CLEnqueueTask: |
| { |
| foundKernel = |
| call->params.getParam("kernel", ParamType::Tcl_kernel, 1).value.cl_kernelVal; |
| break; |
| } |
| |
| default: |
| continue; |
| } |
| |
| if (foundKernel == *kernel) |
| { |
| removeCLCall(calls, i); |
| --i; |
| } |
| } |
| } |
| |
| void FrameCaptureShared::removeCLProgramOccurrences(const cl_program *program, |
| std::vector<CallCapture> *calls) |
| { |
| // This function gets called when it captures a clReleaseMemObj prior to the starting frame |
| // that sets the reference count to 0, and the program is not linked to any other program, |
| // meaning that this cl_mem object isn't necessary for the wanted frames. So, we can |
| // remove the calls that use it. |
| |
| for (size_t i = 0; i < calls->size(); ++i) |
| { |
| CallCapture *call = &calls->at(i); |
| cl_program foundProgram; |
| switch (call->entryPoint) |
| { |
| case EntryPoint::CLCreateProgramWithSource: |
| case EntryPoint::CLCreateProgramWithBinary: |
| case EntryPoint::CLCreateProgramWithBuiltInKernels: |
| case EntryPoint::CLCreateProgramWithIL: |
| case EntryPoint::CLLinkProgram: |
| { |
| foundProgram = call->params.getReturnValue().value.cl_programVal; |
| break; |
| } |
| case EntryPoint::CLRetainProgram: |
| case EntryPoint::CLReleaseProgram: |
| case EntryPoint::CLBuildProgram: |
| case EntryPoint::CLGetProgramInfo: |
| case EntryPoint::CLGetProgramBuildInfo: |
| case EntryPoint::CLCreateKernel: |
| case EntryPoint::CLCreateKernelsInProgram: |
| case EntryPoint::CLUnloadPlatformCompiler: |
| case EntryPoint::CLCompileProgram: |
| { |
| uint8_t programIndex = call->entryPoint == EntryPoint::CLCompileProgram ? 1 : 0; |
| foundProgram = |
| call->params.getParam("program", ParamType::Tcl_program, programIndex) |
| .value.cl_programVal; |
| break; |
| } |
| default: |
| continue; |
| } |
| |
| if (foundProgram == *program) |
| { |
| removeCLCall(calls, i); |
| --i; |
| } |
| } |
| |
| if (mResourceTrackerCL.mCLProgramToKernels.find(*program) != |
| mResourceTrackerCL.mCLProgramToKernels.end()) |
| { |
| for (size_t i = 0; i < mResourceTrackerCL.mCLProgramToKernels[*program].size(); ++i) |
| { |
| removeCLKernelOccurrences(&mResourceTrackerCL.mCLProgramToKernels[*program].at(i), |
| calls); |
| } |
| mResourceTrackerCL.mCLProgramToKernels.erase(*program); |
| } |
| } |
| |
| void FrameCaptureShared::removeCLCall(std::vector<CallCapture> *callVector, size_t &callIndex) |
| { |
| CallCapture *call = &callVector->at(callIndex); |
| const std::vector<ParamCapture> *params = &call->params.getParamCaptures(); |
| cl_context context = nullptr; |
| |
| // Checks if there is an event that is implicitly created during the deleted call. |
| // If there is, need to inject a clCreateUserEvent call and a clSetUserEventStatus call. |
| for (auto ¶m : *params) |
| { |
| if (param.type == ParamType::Tcl_context) |
| { |
| context = param.value.cl_contextVal; |
| } |
| else if (param.type == ParamType::Tcl_command_queue) |
| { |
| context = |
| param.value.cl_command_queueVal->cast<cl::CommandQueue>().getContext().getNative(); |
| } |
| else if (param.type == ParamType::Tcl_eventPointer && param.value.cl_eventVal != nullptr && |
| context) |
| { |
| // Capture the creation of a successful event if the CL call being removed created an |
| // event (ex: clEnqueueReadBuffer) |
| cl_event event = param.value.cl_eventVal; |
| callVector->insert(callVector->begin() + callIndex, |
| CaptureSetUserEventStatus(true, event, CL_COMPLETE, CL_SUCCESS)); |
| callVector->insert(callVector->begin() + callIndex, |
| CaptureCreateUserEvent(true, context, nullptr, event)); |
| callIndex += 2; |
| break; |
| } |
| } |
| callVector->erase(callVector->begin() + callIndex); |
| } |
| |
| void FrameCaptureShared::maybeCapturePreCallUpdatesCL(CallCapture &call) |
| { |
| switch (call.entryPoint) |
| { |
| case EntryPoint::CLGetExtensionFunctionAddress: |
| case EntryPoint::CLGetExtensionFunctionAddressForPlatform: |
| { |
| uint32_t index = call.entryPoint == EntryPoint::CLGetExtensionFunctionAddress ? 0 : 1; |
| std::string funcName = |
| (const char *)call.params.getParam("func_name", ParamType::TcharConstPointer, index) |
| .value.charConstPointerPointerVal; |
| call.customFunctionName = |
| funcName + " = (" + funcName + "_fn)" + GetEntryPointName(call.entryPoint); |
| |
| if (std::find(mExtFuncsAdded.begin(), mExtFuncsAdded.end(), funcName) == |
| mExtFuncsAdded.end()) |
| { |
| mExtFuncsAdded.push_back(funcName); |
| } |
| break; |
| } |
| case EntryPoint::CLCreateContext: |
| case EntryPoint::CLCreateContextFromType: |
| { |
| if (call.params.getParam("properties", ParamType::Tcl_context_propertiesConstPointer, 0) |
| .value.cl_context_propertiesConstPointerVal) |
| { |
| size_t propSize = 0; |
| size_t platformIDIndex = 0; |
| const cl_context_properties *propertiesData = |
| (cl_context_properties *)call.params |
| .getParam("properties", ParamType::Tcl_context_propertiesConstPointer, 0) |
| .data[0] |
| .data(); |
| while (propertiesData[propSize] != 0) |
| { |
| if (propertiesData[propSize] == CL_CONTEXT_PLATFORM) |
| { |
| // "Each property name is immediately followed by the corresponding desired |
| // value" |
| platformIDIndex = propSize + 1; |
| } |
| ++propSize; |
| } |
| ++propSize; |
| |
| if (platformIDIndex == 0) |
| { |
| ParamBuffer params; |
| |
| params.addValueParam("propSize", ParamType::Tsize_t, propSize); |
| |
| ParamCapture propertiesParam("propData", |
| ParamType::Tcl_context_propertiesConstPointer); |
| InitParamValue(ParamType::Tcl_context_propertiesConstPointer, propertiesData, |
| &propertiesParam.value); |
| CaptureMemory(propertiesData, propSize * sizeof(cl_context_properties), |
| &propertiesParam); |
| params.addParam(std::move(propertiesParam)); |
| mFrameCalls.emplace_back( |
| CallCapture("UpdateCLContextPropertiesNoPlatform", std::move(params))); |
| |
| call.params |
| .getParam("properties", ParamType::Tcl_context_propertiesConstPointer, 0) |
| .data.clear(); |
| break; |
| } |
| |
| // Create call to UpdateCLContextProperties |
| ParamBuffer params; |
| |
| params.addValueParam("propSize", ParamType::Tsize_t, propSize); |
| |
| ParamCapture propertiesParam("propData", |
| ParamType::Tcl_context_propertiesConstPointer); |
| InitParamValue(ParamType::Tcl_context_propertiesConstPointer, propertiesData, |
| &propertiesParam.value); |
| CaptureMemory(propertiesData, propSize * sizeof(cl_context_properties), |
| &propertiesParam); |
| params.addParam(std::move(propertiesParam)); |
| |
| params.addValueParam("platformIdxInProps", ParamType::Tsize_t, platformIDIndex); |
| params.addValueParam("platformIdxInMap", ParamType::Tsize_t, |
| getIndex((cl_platform_id *)&propertiesData[platformIDIndex])); |
| |
| call.params.getParam("properties", ParamType::Tcl_context_propertiesConstPointer, 0) |
| .data.clear(); |
| |
| mFrameCalls.emplace_back( |
| CallCapture("UpdateCLContextPropertiesWithPlatform", std::move(params))); |
| } |
| break; |
| } |
| default: |
| break; |
| } |
| |
| updateReadBufferSize(call.params.getReadBufferSize()); |
| } |
| |
| void FrameCaptureShared::addCLResetObj(const ParamCapture ¶m) |
| { |
| mResourceTrackerCL.mCLResetObjs.push_back(angle::ParamCapture("resetObj", param.type)); |
| auto paramValue = |
| &mResourceTrackerCL.mCLResetObjs.at(mResourceTrackerCL.mCLResetObjs.size() - 1).value; |
| switch (param.type) |
| { |
| case ParamType::Tcl_device_id: |
| InitParamValue(param.type, param.value.cl_device_idVal, paramValue); |
| break; |
| case ParamType::Tcl_mem: |
| InitParamValue(param.type, param.value.cl_memVal, paramValue); |
| break; |
| case ParamType::Tcl_kernel: |
| InitParamValue(param.type, param.value.cl_kernelVal, paramValue); |
| break; |
| case ParamType::Tcl_program: |
| InitParamValue(param.type, param.value.cl_programVal, paramValue); |
| break; |
| case ParamType::Tcl_command_queue: |
| InitParamValue(param.type, param.value.cl_command_queueVal, paramValue); |
| break; |
| case ParamType::Tcl_context: |
| InitParamValue(param.type, param.value.cl_contextVal, paramValue); |
| break; |
| case ParamType::Tcl_sampler: |
| InitParamValue(param.type, param.value.cl_samplerVal, paramValue); |
| break; |
| case ParamType::Tcl_event: |
| InitParamValue(param.type, param.value.cl_eventVal, paramValue); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void FrameCaptureShared::removeCLResetObj(const ParamCapture ¶m) |
| { |
| std::vector<ParamCapture> &mCLResetObjs = mResourceTrackerCL.mCLResetObjs; |
| for (size_t i = 0; i < mCLResetObjs.size(); ++i) |
| { |
| bool foundCLObj = |
| param.type == mCLResetObjs.at(i).type && |
| ((param.type == ParamType::Tcl_device_id && |
| param.value.cl_device_idVal == mCLResetObjs.at(i).value.cl_device_idVal) || |
| (param.type == ParamType::Tcl_mem && |
| param.value.cl_memVal == mCLResetObjs.at(i).value.cl_memVal) || |
| (param.type == ParamType::Tcl_kernel && |
| param.value.cl_kernelVal == mCLResetObjs.at(i).value.cl_kernelVal) || |
| (param.type == ParamType::Tcl_program && |
| param.value.cl_programVal == mCLResetObjs.at(i).value.cl_programVal) || |
| (param.type == ParamType::Tcl_command_queue && |
| param.value.cl_command_queueVal == mCLResetObjs.at(i).value.cl_command_queueVal) || |
| (param.type == ParamType::Tcl_context && |
| param.value.cl_contextVal == mCLResetObjs.at(i).value.cl_contextVal) || |
| (param.type == ParamType::Tcl_sampler && |
| param.value.cl_samplerVal == mCLResetObjs.at(i).value.cl_samplerVal) || |
| (param.type == ParamType::Tcl_event && |
| param.value.cl_eventVal == mCLResetObjs.at(i).value.cl_eventVal)); |
| |
| if (foundCLObj) |
| { |
| mCLResetObjs.erase(mCLResetObjs.begin() + i); |
| break; |
| } |
| } |
| } |
| |
| void FrameCaptureShared::printCLResetObjs(std::stringstream &stream) |
| { |
| std::vector<ParamCapture> &mCLResetObjs = mResourceTrackerCL.mCLResetObjs; |
| for (size_t i = 0; i < mCLResetObjs.size(); ++i) |
| { |
| stream << " "; |
| switch (mCLResetObjs.at(i).type) |
| { |
| case ParamType::Tcl_device_id: |
| stream << "clReleaseDevice(clDevicesMap[" |
| << std::to_string(getIndex(&mCLResetObjs.at(i).value.cl_device_idVal)) |
| << "]);"; |
| break; |
| case ParamType::Tcl_mem: |
| stream << "clReleaseMemObject(clMemMap[" |
| << std::to_string(getIndex(&mCLResetObjs.at(i).value.cl_memVal)) << "]);"; |
| break; |
| case ParamType::Tcl_kernel: |
| stream << "clReleaseKernel(clKernelsMap[" |
| << std::to_string(getIndex(&mCLResetObjs.at(i).value.cl_kernelVal)) << "]);"; |
| break; |
| case ParamType::Tcl_program: |
| stream << "clReleaseProgram(clProgramsMap[" |
| << std::to_string(getIndex(&mCLResetObjs.at(i).value.cl_programVal)) |
| << "]);"; |
| break; |
| case ParamType::Tcl_command_queue: |
| stream << "clReleaseCommandQueue(clCommandQueuesMap[" |
| << std::to_string(getIndex(&mCLResetObjs.at(i).value.cl_command_queueVal)) |
| << "]);"; |
| break; |
| case ParamType::Tcl_context: |
| stream << "clReleaseContext(clContextsMap[" |
| << std::to_string(getIndex(&mCLResetObjs.at(i).value.cl_contextVal)) |
| << "]);"; |
| break; |
| case ParamType::Tcl_sampler: |
| stream << "clReleaseSampler(clSamplersMap[" |
| << std::to_string(getIndex(&mCLResetObjs.at(i).value.cl_samplerVal)) |
| << "]);"; |
| break; |
| case ParamType::Tcl_event: |
| stream << "clReleaseEvent(clEventsMap[" |
| << std::to_string(getIndex(&mCLResetObjs.at(i).value.cl_eventVal)) << "]);"; |
| break; |
| default: |
| break; |
| } |
| stream << "\n"; |
| } |
| } |
| |
| void FrameCaptureShared::updateResourceCountsFromParamCaptureCL(const ParamCapture ¶m, |
| const CallCapture &call) |
| { |
| switch (param.type) |
| { |
| case ParamType::Tcl_platform_idPointer: |
| if (call.entryPoint == EntryPoint::CLIcdGetPlatformIDsKHR || |
| call.entryPoint == EntryPoint::CLGetPlatformIDs) |
| { |
| mMaxCLParamsSize[param.type] += |
| sizeof(cl_platform_id) * ((call.params.getParamCaptures()[0]).value.cl_uintVal); |
| } |
| break; |
| case ParamType::Tcl_device_idPointer: |
| if (call.entryPoint == EntryPoint::CLGetDeviceIDs) |
| { |
| mMaxCLParamsSize[param.type] += |
| sizeof(cl_device_id) * ((call.params.getParamCaptures()[2]).value.cl_uintVal); |
| } |
| break; |
| case ParamType::Tcl_context: |
| if (call.entryPoint == EntryPoint::CLCreateContext || |
| call.entryPoint == EntryPoint::CLCreateContextFromType) |
| { |
| if ((getIndex(¶m.value.cl_contextVal) + 1) * sizeof(cl_context) > |
| mMaxCLParamsSize[param.type]) |
| { |
| mMaxCLParamsSize[param.type] = |
| (uint32_t)((getIndex(¶m.value.cl_contextVal) + 1) * sizeof(cl_context)); |
| } |
| addCLResetObj(param); |
| } |
| break; |
| case ParamType::Tcl_command_queue: |
| if (call.entryPoint == EntryPoint::CLCreateCommandQueueWithProperties || |
| call.entryPoint == EntryPoint::CLCreateCommandQueue) |
| { |
| if ((getIndex(¶m.value.cl_command_queueVal) + 1) * sizeof(cl_command_queue) > |
| mMaxCLParamsSize[param.type]) |
| { |
| mMaxCLParamsSize[param.type] = |
| (uint32_t)((getIndex(¶m.value.cl_command_queueVal) + 1) * |
| sizeof(cl_command_queue)); |
| } |
| addCLResetObj(param); |
| } |
| break; |
| case ParamType::Tcl_mem: |
| if (call.entryPoint == EntryPoint::CLCreateBufferWithProperties || |
| call.entryPoint == EntryPoint::CLCreateBuffer || |
| call.entryPoint == EntryPoint::CLCreateSubBuffer || |
| call.entryPoint == EntryPoint::CLCreateImageWithProperties || |
| call.entryPoint == EntryPoint::CLCreateImage || |
| call.entryPoint == EntryPoint::CLCreateImage2D || |
| call.entryPoint == EntryPoint::CLCreateImage3D) |
| { |
| if ((getIndex(¶m.value.cl_memVal) + 1) * sizeof(cl_mem) > |
| mMaxCLParamsSize[param.type]) |
| { |
| mMaxCLParamsSize[param.type] = |
| (uint32_t)((getIndex(¶m.value.cl_memVal) + 1) * sizeof(cl_mem)); |
| } |
| addCLResetObj(param); |
| } |
| break; |
| case ParamType::Tcl_eventPointer: |
| { |
| if (param.value.cl_eventVal) |
| { |
| if ((getIndex(¶m.value.cl_eventVal) + 1) * sizeof(cl_event) > |
| mMaxCLParamsSize[param.type]) |
| { |
| mMaxCLParamsSize[param.type] = |
| (uint32_t)((getIndex(¶m.value.cl_eventVal) + 1) * sizeof(cl_event)); |
| } |
| angle::ParamCapture eventParam("event", angle::ParamType::Tcl_event); |
| InitParamValue(angle::ParamType::Tcl_event, param.value.cl_eventVal, |
| &eventParam.value); |
| addCLResetObj(eventParam); |
| } |
| break; |
| } |
| case ParamType::Tcl_program: |
| if (call.entryPoint == EntryPoint::CLCreateProgramWithSource || |
| call.entryPoint == EntryPoint::CLCreateProgramWithBinary || |
| call.entryPoint == EntryPoint::CLCreateProgramWithBuiltInKernels || |
| call.entryPoint == EntryPoint::CLLinkProgram || |
| call.entryPoint == EntryPoint::CLCreateProgramWithIL) |
| { |
| if ((getIndex(¶m.value.cl_programVal) + 1) * sizeof(cl_program) > |
| mMaxCLParamsSize[param.type]) |
| { |
| mMaxCLParamsSize[param.type] = |
| (uint32_t)((getIndex(¶m.value.cl_programVal) + 1) * sizeof(cl_program)); |
| } |
| addCLResetObj(param); |
| } |
| break; |
| case ParamType::Tcl_kernel: |
| if (call.entryPoint == EntryPoint::CLCreateKernel || |
| call.entryPoint == EntryPoint::CLCloneKernel) |
| { |
| if ((getIndex(¶m.value.cl_kernelVal) + 1) * sizeof(cl_kernel) > |
| mMaxCLParamsSize[param.type]) |
| { |
| mMaxCLParamsSize[param.type] = |
| (uint32_t)((getIndex(¶m.value.cl_kernelVal) + 1) * sizeof(cl_kernel)); |
| } |
| addCLResetObj(param); |
| } |
| break; |
| case ParamType::Tcl_sampler: |
| if (call.entryPoint == EntryPoint::CLCreateSampler || |
| call.entryPoint == EntryPoint::CLCreateSamplerWithProperties) |
| { |
| if ((getIndex(¶m.value.cl_samplerVal) + 1) * sizeof(cl_sampler) > |
| mMaxCLParamsSize[param.type]) |
| { |
| mMaxCLParamsSize[param.type] = |
| (uint32_t)((getIndex(¶m.value.cl_samplerVal) + 1) * sizeof(cl_sampler)); |
| } |
| addCLResetObj(param); |
| } |
| break; |
| case ParamType::TvoidPointer: |
| if (call.entryPoint == EntryPoint::CLEnqueueMapImage || |
| call.entryPoint == EntryPoint::CLEnqueueMapBuffer) |
| { |
| mMaxCLParamsSize[param.type] += sizeof(void *); |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void FrameCaptureShared::updateResourceCountsFromCallCaptureCL(const CallCapture &call) |
| { |
| for (const ParamCapture ¶m : call.params.getParamCaptures()) |
| { |
| updateResourceCountsFromParamCaptureCL(param, call); |
| } |
| |
| // Update resource IDs in the return value. |
| switch (call.entryPoint) |
| { |
| case EntryPoint::CLCreateContext: |
| case EntryPoint::CLCreateContextFromType: |
| setIndex(&call.params.getReturnValue().value.cl_contextVal); |
| updateResourceCountsFromParamCaptureCL(call.params.getReturnValue(), call); |
| break; |
| case EntryPoint::CLCreateBuffer: |
| case EntryPoint::CLCreateBufferWithProperties: |
| case EntryPoint::CLCreateSubBuffer: |
| case EntryPoint::CLCreateImageWithProperties: |
| case EntryPoint::CLCreateImage: |
| case EntryPoint::CLCreateImage2D: |
| case EntryPoint::CLCreateImage3D: |
| case EntryPoint::CLCreatePipe: |
| setIndex(&call.params.getReturnValue().value.cl_memVal); |
| updateResourceCountsFromParamCaptureCL(call.params.getReturnValue(), call); |
| break; |
| case EntryPoint::CLCreateSampler: |
| case EntryPoint::CLCreateSamplerWithProperties: |
| setIndex(&call.params.getReturnValue().value.cl_samplerVal); |
| updateResourceCountsFromParamCaptureCL(call.params.getReturnValue(), call); |
| break; |
| case EntryPoint::CLCreateCommandQueue: |
| case EntryPoint::CLCreateCommandQueueWithProperties: |
| setIndex(&call.params.getReturnValue().value.cl_command_queueVal); |
| updateResourceCountsFromParamCaptureCL(call.params.getReturnValue(), call); |
| break; |
| case EntryPoint::CLCreateProgramWithSource: |
| case EntryPoint::CLCreateProgramWithBinary: |
| case EntryPoint::CLCreateProgramWithBuiltInKernels: |
| case EntryPoint::CLLinkProgram: |
| case EntryPoint::CLCreateProgramWithIL: |
| setIndex(&call.params.getReturnValue().value.cl_programVal); |
| updateResourceCountsFromParamCaptureCL(call.params.getReturnValue(), call); |
| break; |
| case EntryPoint::CLCreateKernel: |
| case EntryPoint::CLCloneKernel: |
| setIndex(&call.params.getReturnValue().value.cl_kernelVal); |
| updateResourceCountsFromParamCaptureCL(call.params.getReturnValue(), call); |
| break; |
| case EntryPoint::CLEnqueueMapBuffer: |
| case EntryPoint::CLEnqueueMapImage: |
| case EntryPoint::CLSVMAlloc: |
| if (call.params.getReturnValue().value.voidPointerVal) |
| { |
| setCLVoidIndex(call.params.getReturnValue().value.voidPointerVal); |
| updateResourceCountsFromParamCaptureCL(call.params.getReturnValue(), call); |
| } |
| break; |
| case EntryPoint::CLCreateUserEvent: |
| setIndex(&call.params.getReturnValue().value.cl_eventVal); |
| break; |
| case EntryPoint::CLReleaseDevice: |
| case EntryPoint::CLReleaseCommandQueue: |
| case EntryPoint::CLReleaseContext: |
| case EntryPoint::CLReleaseEvent: |
| case EntryPoint::CLReleaseKernel: |
| case EntryPoint::CLReleaseMemObject: |
| case EntryPoint::CLReleaseProgram: |
| case EntryPoint::CLReleaseSampler: |
| removeCLResetObj(call.params.getParamCaptures()[0]); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void FrameCaptureShared::captureCLCall(CallCapture &&inCall, bool isCallValid) |
| { |
| if (!mCallCaptured) |
| { |
| mReplayWriter.captureAPI = CaptureAPI::CL; |
| mBinaryData.clear(); |
| mCallCaptured = true; |
| std::atexit(onCLProgramEnd); |
| } |
| |
| if (mFrameIndex <= mCaptureEndFrame) |
| { |
| |
| // Keep track of return values from OpenCL calls |
| updateResourceCountsFromCallCaptureCL(inCall); |
| |
| // Set to true if the call signifies the end of a frame |
| // ex: clEnqueueNDRangeKernel |
| bool frameEnd = false; |
| |
| // Covers pre call updates, like updating the read buffer size |
| maybeCapturePreCallUpdatesCL(inCall); |
| |
| // If it's an unnecessary call for replay (ex: clGetDeviceInfo) |
| if (mCLOptionalCalls.find(inCall.entryPoint) == mCLOptionalCalls.end()) |
| { |
| if (mCLEndFrameCalls.find(inCall.entryPoint) != mCLEndFrameCalls.end()) |
| { |
| frameEnd = true; |
| } |
| |
| mFrameCalls.emplace_back(std::move(inCall)); |
| } |
| else |
| { |
| saveCLGetInfo(inCall); |
| return; |
| } |
| |
| // For kernel argument memory snapshots |
| maybeCapturePostCallUpdatesCL(); |
| if (mFrameIndex >= mCaptureStartFrame || |
| (mFrameIndex + 1 == mCaptureStartFrame && frameEnd)) |
| { |
| // Maybe add clEnqueueWrite* or memcpy for memory snapshots |
| captureUpdateCLObjs(&mFrameCalls); |
| } |
| |
| if (frameEnd && mFrameIndex >= mCaptureStartFrame) |
| { |
| mActiveFrameIndices.push_back(mFrameIndex); |
| writeMainContextCppReplayCL(); |
| if (mFrameIndex == mCaptureEndFrame) |
| { |
| writeCppReplayIndexFilesCL(); |
| SaveBinaryData(mCompression, mOutDirectory, kNoContextId, mCaptureLabel, |
| mBinaryData); |
| } |
| reset(); |
| } |
| |
| if (frameEnd) |
| { |
| if (mFrameIndex == (mCaptureStartFrame == 0 ? 0 : mCaptureStartFrame - 1)) |
| { |
| mCLSetupCalls = std::move(mFrameCalls); |
| } |
| ++mFrameIndex; |
| } |
| } |
| } |
| |
| void FrameCaptureShared::maybeCapturePostCallUpdatesCL() |
| { |
| CallCapture &lastCall = mFrameCalls.back(); |
| switch (lastCall.entryPoint) |
| { |
| case EntryPoint::CLEnqueueMapBuffer: |
| { |
| // Recreate the map call to store in the mCLMapCall unordered_map |
| // so later upon the unmap call, the original map data will be available |
| cl_command_queue command_queue = |
| lastCall.params.getParam("command_queue", ParamType::Tcl_command_queue, 0) |
| .value.cl_command_queueVal; |
| cl_mem buffer = |
| lastCall.params.getParam("buffer", ParamType::Tcl_mem, 1).value.cl_memVal; |
| cl_bool blocking_map = |
| lastCall.params.getParam("blocking_map", ParamType::Tcl_bool, 2).value.cl_boolVal; |
| cl::MapFlags map_flags = |
| lastCall.params.getParam("map_flagsPacked", ParamType::TMapFlags, 3) |
| .value.MapFlagsVal; |
| size_t offset = |
| lastCall.params.getParam("offset", ParamType::Tsize_t, 4).value.size_tVal; |
| size_t size = lastCall.params.getParam("size", ParamType::Tsize_t, 5).value.size_tVal; |
| |
| mResourceTrackerCL.mCLMapCall.emplace( |
| lastCall.params.getReturnValue().value.voidPointerVal, |
| CaptureEnqueueMapBuffer(true, command_queue, buffer, blocking_map, map_flags, |
| offset, size, 0, nullptr, nullptr, nullptr, nullptr)); |
| break; |
| } |
| case EntryPoint::CLEnqueueMapImage: |
| { |
| // Recreate the map call to store in the mCLMapCall unordered_map |
| // so later upon the unmap call, the original map data will be available |
| cl_command_queue command_queue = |
| lastCall.params.getParam("command_queue", ParamType::Tcl_command_queue, 0) |
| .value.cl_command_queueVal; |
| cl_mem image = lastCall.params.getParam("image", ParamType::Tcl_mem, 1).value.cl_memVal; |
| cl_bool blocking_map = |
| lastCall.params.getParam("blocking_map", ParamType::Tcl_bool, 2).value.cl_boolVal; |
| cl::MapFlags map_flags = |
| lastCall.params.getParam("map_flagsPacked", ParamType::TMapFlags, 3) |
| .value.MapFlagsVal; |
| const size_t *origin = |
| lastCall.params.getParam("origin", ParamType::Tsize_tConstPointer, 4) |
| .value.size_tConstPointerVal; |
| const size_t *region = |
| lastCall.params.getParam("region", ParamType::Tsize_tConstPointer, 5) |
| .value.size_tConstPointerVal; |
| size_t *image_row_pitch = |
| lastCall.params.getParam("image_row_pitch", ParamType::Tsize_tPointer, 6) |
| .value.size_tPointerVal; |
| size_t *image_slice_pitch = |
| lastCall.params.getParam("image_slice_pitch", ParamType::Tsize_tPointer, 7) |
| .value.size_tPointerVal; |
| |
| mResourceTrackerCL.mCLMapCall.emplace( |
| lastCall.params.getReturnValue().value.voidPointerVal, |
| CaptureEnqueueMapImage(true, command_queue, image, blocking_map, map_flags, origin, |
| region, image_row_pitch, image_slice_pitch, 0, nullptr, |
| nullptr, nullptr, nullptr)); |
| mResourceTrackerCL.mCLMapCall.at(lastCall.params.getReturnValue().value.voidPointerVal) |
| .params.setValueParamAtIndex("image_row_pitch", ParamType::Tsize_t, |
| *image_row_pitch, 6); |
| mResourceTrackerCL.mCLMapCall.at(lastCall.params.getReturnValue().value.voidPointerVal) |
| .params.setValueParamAtIndex("image_slice_pitch", ParamType::Tsize_t, |
| image_slice_pitch == nullptr ? 0 : *image_slice_pitch, |
| 7); |
| break; |
| } |
| case EntryPoint::CLEnqueueUnmapMemObject: |
| { |
| if (mFrameIndex >= mCaptureStartFrame) |
| { |
| // Mark as dirty |
| cl_mem *mem = |
| &lastCall.params.getParam("memobj", ParamType::Tcl_mem, 1).value.cl_memVal; |
| mResourceTrackerCL.mCLCurrentCommandQueue = |
| lastCall.params.getParam("command_queue", ParamType::Tcl_command_queue, 0) |
| .value.cl_command_queueVal; |
| CallCapture *mapCall = &mResourceTrackerCL.mCLMapCall.at( |
| lastCall.params.getParam("mapped_ptr", ParamType::TvoidPointer, 2) |
| .value.voidPointerVal); |
| auto it = std::find(mResourceTrackerCL.mCLDirtyMem.begin(), |
| mResourceTrackerCL.mCLDirtyMem.end(), *mem); |
| if (it == mResourceTrackerCL.mCLDirtyMem.end() && |
| mapCall->params.getParam("map_flagsPacked", ParamType::TMapFlags, 3) |
| .value.MapFlagsVal.mask(CL_MAP_WRITE | |
| CL_MAP_WRITE_INVALIDATE_REGION) != 0u) |
| { |
| mResourceTrackerCL.mCLDirtyMem.push_back(*mem); |
| } |
| } |
| break; |
| } |
| case EntryPoint::CLEnqueueSVMUnmap: |
| { |
| // Mark as dirty |
| void *svm = &lastCall.params.getParam("svm_ptr", ParamType::TvoidPointer, 1) |
| .value.voidPointerVal; |
| mResourceTrackerCL.mCLCurrentCommandQueue = |
| lastCall.params.getParam("command_queue", ParamType::Tcl_command_queue, 0) |
| .value.cl_command_queueVal; |
| mResourceTrackerCL.mCLDirtySVM.push_back(svm); |
| break; |
| } |
| default: |
| break; |
| } |
| |
| // OpenCL calls that come before the starting frame |
| if (mFrameIndex < mCaptureStartFrame) |
| { |
| std::unordered_map<cl_program, std::vector<cl_kernel>> &mCLProgramToKernels = |
| mResourceTrackerCL.mCLProgramToKernels; |
| switch (lastCall.entryPoint) |
| { |
| // There should be no unnecessary enqueue functions prior to the starting frame. |
| // captureUpdateCLObjs accounts for it by dynamically adding |
| // CLEnqueueWriteBuffer/CLEnqueueWriteImage to ensure the cl_mem objects |
| // have the needed info upon replay |
| case EntryPoint::CLEnqueueNDRangeKernel: |
| case EntryPoint::CLEnqueueNativeKernel: |
| case EntryPoint::CLEnqueueTask: |
| case EntryPoint::CLEnqueueReadBuffer: |
| case EntryPoint::CLEnqueueWriteBuffer: |
| case EntryPoint::CLEnqueueReadBufferRect: |
| case EntryPoint::CLEnqueueWriteBufferRect: |
| case EntryPoint::CLEnqueueReadImage: |
| case EntryPoint::CLEnqueueWriteImage: |
| case EntryPoint::CLEnqueueCopyBuffer: |
| case EntryPoint::CLEnqueueCopyBufferRect: |
| case EntryPoint::CLEnqueueCopyImage: |
| case EntryPoint::CLEnqueueCopyBufferToImage: |
| case EntryPoint::CLEnqueueCopyImageToBuffer: |
| case EntryPoint::CLEnqueueFillBuffer: |
| case EntryPoint::CLEnqueueFillImage: |
| case EntryPoint::CLEnqueueWaitForEvents: |
| case EntryPoint::CLEnqueueMarkerWithWaitList: |
| case EntryPoint::CLEnqueueBarrierWithWaitList: |
| case EntryPoint::CLEnqueueBarrier: |
| case EntryPoint::CLEnqueueMarker: |
| case EntryPoint::CLEnqueueMigrateMemObjects: |
| case EntryPoint::CLEnqueueSVMMemcpy: |
| case EntryPoint::CLEnqueueSVMMemFill: |
| case EntryPoint::CLEnqueueSVMMigrateMem: |
| { |
| size_t index = mFrameCalls.size() - 1; |
| removeCLCall(&mFrameCalls, index); |
| break; |
| } |
| case EntryPoint::CLCreateBuffer: |
| case EntryPoint::CLCreateBufferWithProperties: |
| case EntryPoint::CLCreateImage: |
| case EntryPoint::CLCreateImageWithProperties: |
| case EntryPoint::CLCreateImage2D: |
| case EntryPoint::CLCreateImage3D: |
| case EntryPoint::CLCreatePipe: |
| case EntryPoint::CLCreateSubBuffer: |
| { |
| const cl_mem *newBuff = &lastCall.params.getReturnValue().value.cl_memVal; |
| |
| // Set the parent |
| if (lastCall.entryPoint == EntryPoint::CLCreateSubBuffer) |
| { |
| cl_mem parent = |
| lastCall.params.getParam("buffer", ParamType::Tcl_mem, 0).value.cl_memVal; |
| mResourceTrackerCL.mCLSubBufferToParent[*newBuff] = parent; |
| } |
| |
| // Implicit retain |
| (*newBuff)->cast<cl::Memory>().retain(); |
| |
| // Add buffer as tracked |
| trackCLMemUpdate(newBuff, true); |
| break; |
| } |
| case EntryPoint::CLReleaseMemObject: |
| { |
| // Potentially remove buffer/image (and potentially parents) as tracked |
| trackCLMemUpdate( |
| &lastCall.params.getParam("memobj", ParamType::Tcl_mem, 0).value.cl_memVal, |
| false); |
| break; |
| } |
| case EntryPoint::CLCreateCommandQueue: |
| case EntryPoint::CLCreateCommandQueueWithProperties: |
| { |
| mResourceTrackerCL.mCLCurrentCommandQueue = |
| lastCall.params.getReturnValue().value.cl_command_queueVal; |
| break; |
| } |
| case EntryPoint::CLCreateProgramWithSource: |
| case EntryPoint::CLCreateProgramWithBinary: |
| case EntryPoint::CLCreateProgramWithBuiltInKernels: |
| case EntryPoint::CLCreateProgramWithIL: |
| { |
| mCLProgramToKernels[lastCall.params.getReturnValue().value.cl_programVal] = |
| std::vector<cl_kernel>(); |
| trackCLProgramUpdate(&lastCall.params.getReturnValue().value.cl_programVal, true, 0, |
| nullptr); |
| break; |
| } |
| case EntryPoint::CLRetainProgram: |
| { |
| trackCLProgramUpdate(&lastCall.params.getParam("program", ParamType::Tcl_program, 0) |
| .value.cl_programVal, |
| true, 0, nullptr); |
| break; |
| } |
| case EntryPoint::CLCompileProgram: |
| { |
| const cl_program *program = |
| &lastCall.params.getParam("program", ParamType::Tcl_program, 0) |
| .value.cl_programVal; |
| trackCLProgramUpdate( |
| program, true, |
| lastCall.params.getParam("num_input_headers", ParamType::Tcl_uint, 4) |
| .value.cl_uintVal, |
| lastCall.params.getParam("input_headers", ParamType::Tcl_programConstPointer, 5) |
| .value.cl_programConstPointerVal); |
| break; |
| } |
| case EntryPoint::CLLinkProgram: |
| { |
| const cl_program *program = &lastCall.params.getReturnValue().value.cl_programVal; |
| mCLProgramToKernels[*program] = std::vector<cl_kernel>(); |
| trackCLProgramUpdate( |
| program, true, |
| lastCall.params.getParam("num_input_programs", ParamType::Tcl_uint, 4) |
| .value.cl_uintVal, |
| lastCall.params |
| .getParam("input_programs", ParamType::Tcl_programConstPointer, 5) |
| .value.cl_programConstPointerVal); |
| break; |
| } |
| case EntryPoint::CLReleaseProgram: |
| { |
| trackCLProgramUpdate(&lastCall.params.getParam("program", ParamType::Tcl_program, 0) |
| .value.cl_programVal, |
| false, 0, nullptr); |
| break; |
| } |
| case EntryPoint::CLCreateKernel: |
| { |
| cl_program *program = |
| &lastCall.params.getParam("program", ParamType::Tcl_program, 0) |
| .value.cl_programVal; |
| const cl_kernel *kernel = &lastCall.params.getReturnValue().value.cl_kernelVal; |
| mCLProgramToKernels[*program].push_back(*kernel); |
| mResourceTrackerCL.mCLKernelToProgram[*kernel] = *program; |
| break; |
| } |
| case EntryPoint::CLCloneKernel: |
| { |
| cl_program *program = |
| &mResourceTrackerCL.mCLKernelToProgram[lastCall.params |
| .getParam("source_kernel", |
| ParamType::Tcl_kernel, 0) |
| .value.cl_kernelVal]; |
| const cl_kernel *kernel = &lastCall.params.getReturnValue().value.cl_kernelVal; |
| mCLProgramToKernels[*program].push_back(*kernel); |
| mResourceTrackerCL.mCLKernelToProgram[*kernel] = *program; |
| break; |
| } |
| case EntryPoint::CLSVMAlloc: |
| { |
| void *svm = lastCall.params.getReturnValue().value.voidPointerVal; |
| |
| // Potentially mark as dirty |
| auto it = std::find(mResourceTrackerCL.mCLDirtySVM.begin(), |
| mResourceTrackerCL.mCLDirtySVM.end(), svm); |
| if (it == mResourceTrackerCL.mCLDirtySVM.end()) |
| { |
| mResourceTrackerCL.mCLDirtySVM.push_back(svm); |
| } |
| break; |
| } |
| case EntryPoint::CLSVMFree: |
| { |
| void *svm = lastCall.params.getParam("svm_pointer", ParamType::TvoidPointer, 1) |
| .value.voidPointerVal; |
| auto it = std::find(mResourceTrackerCL.mCLDirtySVM.begin(), |
| mResourceTrackerCL.mCLDirtySVM.end(), svm); |
| if (it != mResourceTrackerCL.mCLDirtySVM.end()) |
| { |
| mResourceTrackerCL.mCLDirtySVM.erase(it); |
| } |
| break; |
| } |
| case EntryPoint::CLEnqueueSVMFree: |
| { |
| for (cl_uint svmIndex = 0; |
| svmIndex < lastCall.params.getParam("num_svm_pointers", ParamType::Tcl_uint, 1) |
| .value.cl_uintVal; |
| ++svmIndex) |
| { |
| void *svm = |
| lastCall.params.getParam("svm_pointers", ParamType::TvoidPointerPointer, 1) |
| .value.voidPointerPointerVal[svmIndex]; |
| auto it = std::find(mResourceTrackerCL.mCLDirtySVM.begin(), |
| mResourceTrackerCL.mCLDirtySVM.end(), svm); |
| if (it != mResourceTrackerCL.mCLDirtySVM.end()) |
| { |
| mResourceTrackerCL.mCLDirtySVM.erase(it); |
| } |
| } |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| } |
| |
| void FrameCaptureShared::onCLProgramEnd() |
| { |
| if (cl::Platform::GetDefault()->getFrameCaptureShared()->onEndCLCapture()) |
| { |
| delete cl::Platform::GetDefault()->getFrameCaptureShared(); |
| } |
| } |
| |
| bool FrameCaptureShared::onEndCLCapture() |
| { |
| if (mFrameIndex >= mCaptureStartFrame && mFrameIndex <= mCaptureEndFrame) |
| { |
| mActiveFrameIndices.push_back(mFrameIndex); |
| mCaptureEndFrame = mFrameIndex; |
| writeMainContextCppReplayCL(); |
| writeCppReplayIndexFilesCL(); |
| SaveBinaryData(mCompression, mOutDirectory, kNoContextId, mCaptureLabel, mBinaryData); |
| return true; |
| } |
| return false; |
| } |
| |
| ResourceTrackerCL::ResourceTrackerCL() = default; |
| |
| ResourceTrackerCL::~ResourceTrackerCL() = default; |
| |
| void FrameCaptureShared::setCLPlatformIndices(cl_platform_id *platforms, size_t numPlatforms) |
| { |
| for (uint32_t i = 0; i < numPlatforms; ++i) |
| { |
| setIndex(&platforms[i]); |
| } |
| } |
| |
| void FrameCaptureShared::setCLDeviceIndices(cl_device_id *devices, size_t numDevices) |
| { |
| for (uint32_t i = 0; i < numDevices; ++i) |
| { |
| setIndex(&devices[i]); |
| } |
| } |
| |
| size_t FrameCaptureShared::getCLVoidIndex(const void *v) |
| { |
| if (mResourceTrackerCL.mCLVoidIndices.find(v) == mResourceTrackerCL.mCLVoidIndices.end()) |
| { |
| return SIZE_MAX; |
| } |
| return mResourceTrackerCL.mCLVoidIndices[v]; |
| } |
| |
| void FrameCaptureShared::setCLVoidIndex(const void *v) |
| { |
| if (mResourceTrackerCL.mCLVoidIndices.find(v) == mResourceTrackerCL.mCLVoidIndices.end()) |
| { |
| size_t tempSize = mResourceTrackerCL.mCLVoidIndices.size(); |
| mResourceTrackerCL.mCLVoidIndices[v] = tempSize; |
| } |
| } |
| |
| void FrameCaptureShared::setCLVoidVectorIndex(const void *pointers[], |
| size_t numPointers, |
| const angle::ParamCapture *paramCaptureKey) |
| { |
| mResourceTrackerCL.mCLParamIDToIndexVector[paramCaptureKey->uniqueID] = std::vector<size_t>(); |
| for (size_t i = 0; i < numPointers; ++i) |
| { |
| mResourceTrackerCL.mCLParamIDToIndexVector[paramCaptureKey->uniqueID].push_back( |
| getCLVoidIndex(pointers[i])); |
| } |
| } |
| |
| void FrameCaptureShared::setOffsetsVector(const void *args, |
| const void **argsLocations, |
| size_t numLocations, |
| const angle::ParamCapture *paramCaptureKey) |
| { |
| mResourceTrackerCL.mCLParamIDToIndexVector[paramCaptureKey->uniqueID] = std::vector<size_t>(); |
| for (size_t i = 0; i < numLocations; ++i) |
| { |
| mResourceTrackerCL.mCLParamIDToIndexVector[paramCaptureKey->uniqueID].push_back( |
| (char *)argsLocations[i] - (char *)args); |
| } |
| } |
| |
| std::vector<size_t> FrameCaptureShared::getCLObjVector(const angle::ParamCapture *paramCaptureKey) |
| { |
| if (mResourceTrackerCL.mCLParamIDToIndexVector.find(paramCaptureKey->uniqueID) != |
| mResourceTrackerCL.mCLParamIDToIndexVector.end()) |
| { |
| return mResourceTrackerCL.mCLParamIDToIndexVector[paramCaptureKey->uniqueID]; |
| } |
| return std::vector<size_t>(); |
| } |
| |
| template <typename T> |
| std::unordered_map<T, size_t> &FrameCaptureShared::getMap() |
| { |
| ASSERT(false); |
| return std::unordered_map<T, size_t>(); |
| } |
| template <> |
| std::unordered_map<cl_platform_id, size_t> &FrameCaptureShared::getMap<cl_platform_id>() |
| { |
| return mResourceTrackerCL.mCLPlatformIDIndices; |
| } |
| template <> |
| std::unordered_map<cl_device_id, size_t> &FrameCaptureShared::getMap<cl_device_id>() |
| { |
| return mResourceTrackerCL.mCLDeviceIDIndices; |
| } |
| template <> |
| std::unordered_map<cl_context, size_t> &FrameCaptureShared::getMap<cl_context>() |
| { |
| return mResourceTrackerCL.mCLContextIndices; |
| } |
| template <> |
| std::unordered_map<cl_event, size_t> &FrameCaptureShared::getMap<cl_event>() |
| { |
| return mResourceTrackerCL.mCLEventsIndices; |
| } |
| template <> |
| std::unordered_map<cl_command_queue, size_t> &FrameCaptureShared::getMap<cl_command_queue>() |
| { |
| return mResourceTrackerCL.mCLCommandQueueIndices; |
| } |
| template <> |
| std::unordered_map<cl_mem, size_t> &FrameCaptureShared::getMap<cl_mem>() |
| { |
| return mResourceTrackerCL.mCLMemIndices; |
| } |
| template <> |
| std::unordered_map<cl_sampler, size_t> &FrameCaptureShared::getMap<cl_sampler>() |
| { |
| return mResourceTrackerCL.mCLSamplerIndices; |
| } |
| template <> |
| std::unordered_map<cl_program, size_t> &FrameCaptureShared::getMap<cl_program>() |
| { |
| return mResourceTrackerCL.mCLProgramIndices; |
| } |
| template <> |
| std::unordered_map<cl_kernel, size_t> &FrameCaptureShared::getMap<cl_kernel>() |
| { |
| return mResourceTrackerCL.mCLKernelIndices; |
| } |
| |
| void FrameCaptureShared::writeJSONCL() |
| { |
| |
| JsonSerializer json; |
| json.startGroup("TraceMetadata"); |
| json.addBool("IsBinaryDataCompressed", mCompression); |
| json.addScalar("CaptureRevision", GetANGLERevision()); |
| json.addScalar("FrameStart", mCaptureStartFrame); |
| json.addScalar("FrameEnd", mFrameIndex); |
| json.addBool("IsOpenCL", true); |
| json.endGroup(); |
| |
| { |
| const std::vector<std::string> &traceFiles = mReplayWriter.getAndResetWrittenFiles(); |
| json.addVectorOfStrings("TraceFiles", traceFiles); |
| } |
| |
| { |
| std::stringstream jsonFileNameStream; |
| jsonFileNameStream << mOutDirectory << FmtCapturePrefix(kNoContextId, mCaptureLabel) |
| << ".json"; |
| std::string jsonFileName = jsonFileNameStream.str(); |
| |
| SaveFileHelper saveData(jsonFileName); |
| saveData.write(reinterpret_cast<const uint8_t *>(json.data()), json.length()); |
| } |
| } |
| |
| void FrameCaptureShared::saveCLGetInfo(const CallCapture &call) |
| { |
| std::string prevCall = ""; |
| size_t size; |
| std::ostringstream objectStream; |
| std::string clObject; |
| JsonSerializer json; |
| |
| json.startGroup(call.name()); |
| |
| // Below ONLY for clGetSupportedImageFormats |
| if (call.entryPoint == EntryPoint::CLGetSupportedImageFormats) |
| { |
| const cl_image_format *data = |
| call.params.getParam("image_formats", ParamType::Tcl_image_formatPointer, 4) |
| .value.cl_image_formatPointerVal; |
| if (!data) |
| { |
| return; |
| } |
| size_t *sizePointer = |
| call.params.getParam("num_image_formats", ParamType::Tcl_uintPointer, 5) |
| .value.size_tPointerVal; |
| if (!sizePointer) |
| { |
| size = |
| call.params.getParam("param_value_size", ParamType::Tcl_uint, 3).value.cl_uintVal; |
| } |
| else |
| { |
| size = *sizePointer; |
| } |
| |
| cl_context context = call.params.getParamCaptures()[0].value.cl_contextVal; |
| objectStream << static_cast<void *>(context); |
| clObject = objectStream.str(); |
| json.addString("context", clObject); |
| json.addScalar("flags", call.params.getParamCaptures()[1].value.MemFlagsVal.get()); |
| |
| cl::MemObjectType imageType = |
| call.params.getParam("image_typePacked", ParamType::TMemObjectType, 2) |
| .value.MemObjectTypeVal; |
| std::ostringstream oss; |
| oss << imageType; |
| std::string infoString = oss.str(); |
| json.startGroup(infoString); |
| for (size_t j = 0; j < size; ++j) |
| { |
| std::ostringstream temp; |
| temp << (j + 1); |
| json.addScalar("image_channel_order" + temp.str(), data[j].image_channel_order); |
| json.addScalar("image_channel_data_type" + temp.str(), data[j].image_channel_data_type); |
| } |
| |
| json.endGroup(); |
| json.endGroup(); |
| return; |
| } |
| |
| // Get the param_value and size |
| bool offsetData = 0; |
| switch (call.entryPoint) |
| { |
| case EntryPoint::CLGetProgramBuildInfo: |
| case EntryPoint::CLGetKernelArgInfo: |
| case EntryPoint::CLGetKernelWorkGroupInfo: |
| { |
| offsetData = 1; |
| break; |
| } |
| default: |
| break; |
| } |
| |
| const void *data = call.params.getParam("param_value", ParamType::TvoidPointer, 3 + offsetData) |
| .value.voidPointerVal; |
| if (!data) |
| { |
| return; |
| } |
| size_t *sizePointer = |
| call.params.getParam("param_value_size_ret", ParamType::Tsize_tPointer, 4 + offsetData) |
| .value.size_tPointerVal; |
| if (!sizePointer) |
| { |
| size = call.params.getParam("param_value_size", ParamType::Tsize_t, 2 + offsetData) |
| .value.size_tVal; |
| } |
| else |
| { |
| size = *sizePointer; |
| } |
| |
| // Get string representation of OpenCL object specified |
| switch (call.entryPoint) |
| { |
| case EntryPoint::CLGetPlatformInfo: |
| { |
| cl_platform_id platform = call.params.getParamCaptures()[0].value.cl_platform_idVal; |
| objectStream << static_cast<void *>(platform); |
| break; |
| } |
| case EntryPoint::CLGetDeviceInfo: |
| { |
| cl_device_id device = call.params.getParamCaptures()[0].value.cl_device_idVal; |
| objectStream << static_cast<void *>(device); |
| break; |
| } |
| case EntryPoint::CLGetContextInfo: |
| { |
| cl_context context = call.params.getParamCaptures()[0].value.cl_contextVal; |
| objectStream << static_cast<void *>(context); |
| break; |
| } |
| case EntryPoint::CLGetCommandQueueInfo: |
| { |
| cl_command_queue commandQueue = |
| call.params.getParamCaptures()[0].value.cl_command_queueVal; |
| objectStream << static_cast<void *>(commandQueue); |
| break; |
| } |
| case EntryPoint::CLGetProgramInfo: |
| case EntryPoint::CLGetProgramBuildInfo: |
| { |
| cl_program program = call.params.getParamCaptures()[0].value.cl_programVal; |
| objectStream << static_cast<void *>(program); |
| break; |
| } |
| case EntryPoint::CLGetKernelInfo: |
| case EntryPoint::CLGetKernelArgInfo: |
| case EntryPoint::CLGetKernelWorkGroupInfo: |
| { |
| cl_kernel kernel = call.params.getParamCaptures()[0].value.cl_kernelVal; |
| objectStream << static_cast<void *>(kernel); |
| break; |
| } |
| case EntryPoint::CLGetEventInfo: |
| case EntryPoint::CLGetEventProfilingInfo: |
| { |
| cl_event event = call.params.getParamCaptures()[0].value.cl_eventVal; |
| objectStream << static_cast<void *>(event); |
| break; |
| } |
| case EntryPoint::CLGetMemObjectInfo: |
| case EntryPoint::CLGetImageInfo: |
| { |
| cl_mem mem = call.params.getParamCaptures()[0].value.cl_memVal; |
| objectStream << static_cast<void *>(mem); |
| break; |
| } |
| case EntryPoint::CLGetSamplerInfo: |
| { |
| cl_sampler sampler = call.params.getParamCaptures()[0].value.cl_samplerVal; |
| objectStream << static_cast<void *>(sampler); |
| break; |
| } |
| default: |
| break; |
| } |
| clObject = objectStream.str(); |
| |
| // Go through the param_name options |
| switch (call.entryPoint) |
| { |
| case EntryPoint::CLGetPlatformInfo: |
| { |
| cl::PlatformInfo info = call.params.getParamCaptures()[1].value.PlatformInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| json.addString("platform", clObject); |
| |
| switch (ToCLenum(info)) |
| { |
| case CL_PLATFORM_PROFILE: |
| case CL_PLATFORM_VERSION: |
| case CL_PLATFORM_NAME: |
| case CL_PLATFORM_VENDOR: |
| case CL_PLATFORM_EXTENSIONS: |
| case CL_PLATFORM_ICD_SUFFIX_KHR: |
| { |
| json.addCString(infoString, static_cast<const char *>(data)); |
| break; |
| } |
| case CL_PLATFORM_EXTENSIONS_WITH_VERSION: |
| { |
| const cl_name_version *nameVersion = static_cast<const cl_name_version *>(data); |
| json.startGroup(infoString); |
| for (size_t j = 0; j < size / sizeof(cl_name_version); ++j) |
| { |
| json.addScalar(nameVersion[j].name, nameVersion[j].version); |
| } |
| json.endGroup(); |
| break; |
| } |
| case CL_PLATFORM_NUMERIC_VERSION: |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| case CL_PLATFORM_HOST_TIMER_RESOLUTION: |
| case CL_PLATFORM_COMMAND_BUFFER_CAPABILITIES_KHR: |
| json.addScalar(infoString, *static_cast<const cl_ulong *>(data)); |
| break; |
| case CL_PLATFORM_EXTERNAL_MEMORY_IMPORT_HANDLE_TYPES_KHR: |
| case CL_PLATFORM_SEMAPHORE_TYPES_KHR: |
| case CL_PLATFORM_SEMAPHORE_IMPORT_HANDLE_TYPES_KHR: |
| case CL_PLATFORM_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR: |
| json.addVector(infoString, |
| std::vector<cl_uint>((cl_uint *)data, |
| (cl_uint *)data + size / sizeof(cl_uint))); |
| break; |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| |
| break; |
| } |
| case EntryPoint::CLGetDeviceInfo: |
| { |
| cl::DeviceInfo info = call.params.getParamCaptures()[1].value.DeviceInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| json.addString("device", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_DEVICE_IL_VERSION: |
| case CL_DEVICE_LATEST_CONFORMANCE_VERSION_PASSED: |
| case CL_DEVICE_OPENCL_C_VERSION: |
| case CL_DEVICE_EXTENSIONS: |
| case CL_DEVICE_VERSION: |
| case CL_DEVICE_PROFILE: |
| case CL_DRIVER_VERSION: |
| case CL_DEVICE_VENDOR: |
| case CL_DEVICE_NAME: |
| json.addCString(infoString, static_cast<const char *>(data)); |
| break; |
| case CL_DEVICE_TYPE: |
| case CL_DEVICE_MAX_MEM_ALLOC_SIZE: |
| case CL_DEVICE_LOCAL_MEM_SIZE: |
| case CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE: |
| case CL_DEVICE_GLOBAL_MEM_SIZE: |
| case CL_DEVICE_GLOBAL_MEM_CACHE_SIZE: |
| case CL_DEVICE_HALF_FP_CONFIG: |
| case CL_DEVICE_SINGLE_FP_CONFIG: |
| case CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES: |
| case CL_DEVICE_ATOMIC_FENCE_CAPABILITIES: |
| case CL_DEVICE_ATOMIC_MEMORY_CAPABILITIES: |
| case CL_DEVICE_SVM_CAPABILITIES: |
| case CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES: |
| case CL_DEVICE_PARTITION_AFFINITY_DOMAIN: |
| case CL_DEVICE_DOUBLE_FP_CONFIG: |
| case CL_DEVICE_QUEUE_ON_HOST_PROPERTIES: |
| case CL_DEVICE_EXECUTION_CAPABILITIES: |
| // cl_ulong and cl_bitfield |
| json.addScalar(infoString, *static_cast<const cl_ulong *>(data)); |
| break; |
| case CL_DEVICE_VENDOR_ID: |
| case CL_DEVICE_MAX_COMPUTE_UNITS: |
| case CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS: |
| case CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR: |
| case CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT: |
| case CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT: |
| case CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG: |
| case CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT: |
| case CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE: |
| case CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF: |
| case CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR: |
| case CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT: |
| case CL_DEVICE_NATIVE_VECTOR_WIDTH_INT: |
| case CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG: |
| case CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT: |
| case CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE: |
| case CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF: |
| case CL_DEVICE_MAX_CLOCK_FREQUENCY: |
| case CL_DEVICE_ADDRESS_BITS: |
| case CL_DEVICE_IMAGE_SUPPORT: |
| case CL_DEVICE_MAX_READ_IMAGE_ARGS: |
| case CL_DEVICE_MAX_WRITE_IMAGE_ARGS: |
| case CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS: |
| case CL_DEVICE_PIPE_SUPPORT: |
| case CL_DEVICE_GENERIC_ADDRESS_SPACE_SUPPORT: |
| case CL_DEVICE_WORK_GROUP_COLLECTIVE_FUNCTIONS_SUPPORT: |
| case CL_DEVICE_NON_UNIFORM_WORK_GROUP_SUPPORT: |
| case CL_DEVICE_NUMERIC_VERSION: |
| case CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS: |
| case CL_DEVICE_MAX_NUM_SUB_GROUPS: |
| case CL_DEVICE_PREFERRED_LOCAL_ATOMIC_ALIGNMENT: |
| case CL_DEVICE_PREFERRED_GLOBAL_ATOMIC_ALIGNMENT: |
| case CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT: |
| case CL_DEVICE_PIPE_MAX_PACKET_SIZE: |
| case CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS: |
| case CL_DEVICE_MAX_PIPE_ARGS: |
| case CL_DEVICE_MAX_ON_DEVICE_EVENTS: |
| case CL_DEVICE_MAX_ON_DEVICE_QUEUES: |
| case CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE: |
| case CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE: |
| case CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT: |
| case CL_DEVICE_IMAGE_PITCH_ALIGNMENT: |
| case CL_DEVICE_PREFERRED_INTEROP_USER_SYNC: |
| case CL_DEVICE_REFERENCE_COUNT: |
| case CL_DEVICE_PARTITION_MAX_SUB_DEVICES: |
| case CL_DEVICE_LINKER_AVAILABLE: |
| case CL_DEVICE_HOST_UNIFIED_MEMORY: |
| case CL_DEVICE_COMPILER_AVAILABLE: |
| case CL_DEVICE_AVAILABLE: |
| case CL_DEVICE_ENDIAN_LITTLE: |
| case CL_DEVICE_ERROR_CORRECTION_SUPPORT: |
| case CL_DEVICE_LOCAL_MEM_TYPE: |
| case CL_DEVICE_MAX_CONSTANT_ARGS: |
| case CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE: |
| case CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE: |
| case CL_DEVICE_MEM_BASE_ADDR_ALIGN: |
| case CL_DEVICE_MAX_SAMPLERS: |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| case CL_DEVICE_MAX_WORK_GROUP_SIZE: |
| case CL_DEVICE_IMAGE2D_MAX_WIDTH: |
| case CL_DEVICE_IMAGE2D_MAX_HEIGHT: |
| case CL_DEVICE_IMAGE3D_MAX_WIDTH: |
| case CL_DEVICE_IMAGE3D_MAX_HEIGHT: |
| case CL_DEVICE_IMAGE3D_MAX_DEPTH: |
| case CL_DEVICE_IMAGE_MAX_BUFFER_SIZE: |
| case CL_DEVICE_IMAGE_MAX_ARRAY_SIZE: |
| case CL_DEVICE_PREFERRED_WORK_GROUP_SIZE_MULTIPLE: |
| case CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE: |
| case CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE: |
| case CL_DEVICE_PRINTF_BUFFER_SIZE: |
| case CL_DEVICE_PROFILING_TIMER_RESOLUTION: |
| case CL_DEVICE_MAX_PARAMETER_SIZE: |
| json.addScalar(infoString, *static_cast<const size_t *>(data)); |
| break; |
| case CL_DEVICE_MAX_WORK_ITEM_SIZES: |
| json.addVector(infoString, |
| std::vector<size_t>((size_t *)data, |
| (size_t *)data + size / sizeof(size_t))); |
| break; |
| case CL_DEVICE_PARTITION_TYPE: |
| case CL_DEVICE_PARTITION_PROPERTIES: |
| json.addVector(infoString, std::vector<cl_ulong>( |
| (cl_ulong *)data, |
| (cl_ulong *)data + size / sizeof(cl_ulong))); |
| break; |
| case CL_DEVICE_PARENT_DEVICE: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_device_id *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| case CL_DEVICE_PLATFORM: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_platform_id *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| case CL_DEVICE_ILS_WITH_VERSION: |
| case CL_DEVICE_OPENCL_C_FEATURES: |
| case CL_DEVICE_OPENCL_C_ALL_VERSIONS: |
| case CL_DEVICE_BUILT_IN_KERNELS_WITH_VERSION: |
| case CL_DEVICE_EXTENSIONS_WITH_VERSION: |
| { |
| const cl_name_version *nameVersion = static_cast<const cl_name_version *>(data); |
| json.startGroup(infoString); |
| for (size_t j = 0; j < size / sizeof(cl_name_version); ++j) |
| { |
| json.addScalar(nameVersion[j].name, nameVersion[j].version); |
| } |
| json.endGroup(); |
| break; |
| } |
| |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| |
| break; |
| } |
| case EntryPoint::CLGetContextInfo: |
| { |
| cl::ContextInfo info = call.params.getParamCaptures()[1].value.ContextInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("context", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_PLATFORM_PROFILE: |
| case CL_PLATFORM_VERSION: |
| case CL_PLATFORM_NAME: |
| case CL_PLATFORM_VENDOR: |
| case CL_PLATFORM_EXTENSIONS: |
| case CL_PLATFORM_ICD_SUFFIX_KHR: |
| { |
| json.addCString(infoString, static_cast<const char *>(data)); |
| break; |
| } |
| case CL_CONTEXT_REFERENCE_COUNT: |
| case CL_CONTEXT_NUM_DEVICES: |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| case CL_CONTEXT_PROPERTIES: |
| json.addVector(infoString, std::vector<cl_ulong>( |
| (cl_ulong *)data, |
| (cl_ulong *)data + size / sizeof(cl_ulong))); |
| break; |
| case CL_CONTEXT_DEVICES: |
| { |
| const cl_device_id *devices = static_cast<const cl_device_id *>(data); |
| std::vector<std::string> devicesStrings; |
| for (size_t j = 0; j < size / sizeof(cl_device_id); ++j) |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(devices[j]); |
| devicesStrings.push_back(voidStream.str()); |
| } |
| json.addVectorOfStrings(infoString, devicesStrings); |
| break; |
| } |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| |
| break; |
| } |
| case EntryPoint::CLGetCommandQueueInfo: |
| { |
| cl::CommandQueueInfo info = call.params.getParamCaptures()[1].value.CommandQueueInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("command_queue", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_QUEUE_DEVICE_DEFAULT: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_command_queue *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| case CL_QUEUE_CONTEXT: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_context *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| case CL_QUEUE_DEVICE: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_device_id *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| case CL_QUEUE_REFERENCE_COUNT: |
| case CL_QUEUE_SIZE: |
| { |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| } |
| case CL_QUEUE_PROPERTIES: |
| { |
| json.addScalar(infoString, *static_cast<const cl_ulong *>(data)); |
| break; |
| } |
| case CL_QUEUE_PROPERTIES_ARRAY: |
| { |
| json.addVector(infoString, std::vector<cl_ulong>( |
| (cl_ulong *)data, |
| (cl_ulong *)data + size / sizeof(cl_ulong))); |
| break; |
| } |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| |
| break; |
| } |
| case EntryPoint::CLGetProgramInfo: |
| { |
| cl::ProgramInfo info = call.params.getParamCaptures()[1].value.ProgramInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("program", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_PROGRAM_SOURCE: |
| case CL_PROGRAM_IL: |
| case CL_PROGRAM_KERNEL_NAMES: |
| { |
| json.addCString(infoString, static_cast<const char *>(data)); |
| break; |
| } |
| case CL_PROGRAM_CONTEXT: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_context *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| case CL_PROGRAM_REFERENCE_COUNT: |
| case CL_PROGRAM_NUM_DEVICES: |
| case CL_PROGRAM_SCOPE_GLOBAL_CTORS_PRESENT: |
| case CL_PROGRAM_SCOPE_GLOBAL_DTORS_PRESENT: |
| { |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| } |
| case CL_PROGRAM_DEVICES: |
| { |
| const cl_device_id *devices = static_cast<const cl_device_id *>(data); |
| std::vector<std::string> devicesStrings; |
| for (size_t j = 0; j < size / sizeof(cl_device_id); ++j) |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(devices[j]); |
| devicesStrings.push_back(voidStream.str()); |
| } |
| json.addVectorOfStrings(infoString, devicesStrings); |
| break; |
| } |
| case CL_PROGRAM_NUM_KERNELS: |
| { |
| json.addScalar(infoString, *static_cast<const size_t *>(data)); |
| break; |
| } |
| case CL_PROGRAM_BINARY_SIZES: |
| json.addVector(infoString, |
| std::vector<size_t>((size_t *)data, |
| (size_t *)data + size / sizeof(size_t))); |
| break; |
| case CL_PROGRAM_BINARIES: |
| json.addVector(infoString, |
| std::vector<unsigned char>( |
| (unsigned char *)data, |
| (unsigned char *)data + size / sizeof(unsigned char))); |
| break; |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| |
| break; |
| } |
| case EntryPoint::CLGetProgramBuildInfo: |
| { |
| cl::ProgramBuildInfo info = call.params.getParamCaptures()[2].value.ProgramBuildInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("program", clObject); |
| cl_device_id device = call.params.getParamCaptures()[1].value.cl_device_idVal; |
| std::ostringstream objectStream2; |
| objectStream2 << static_cast<void *>(device); |
| clObject = objectStream2.str(); |
| json.addString("device", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_PROGRAM_BUILD_OPTIONS: |
| case CL_PROGRAM_BUILD_LOG: |
| { |
| json.addCString(infoString, static_cast<const char *>(data)); |
| break; |
| } |
| case CL_PROGRAM_BINARY_TYPE: |
| { |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| } |
| case CL_PROGRAM_BUILD_STATUS: |
| { |
| json.addScalar(infoString, *static_cast<const cl_int *>(data)); |
| break; |
| } |
| case CL_PROGRAM_BUILD_GLOBAL_VARIABLE_TOTAL_SIZE: |
| { |
| json.addScalar(infoString, *static_cast<const size_t *>(data)); |
| break; |
| } |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| break; |
| } |
| case EntryPoint::CLGetKernelInfo: |
| { |
| cl::KernelInfo info = call.params.getParamCaptures()[1].value.KernelInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("kernel", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_KERNEL_FUNCTION_NAME: |
| case CL_KERNEL_ATTRIBUTES: |
| { |
| json.addCString(infoString, static_cast<const char *>(data)); |
| break; |
| } |
| case CL_KERNEL_NUM_ARGS: |
| case CL_KERNEL_REFERENCE_COUNT: |
| { |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| } |
| case CL_KERNEL_CONTEXT: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_context *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| case CL_KERNEL_PROGRAM: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_program *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| break; |
| } |
| case EntryPoint::CLGetKernelArgInfo: |
| { |
| cl::KernelArgInfo info = call.params.getParamCaptures()[2].value.KernelArgInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("kernel", clObject); |
| cl_uint index = call.params.getParamCaptures()[1].value.cl_uintVal; |
| json.addScalar("arg_index", index); |
| switch (ToCLenum(info)) |
| { |
| case CL_KERNEL_ARG_TYPE_NAME: |
| case CL_KERNEL_ARG_NAME: |
| { |
| json.addCString(infoString, static_cast<const char *>(data)); |
| break; |
| } |
| case CL_KERNEL_ARG_ADDRESS_QUALIFIER: |
| case CL_KERNEL_ARG_ACCESS_QUALIFIER: |
| { |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| } |
| case CL_KERNEL_ARG_TYPE_QUALIFIER: |
| { |
| json.addScalar(infoString, *static_cast<const cl_ulong *>(data)); |
| break; |
| } |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| break; |
| } |
| case EntryPoint::CLGetKernelWorkGroupInfo: |
| { |
| cl::KernelWorkGroupInfo info = |
| call.params.getParamCaptures()[2].value.KernelWorkGroupInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("kernel", clObject); |
| cl_device_id device = call.params.getParamCaptures()[1].value.cl_device_idVal; |
| std::ostringstream objectStream2; |
| objectStream2 << static_cast<void *>(device); |
| clObject = objectStream2.str(); |
| json.addString("device", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_KERNEL_LOCAL_MEM_SIZE: |
| case CL_KERNEL_PRIVATE_MEM_SIZE: |
| { |
| json.addScalar(infoString, *static_cast<const cl_ulong *>(data)); |
| break; |
| } |
| case CL_KERNEL_WORK_GROUP_SIZE: |
| case CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE: |
| { |
| json.addScalar(infoString, *static_cast<const size_t *>(data)); |
| break; |
| } |
| case CL_KERNEL_GLOBAL_WORK_SIZE: |
| case CL_KERNEL_COMPILE_WORK_GROUP_SIZE: |
| { |
| json.addVector(infoString, |
| std::vector<size_t>((size_t *)data, (size_t *)data + 3)); |
| break; |
| } |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| break; |
| } |
| case EntryPoint::CLGetEventInfo: |
| { |
| cl::EventInfo info = call.params.getParamCaptures()[1].value.EventInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("event", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_EVENT_REFERENCE_COUNT: |
| case CL_EVENT_COMMAND_TYPE: |
| { |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| } |
| case CL_EVENT_COMMAND_EXECUTION_STATUS: |
| { |
| json.addScalar(infoString, *static_cast<const cl_int *>(data)); |
| break; |
| } |
| case CL_EVENT_CONTEXT: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_context *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| case CL_EVENT_COMMAND_QUEUE: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_command_queue *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| break; |
| } |
| case EntryPoint::CLGetEventProfilingInfo: |
| { |
| cl::ProfilingInfo info = call.params.getParamCaptures()[1].value.ProfilingInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("event", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_PROFILING_COMMAND_QUEUED: |
| case CL_PROFILING_COMMAND_SUBMIT: |
| case CL_PROFILING_COMMAND_START: |
| case CL_PROFILING_COMMAND_END: |
| case CL_PROFILING_COMMAND_COMPLETE: |
| { |
| json.addScalar(infoString, *static_cast<const cl_ulong *>(data)); |
| break; |
| } |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| break; |
| } |
| case EntryPoint::CLGetMemObjectInfo: |
| { |
| cl::MemInfo info = call.params.getParamCaptures()[1].value.MemInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("memObj", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_MEM_TYPE: |
| case CL_MEM_MAP_COUNT: |
| case CL_MEM_REFERENCE_COUNT: |
| case CL_MEM_USES_SVM_POINTER: |
| { |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| } |
| case CL_MEM_FLAGS: |
| { |
| json.addScalar(infoString, *static_cast<const cl_ulong *>(data)); |
| break; |
| } |
| case CL_MEM_SIZE: |
| case CL_MEM_OFFSET: |
| { |
| json.addScalar(infoString, *static_cast<const size_t *>(data)); |
| break; |
| } |
| case CL_MEM_HOST_PTR: |
| { |
| std::ostringstream voidStream; |
| voidStream << data; |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| case CL_MEM_CONTEXT: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_context *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| case CL_MEM_ASSOCIATED_MEMOBJECT: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_mem *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| case CL_MEM_PROPERTIES: |
| { |
| json.addVector(infoString, std::vector<cl_mem_properties>( |
| (cl_mem_properties *)data, |
| (cl_mem_properties *)data + |
| size / sizeof(cl_mem_properties))); |
| break; |
| } |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| break; |
| } |
| case EntryPoint::CLGetImageInfo: |
| { |
| cl::ImageInfo info = call.params.getParamCaptures()[1].value.ImageInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("image", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_IMAGE_FORMAT: |
| { |
| json.startGroup(infoString); |
| json.addScalar("image_channel_order", |
| static_cast<const cl_image_format *>(data)->image_channel_order); |
| json.addScalar( |
| "image_channel_data_type", |
| static_cast<const cl_image_format *>(data)->image_channel_data_type); |
| json.endGroup(); |
| break; |
| } |
| case CL_IMAGE_NUM_MIP_LEVELS: |
| case CL_IMAGE_NUM_SAMPLES: |
| { |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| } |
| case CL_IMAGE_ELEMENT_SIZE: |
| case CL_IMAGE_ROW_PITCH: |
| case CL_IMAGE_SLICE_PITCH: |
| case CL_IMAGE_WIDTH: |
| case CL_IMAGE_HEIGHT: |
| case CL_IMAGE_DEPTH: |
| case CL_IMAGE_ARRAY_SIZE: |
| { |
| json.addScalar(infoString, *static_cast<const size_t *>(data)); |
| break; |
| } |
| case CL_IMAGE_BUFFER: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_mem *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| break; |
| } |
| case EntryPoint::CLGetSamplerInfo: |
| { |
| cl::SamplerInfo info = call.params.getParamCaptures()[1].value.SamplerInfoVal; |
| std::ostringstream oss; |
| oss << info; |
| std::string infoString = oss.str(); |
| |
| json.addString("image", clObject); |
| switch (ToCLenum(info)) |
| { |
| case CL_SAMPLER_REFERENCE_COUNT: |
| case CL_SAMPLER_NORMALIZED_COORDS: |
| case CL_SAMPLER_ADDRESSING_MODE: |
| case CL_SAMPLER_FILTER_MODE: |
| { |
| json.addScalar(infoString, *static_cast<const cl_uint *>(data)); |
| break; |
| } |
| case CL_SAMPLER_PROPERTIES: |
| { |
| json.addVector(infoString, std::vector<cl_sampler_properties>( |
| (cl_sampler_properties *)data, |
| (cl_sampler_properties *)data + |
| size / sizeof(cl_sampler_properties))); |
| break; |
| } |
| case CL_SAMPLER_CONTEXT: |
| { |
| std::ostringstream voidStream; |
| voidStream << static_cast<void *>(*(cl_context *)data); |
| std::string memLoc = voidStream.str(); |
| json.addCString(infoString, memLoc.c_str()); |
| break; |
| } |
| default: |
| // Not supported or cannot add to JSON file |
| break; |
| } |
| break; |
| } |
| default: |
| break; |
| } |
| |
| json.endGroup(); |
| |
| mCLInfoJson += std::string(json.data()) + ",\n"; |
| } |
| |
| void FrameCaptureShared::writeJSONCLGetInfo() |
| { |
| std::stringstream jsonFileNameStream; |
| jsonFileNameStream << mOutDirectory << FmtCapturePrefix(kNoContextId, mCaptureLabel) |
| << "_OpenCL_info.json"; |
| std::string jsonFileName = jsonFileNameStream.str(); |
| |
| SaveFileHelper saveData(jsonFileName); |
| |
| saveData.write(reinterpret_cast<const uint8_t *>(mCLInfoJson.c_str()), mCLInfoJson.length()); |
| } |
| |
| void FrameCaptureShared::writeCppReplayIndexFilesCL() |
| { |
| // Ensure the last frame is written. This will no-op if the frame is already written. |
| mReplayWriter.saveFrame(); |
| |
| { |
| std::stringstream header; |
| |
| header << "#pragma once\n"; |
| header << "\n"; |
| header << "#define CL_NO_EXTENSION_PROTOTYPES\n"; |
| header << "#include <angle_cl.h>\n"; |
| header << "#include <stdint.h>\n"; |
| header << "#include \"trace_fixture_cl.h\"\n"; |
| |
| std::string includes = header.str(); |
| mReplayWriter.setHeaderPrologue(includes); |
| } |
| |
| { |
| std::stringstream source; |
| |
| source << "#include \"" << FmtCapturePrefix(kNoContextId, mCaptureLabel) << ".h\"\n"; |
| source << "#include \"trace_fixture_cl.h\"\n"; |
| |
| std::string sourcePrologue = source.str(); |
| mReplayWriter.setSourcePrologue(sourcePrologue); |
| } |
| |
| { |
| std::string proto = "void InitReplay(void)"; |
| |
| std::stringstream source; |
| source << proto << "\n"; |
| source << "{\n"; |
| WriteInitReplayCallCL(mCompression, source, mCaptureLabel, 0, mReadBufferSize, |
| mMaxCLParamsSize); |
| source << "}\n"; |
| |
| mReplayWriter.addPrivateFunction(proto, std::stringstream(), source); |
| } |
| |
| { |
| std::string proto = "void ReplayFrame(uint32_t frameIndex)"; |
| |
| std::stringstream source; |
| |
| source << proto << "\n"; |
| source << "{\n"; |
| source << " switch (frameIndex)\n"; |
| source << " {\n"; |
| for (uint32_t frameIndex : mActiveFrameIndices) |
| { |
| source << " case " << frameIndex << ":\n"; |
| source << " " << FmtReplayFunction(kNoContextId, FuncUsage::Call, frameIndex) |
| << ";\n"; |
| source << " break;\n"; |
| } |
| source << " default:\n"; |
| source << " break;\n"; |
| source << " }\n"; |
| source << "}\n"; |
| |
| mReplayWriter.addPublicFunction(proto, std::stringstream(), source); |
| } |
| |
| for (auto extFuncName : mExtFuncsAdded) |
| { |
| mReplayWriter.addStaticVariable(extFuncName + "_fn", extFuncName); |
| } |
| |
| std::stringstream protoSetupStream; |
| protoSetupStream << "void SetupFirstFrame(void)"; |
| std::string protoSetup = protoSetupStream.str(); |
| std::stringstream headerStreamSetup; |
| std::stringstream bodyStreamSetup; |
| WriteCppReplayFunctionWithPartsCL(ReplayFunc::SetupFirstFrame, mReplayWriter, |
| mCaptureStartFrame, &mBinaryData, mCLSetupCalls, |
| headerStreamSetup, bodyStreamSetup); |
| mReplayWriter.addPublicFunction(protoSetup, headerStreamSetup, bodyStreamSetup); |
| |
| { |
| std::string proto = "void ResetReplay(void)"; |
| std::stringstream source; |
| source << proto << "\n" << "{\n"; |
| printCLResetObjs(source); |
| source << "}\n"; |
| mReplayWriter.addPublicFunction(proto, std::stringstream(), source); |
| } |
| |
| { |
| std::stringstream fnameStream; |
| fnameStream << mOutDirectory << FmtCapturePrefix(kNoContextId, mCaptureLabel); |
| std::string fnamePattern = fnameStream.str(); |
| |
| mReplayWriter.setFilenamePattern(fnamePattern); |
| } |
| |
| mReplayWriter.saveIndexFilesAndHeader(); |
| |
| writeJSONCL(); |
| writeJSONCLGetInfo(); |
| } |
| |
| void FrameCaptureShared::writeMainContextCppReplayCL() |
| { |
| { |
| std::stringstream header; |
| |
| header << "#include \"" << FmtCapturePrefix(kNoContextId, mCaptureLabel) << ".h\"\n"; |
| header << "#include \"trace_fixture_cl.h\"\n"; |
| |
| std::string headerString = header.str(); |
| mReplayWriter.setSourcePrologue(headerString); |
| } |
| |
| uint32_t frameIndex = getReplayFrameIndex(); |
| |
| if (frameIndex == 1) |
| { |
| { |
| std::string proto = "void SetupReplay(void)"; |
| |
| std::stringstream out; |
| |
| out << proto << "\n"; |
| out << "{\n"; |
| |
| // Setup all of the shared objects. |
| out << " InitReplay();\n"; |
| |
| out << "}\n"; |
| |
| mReplayWriter.addPublicFunction(proto, std::stringstream(), out); |
| } |
| } |
| |
| if (!mFrameCalls.empty()) |
| { |
| std::stringstream protoStream; |
| protoStream << "void " |
| << FmtReplayFunction(kNoContextId, FuncUsage::Prototype, mFrameIndex); |
| std::string proto = protoStream.str(); |
| std::stringstream headerStream; |
| std::stringstream bodyStream; |
| |
| WriteCppReplayFunctionWithPartsCL(ReplayFunc::Replay, mReplayWriter, mFrameIndex, |
| &mBinaryData, mFrameCalls, headerStream, bodyStream); |
| |
| mReplayWriter.addPrivateFunction(proto, headerStream, bodyStream); |
| } |
| |
| { |
| std::stringstream fnamePatternStream; |
| fnamePatternStream << mOutDirectory << FmtCapturePrefix(kNoContextId, mCaptureLabel); |
| std::string fnamePattern = fnamePatternStream.str(); |
| |
| mReplayWriter.setFilenamePattern(fnamePattern); |
| } |
| |
| if (mFrameIndex == mCaptureEndFrame) |
| { |
| mReplayWriter.saveFrame(); |
| } |
| } |
| |
| } // namespace angle |