| /* |
| * Copyright (c) 2019, Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| * OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| //! |
| //! \file mhw_cmd_reader.cpp |
| //! \brief Implementation of class MhwCmdReader |
| //! |
| |
| #if (_DEBUG || _RELEASE_INTERNAL) |
| |
| #include "mhw_cmd_reader.h" |
| #include "mos_utilities.h" |
| #include <algorithm> |
| #include <fstream> |
| #include <sstream> |
| |
| using namespace std; |
| |
| shared_ptr<MhwCmdReader> MhwCmdReader::m_instance = nullptr; |
| |
| shared_ptr<MhwCmdReader> MhwCmdReader::GetInstance() |
| { |
| if (!m_instance) |
| { |
| m_instance = make_shared<MhwCmdReader>(); |
| m_instance->SetFilePath(GetOverrideDataPath()); |
| m_instance->PrepareCmdData(); |
| } |
| return m_instance; |
| } |
| |
| pair<uint32_t *, uint32_t> MhwCmdReader::FindCmd(uint32_t *cmdBuf, uint32_t dwLen, OPCODE opcode) const |
| { |
| uint32_t currOpcode, currLen; |
| uint32_t offset = 0; |
| pair<uint32_t *, uint32_t> cmd(nullptr, 0); |
| |
| while (offset < dwLen) |
| { |
| ParseCmdHeader(cmdBuf[offset], currOpcode, currLen); |
| |
| if (currOpcode == MI_BATCH_BUFFER_END || currOpcode == opcode) |
| { |
| if (currOpcode == opcode) |
| { |
| cmd.first = &cmdBuf[offset]; |
| cmd.second = currLen; |
| } |
| return cmd; |
| } |
| |
| offset += currLen; |
| } |
| |
| return cmd; |
| } |
| |
| void MhwCmdReader::OverrideCmdBuf(uint32_t *cmdBuf, uint32_t dwLen) |
| { |
| if (!m_ready) |
| { |
| return; |
| } |
| |
| uint32_t opcode, len; |
| uint32_t offset = 0; |
| |
| while (offset < dwLen) |
| { |
| ParseCmdHeader(cmdBuf[offset], opcode, len); |
| |
| if (opcode == MI_BATCH_BUFFER_END) |
| { |
| break; |
| } |
| |
| OverrideOneCmd(&cmdBuf[offset], opcode, len); |
| offset += len; |
| } |
| } |
| |
| string MhwCmdReader::GetOverrideDataPath() |
| { |
| char path[1024] = {}; |
| MOS_USER_FEATURE_VALUE_DATA userFeatureData = {}; |
| |
| userFeatureData.StringData.pStringData = path; |
| MOS_UserFeature_ReadValue_ID( |
| nullptr, |
| __MEDIA_USER_FEATURE_VALUE_COMMAND_OVERRIDE_INPUT_FILE_PATH_ID, |
| &userFeatureData, |
| nullptr); |
| |
| return path; |
| } |
| |
| string MhwCmdReader::TrimSpace(const string &str) |
| { |
| int32_t sz = static_cast<int32_t>(str.size()); |
| int32_t beg = 0; |
| while (beg < sz) |
| { |
| if (str[beg] != ' ') |
| { |
| break; |
| } |
| ++beg; |
| } |
| |
| int32_t end = sz - 1; |
| while (end >= beg) |
| { |
| if (str[end] != ' ') |
| { |
| break; |
| } |
| --end; |
| } |
| |
| if (beg < sz) |
| { |
| return str.substr(beg, static_cast<int64_t>(end) - beg + 1); |
| } |
| else |
| { |
| return string(); |
| } |
| } |
| |
| void MhwCmdReader::SetFilePath(string path) |
| { |
| if (!path.empty()) |
| { |
| m_path = path; |
| } |
| } |
| |
| void MhwCmdReader::PrepareCmdData() |
| { |
| ifstream fs(m_path); |
| |
| if (!fs) |
| { |
| return; |
| } |
| |
| string line; |
| getline(fs, line); // ignore the first line |
| |
| while (getline(fs, line)) |
| { |
| CmdField field = {}; |
| |
| size_t beg = 0; |
| size_t end = line.find(','); |
| field.info.opcode = stoul(TrimSpace(line.substr(beg, end - beg)), 0, 16); |
| |
| beg = end + 1; |
| end = line.find(',', beg); |
| field.info.dwordIdx = stoul(TrimSpace(line.substr(beg, end - beg))); |
| |
| beg = end + 1; |
| end = line.find(',', beg); |
| field.info.stardBit = stoul(TrimSpace(line.substr(beg, end - beg))); |
| |
| beg = end + 1; |
| end = line.find(',', beg); |
| field.info.endBit = stoul(TrimSpace(line.substr(beg, end - beg))); |
| |
| beg = end + 1; |
| end = line.find(',', beg); |
| field.info.longTerm = stoul(TrimSpace(line.substr(beg, end - beg))); |
| |
| beg = end + 1; |
| end = line.find(',', beg); |
| field.overrideData = stoul(TrimSpace(line.substr(beg, end - beg)), 0, 0); |
| |
| if (field.info.longTerm) |
| { |
| m_longTermFields.push_back(field); |
| } |
| else |
| { |
| m_shortTermFields.push_back(field); |
| } |
| } |
| |
| fs.close(); |
| m_ready = true; |
| } |
| |
| void MhwCmdReader::ParseCmdHeader(uint32_t cmdHdr, uint32_t &opcode, uint32_t &dwSize) const |
| { |
| if (cmdHdr >> 29 == 0) // MI commands |
| { |
| opcode = (cmdHdr >> 23) << 23; |
| |
| if (opcode == MI_NOOP || opcode == MI_BATCH_BUFFER_END) |
| { |
| dwSize = 1; |
| } |
| else if (opcode == MI_FLUSH_DW) |
| { |
| dwSize = (cmdHdr & 0x1f) + 2; |
| } |
| else if (opcode == MI_STORE_DATA_IMM) |
| { |
| dwSize = (cmdHdr & 0x3ff) + 2; |
| } |
| else |
| { |
| dwSize = (cmdHdr & 0xff) + 2; |
| } |
| } |
| else if (cmdHdr >> 29 == 3) // VDBOX commands |
| { |
| opcode = (cmdHdr >> 16) << 16; |
| |
| if (opcode == MFX_WAIT) |
| { |
| dwSize = 1; |
| } |
| else |
| { |
| dwSize = (cmdHdr & 0xfff) + 2; |
| } |
| } |
| else // unknown opcodes |
| { |
| opcode = cmdHdr; |
| dwSize = 1; |
| } |
| } |
| |
| void MhwCmdReader::AssignField(uint32_t *cmd, const CmdField &field) const |
| { |
| if (field.info.stardBit > field.info.endBit) |
| { |
| return; |
| } |
| |
| uint32_t mask = 0; |
| for (uint32_t i = 0; i < field.info.stardBit; i++) |
| { |
| mask |= (1 << i); |
| } |
| for (uint32_t i = 31; i > field.info.endBit; i--) |
| { |
| mask |= (1 << i); |
| } |
| |
| cmd[field.info.dwordIdx] &= mask; |
| cmd[field.info.dwordIdx] |= (field.overrideData << field.info.stardBit); |
| } |
| |
| void MhwCmdReader::OverrideOneCmd(uint32_t *cmd, uint32_t opcode, uint32_t dwLen) |
| { |
| for (const auto &e : m_longTermFields) |
| { |
| if (e.info.opcode == opcode && e.info.dwordIdx < dwLen) |
| { |
| AssignField(cmd, e); |
| } |
| } |
| |
| auto it = m_shortTermFields.begin(); |
| while (it != m_shortTermFields.end()) |
| { |
| if (it->info.opcode == opcode) |
| { |
| if (it->info.dwordIdx == 0x1fffff) // 0x1fffff is a delimiter which indicates following override data are for next time adding this command |
| { |
| m_shortTermFields.erase(it); |
| break; |
| } |
| else |
| { |
| if (it->info.dwordIdx < dwLen) |
| { |
| AssignField(cmd, *it); |
| } |
| it = m_shortTermFields.erase(it); |
| } |
| } |
| else |
| { |
| ++it; |
| } |
| } |
| } |
| |
| #endif // _DEBUG || _RELEASE_INTERNAL |