/* * Copyright (c) 2017, 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. */ #include "unit_tests/gen_common/gen_cmd_parse.h" #include "gtest/gtest.h" // clang-format off using namespace OCLRT; using GPGPU_WALKER = GEN9::GPGPU_WALKER; using MEDIA_INTERFACE_DESCRIPTOR_LOAD = GEN9::MEDIA_INTERFACE_DESCRIPTOR_LOAD; using MEDIA_STATE_FLUSH = GEN9::MEDIA_STATE_FLUSH; using MEDIA_VFE_STATE = GEN9::MEDIA_VFE_STATE; using MI_ARB_CHECK = GEN9::MI_ARB_CHECK; using MI_ATOMIC = GEN9::MI_ATOMIC; using MI_BATCH_BUFFER_END = GEN9::MI_BATCH_BUFFER_END; using MI_BATCH_BUFFER_START = GEN9::MI_BATCH_BUFFER_START; using MI_LOAD_REGISTER_IMM = GEN9::MI_LOAD_REGISTER_IMM; using MI_LOAD_REGISTER_MEM = GEN9::MI_LOAD_REGISTER_MEM; using MI_STORE_REGISTER_MEM = GEN9::MI_STORE_REGISTER_MEM; using MI_NOOP = GEN9::MI_NOOP; using PIPE_CONTROL = GEN9::PIPE_CONTROL; using PIPELINE_SELECT = GEN9::PIPELINE_SELECT; using STATE_BASE_ADDRESS = GEN9::STATE_BASE_ADDRESS; using MI_REPORT_PERF_COUNT = GEN9::MI_REPORT_PERF_COUNT; using MI_MATH = GEN9::MI_MATH; using MI_LOAD_REGISTER_REG = GEN9::MI_LOAD_REGISTER_REG; using GPGPU_CSR_BASE_ADDRESS = GEN9::GPGPU_CSR_BASE_ADDRESS; using STATE_SIP = GEN9::STATE_SIP; // clang-format on template <> STATE_BASE_ADDRESS *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return STATE_BASE_ADDRESS::COMMAND_TYPE_GFXPIPE == pCmd->TheStructure.Common.CommandType && STATE_BASE_ADDRESS::COMMAND_SUBTYPE_GFXPIPE_COMMON == pCmd->TheStructure.Common.CommandSubtype && STATE_BASE_ADDRESS::_3D_COMMAND_OPCODE_GFXPIPE_NONPIPELINED == pCmd->TheStructure.Common._3DCommandOpcode && STATE_BASE_ADDRESS::_3D_COMMAND_SUB_OPCODE_STATE_BASE_ADDRESS == pCmd->TheStructure.Common._3DCommandSubOpcode ? pCmd : nullptr; } template <> GPGPU_WALKER *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return GPGPU_WALKER::COMMAND_TYPE_GFXPIPE == pCmd->TheStructure.Common.CommandType && GPGPU_WALKER::PIPELINE_MEDIA == pCmd->TheStructure.Common.Pipeline && GPGPU_WALKER::MEDIA_COMMAND_OPCODE_GPGPU_WALKER == pCmd->TheStructure.Common.MediaCommandOpcode && GPGPU_WALKER::SUBOPCODE_GPGPU_WALKER_SUBOP == pCmd->TheStructure.Common.Subopcode ? pCmd : nullptr; } template <> MEDIA_INTERFACE_DESCRIPTOR_LOAD *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MEDIA_INTERFACE_DESCRIPTOR_LOAD::COMMAND_TYPE_GFXPIPE == pCmd->TheStructure.Common.CommandType && MEDIA_INTERFACE_DESCRIPTOR_LOAD::PIPELINE_MEDIA == pCmd->TheStructure.Common.Pipeline && MEDIA_INTERFACE_DESCRIPTOR_LOAD::MEDIA_COMMAND_OPCODE_MEDIA_INTERFACE_DESCRIPTOR_LOAD == pCmd->TheStructure.Common.MediaCommandOpcode && MEDIA_INTERFACE_DESCRIPTOR_LOAD::SUBOPCODE_MEDIA_INTERFACE_DESCRIPTOR_LOAD_SUBOP == pCmd->TheStructure.Common.Subopcode ? pCmd : nullptr; } template <> MEDIA_VFE_STATE *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MEDIA_VFE_STATE::COMMAND_TYPE_GFXPIPE == pCmd->TheStructure.Common.CommandType && MEDIA_VFE_STATE::PIPELINE_MEDIA == pCmd->TheStructure.Common.Pipeline && MEDIA_VFE_STATE::MEDIA_COMMAND_OPCODE_MEDIA_VFE_STATE == pCmd->TheStructure.Common.MediaCommandOpcode && MEDIA_VFE_STATE::SUBOPCODE_MEDIA_VFE_STATE_SUBOP == pCmd->TheStructure.Common.Subopcode ? pCmd : nullptr; } template <> MEDIA_STATE_FLUSH *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MEDIA_STATE_FLUSH::COMMAND_TYPE_GFXPIPE == pCmd->TheStructure.Common.CommandType && MEDIA_STATE_FLUSH::PIPELINE_MEDIA == pCmd->TheStructure.Common.Pipeline && MEDIA_STATE_FLUSH::MEDIA_COMMAND_OPCODE_MEDIA_STATE_FLUSH == pCmd->TheStructure.Common.MediaCommandOpcode && MEDIA_STATE_FLUSH::SUBOPCODE_MEDIA_STATE_FLUSH_SUBOP == pCmd->TheStructure.Common.Subopcode ? pCmd : nullptr; } template <> PIPE_CONTROL *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return PIPE_CONTROL::COMMAND_TYPE_GFXPIPE == pCmd->TheStructure.Common.CommandType && PIPE_CONTROL::COMMAND_SUBTYPE_GFXPIPE_3D == pCmd->TheStructure.Common.CommandSubtype && PIPE_CONTROL::_3D_COMMAND_OPCODE_PIPE_CONTROL == pCmd->TheStructure.Common._3DCommandOpcode && PIPE_CONTROL::_3D_COMMAND_SUB_OPCODE_PIPE_CONTROL == pCmd->TheStructure.Common._3DCommandSubOpcode ? pCmd : nullptr; } template <> PIPELINE_SELECT *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return PIPELINE_SELECT::COMMAND_TYPE_GFXPIPE == pCmd->TheStructure.Common.CommandType && PIPELINE_SELECT::COMMAND_SUBTYPE_GFXPIPE_SINGLE_DW == pCmd->TheStructure.Common.CommandSubtype && PIPELINE_SELECT::_3D_COMMAND_OPCODE_GFXPIPE_NONPIPELINED == pCmd->TheStructure.Common._3DCommandOpcode && PIPELINE_SELECT::_3D_COMMAND_SUB_OPCODE_PIPELINE_SELECT == pCmd->TheStructure.Common._3DCommandSubOpcode ? pCmd : nullptr; } template <> MI_ARB_CHECK *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MI_ARB_CHECK::MI_INSTRUCTION_TYPE_MI_INSTRUCTION == pCmd->TheStructure.Common.MiInstructionType && MI_ARB_CHECK::MI_INSTRUCTION_OPCODE_MI_ARB_CHECK == pCmd->TheStructure.Common.MiInstructionOpcode ? pCmd : nullptr; } template <> MI_LOAD_REGISTER_IMM *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MI_LOAD_REGISTER_IMM::COMMAND_TYPE_MI_COMMAND == pCmd->TheStructure.Common.CommandType && MI_LOAD_REGISTER_IMM::MI_COMMAND_OPCODE_MI_LOAD_REGISTER_IMM == pCmd->TheStructure.Common.MiCommandOpcode ? pCmd : nullptr; } template <> MI_NOOP *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MI_NOOP::COMMAND_TYPE_MI_COMMAND == pCmd->TheStructure.Common.CommandType && MI_NOOP::MI_COMMAND_OPCODE_MI_NOOP == pCmd->TheStructure.Common.MiCommandOpcode ? pCmd : nullptr; } template <> MI_ATOMIC *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MI_ATOMIC::COMMAND_TYPE_MI_COMMAND == pCmd->TheStructure.Common.CommandType && MI_ATOMIC::MI_COMMAND_OPCODE_MI_ATOMIC == pCmd->TheStructure.Common.MiCommandOpcode ? pCmd : nullptr; } template <> MI_BATCH_BUFFER_END *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MI_BATCH_BUFFER_END::COMMAND_TYPE_MI_COMMAND == pCmd->TheStructure.Common.CommandType && MI_BATCH_BUFFER_END::MI_COMMAND_OPCODE_MI_BATCH_BUFFER_END == pCmd->TheStructure.Common.MiCommandOpcode ? pCmd : nullptr; } template <> MI_BATCH_BUFFER_START *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MI_BATCH_BUFFER_START::COMMAND_TYPE_MI_COMMAND == pCmd->TheStructure.Common.CommandType && MI_BATCH_BUFFER_START::MI_COMMAND_OPCODE_MI_BATCH_BUFFER_START == pCmd->TheStructure.Common.MiCommandOpcode ? pCmd : nullptr; } template <> MI_LOAD_REGISTER_MEM *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MI_LOAD_REGISTER_MEM::COMMAND_TYPE_MI_COMMAND == pCmd->TheStructure.Common.CommandType && MI_LOAD_REGISTER_MEM::MI_COMMAND_OPCODE_MI_LOAD_REGISTER_MEM == pCmd->TheStructure.Common.MiCommandOpcode ? pCmd : nullptr; } template <> MI_STORE_REGISTER_MEM *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MI_STORE_REGISTER_MEM::COMMAND_TYPE_MI_COMMAND == pCmd->TheStructure.Common.CommandType && MI_STORE_REGISTER_MEM::MI_COMMAND_OPCODE_MI_STORE_REGISTER_MEM == pCmd->TheStructure.Common.MiCommandOpcode ? pCmd : nullptr; } template <> MI_REPORT_PERF_COUNT *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MI_REPORT_PERF_COUNT::COMMAND_TYPE_MI_COMMAND == pCmd->TheStructure.Common.CommandType && MI_REPORT_PERF_COUNT::MI_COMMAND_OPCODE_MI_REPORT_PERF_COUNT == pCmd->TheStructure.Common.MiCommandOpcode ? pCmd : nullptr; } template <> MI_MATH *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MI_MATH::COMMAND_TYPE_MI_COMMAND == pCmd->DW0.BitField.InstructionType && MI_MATH::MI_COMMAND_OPCODE_MI_MATH == pCmd->DW0.BitField.InstructionOpcode ? pCmd : nullptr; } template <> MI_LOAD_REGISTER_REG *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return MI_LOAD_REGISTER_REG::COMMAND_TYPE_MI_COMMAND == pCmd->TheStructure.Common.CommandType && MI_LOAD_REGISTER_REG::MI_COMMAND_OPCODE_MI_LOAD_REGISTER_REG == pCmd->TheStructure.Common.MiCommandOpcode ? pCmd : nullptr; } template <> GPGPU_CSR_BASE_ADDRESS *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return GPGPU_CSR_BASE_ADDRESS::COMMAND_TYPE_GFXPIPE == pCmd->TheStructure.Common.CommandType && GPGPU_CSR_BASE_ADDRESS::COMMAND_SUBTYPE_GFXPIPE_COMMON == pCmd->TheStructure.Common.CommandSubtype && GPGPU_CSR_BASE_ADDRESS::_3D_COMMAND_OPCODE_GFXPIPE_NONPIPELINED == pCmd->TheStructure.Common._3DCommandOpcode && GPGPU_CSR_BASE_ADDRESS::_3D_COMMAND_SUB_OPCODE_GPGPU_CSR_BASE_ADDRESS == pCmd->TheStructure.Common._3DCommandSubOpcode ? pCmd : nullptr; } template <> STATE_SIP *genCmdCast(void *buffer) { auto pCmd = reinterpret_cast(buffer); return STATE_SIP::COMMAND_TYPE_GFXPIPE == pCmd->TheStructure.Common.CommandType && STATE_SIP::COMMAND_SUBTYPE_GFXPIPE_COMMON == pCmd->TheStructure.Common.CommandSubtype && STATE_SIP::_3D_COMMAND_OPCODE_GFXPIPE_NONPIPELINED == pCmd->TheStructure.Common._3DCommandOpcode && STATE_SIP::_3D_COMMAND_SUB_OPCODE_STATE_SIP == pCmd->TheStructure.Common._3DCommandSubOpcode ? pCmd : nullptr; } size_t SklParse::getCommandLength(void *cmd) { { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return SIZE32(*pCmd); } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return SIZE32(*pCmd); } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return SIZE32(*pCmd); } { auto pCmd = genCmdCast(cmd); if (pCmd) return SIZE32(*pCmd); } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->DW0.BitField.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } { auto pCmd = genCmdCast(cmd); if (pCmd) return pCmd->TheStructure.Common.DwordLength + 2; } return 0; } bool SklParse::parseCommandBuffer(GenCmdList &cmds, void *buffer, size_t length) { if (!buffer || length % sizeof(uint32_t)) { return false; } void *bufferEnd = reinterpret_cast(buffer) + length; while (buffer < bufferEnd) { size_t length = getCommandLength(buffer); if (!length) { return false; } cmds.push_back(buffer); buffer = reinterpret_cast(buffer) + length; } return buffer == bufferEnd; } // MIDL should have a MSF between it and a previous walker template <> void SklParse::validateCommand(GenCmdList::iterator itorBegin, GenCmdList::iterator itorEnd) { auto itorCurrent = itorBegin; auto itorWalker = itorEnd; // Find last GPGPU_WALKER prior to itorCmd while (itorCurrent != itorEnd) { if (genCmdCast(*itorCurrent)) { itorWalker = itorCurrent; } ++itorCurrent; } // If we don't find a GPGPU_WALKER, assume the beginning of a cmd list itorWalker = itorWalker == itorEnd ? itorBegin : itorWalker; // Look for MEDIA_STATE_FLUSH between last GPGPU_WALKER and MIDL. auto itorMSF = itorEnd; itorCurrent = itorWalker; ++itorCurrent; while (itorCurrent != itorEnd) { if (genCmdCast(*itorCurrent)) { itorMSF = itorCurrent; break; } ++itorCurrent; } ASSERT_FALSE(itorMSF == itorEnd) << "A MEDIA_STATE_FLUSH is required before a MEDIA_INTERFACE_DESCRIPTOR_LOAD."; } template <> void SklParse::validateCommand(GenCmdList::iterator itorBegin, GenCmdList::iterator itorEnd) { } // MVFES should have a stalling PC between it and a previous walker template <> void SklParse::validateCommand(GenCmdList::iterator itorBegin, GenCmdList::iterator itorEnd) { auto itorCurrent = itorBegin; auto itorWalker = itorEnd; // Find last GPGPU_WALKER prior to itorCmd while (itorCurrent != itorEnd) { if (genCmdCast(*itorCurrent)) { itorWalker = itorCurrent; } ++itorCurrent; } // If we don't find a GPGPU_WALKER, assume the beginning of a cmd list itorWalker = itorWalker == itorEnd ? itorBegin : itorWalker; // Look for PIPE_CONTROL between last GPGPU_WALKER and MVFES. itorCurrent = itorWalker; ++itorCurrent; while (itorCurrent != itorEnd) { if (genCmdCast(*itorCurrent)) { auto pPC = genCmdCast(*itorCurrent); if (pPC->getCommandStreamerStallEnable()) { return; } } ++itorCurrent; } ASSERT_TRUE(false) << "A PIPE_CONTROL w/ CS stall is required before a MEDIA_VFE_STATE."; }