From c52d4abeceffb406de043c5470ce320870b9a84a Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Sat, 17 Oct 2026 10:21:51 +0200 Subject: [PATCH] fix: emit uc tag update into epilogue stream when present When an idle immediate command list dispatches a regular command list's command buffer as the primary batch buffer, flushTaskHeapful receives that buffer as an exactly full task stream, with the immediate command stream as optionalEpilogueCmdStream. A pending UC tag update was still written into the task stream, so LinearStream::getSpace aborted. Write it into the epilogue stream instead, as the barrier with post-sync in flushTaskHeapful and the UC tag update in flushBcsTask already do. Related-To: https://github.com/intel/compute-runtime/issues/1027 Signed-off-by: Tim Besard --- .../command_stream_receiver_hw_base.inl | 8 +++- .../command_stream_receiver_tests.cpp | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/shared/source/command_stream/command_stream_receiver_hw_base.inl b/shared/source/command_stream/command_stream_receiver_hw_base.inl index f75aa22995530..ba863c358d2c1 100644 --- a/shared/source/command_stream/command_stream_receiver_hw_base.inl +++ b/shared/source/command_stream/command_stream_receiver_hw_base.inl @@ -466,8 +466,13 @@ CompletionStamp CommandStreamReceiverHw::flushTaskHeapful( if (detectInitProgrammingFlagsRequired(dispatchFlags)) { initProgrammingFlags(); } + + // a regular command list dispatched as the primary batch buffer has no space left in + // the task stream, so commands following the task go into the epilogue stream + LinearStream &epilogueCommandStream = dispatchFlags.optionalEpilogueCmdStream != nullptr ? *dispatchFlags.optionalEpilogueCmdStream : commandStreamTask; + if (this->ucResourceRequiresTagUpdate) { - this->emitTagUpdateWithoutDCFlush(commandStreamTask); + this->emitTagUpdateWithoutDCFlush(epilogueCommandStream); } const auto &hwInfo = peekHwInfo(); @@ -478,7 +483,6 @@ CompletionStamp CommandStreamReceiverHw::flushTaskHeapful( dispatchFlags.textureCacheFlush || this->heapStorageRequiresRecyclingTag; if (barrierWithPostSyncNeeded) { - LinearStream &epilogueCommandStream = dispatchFlags.optionalEpilogueCmdStream != nullptr ? *dispatchFlags.optionalEpilogueCmdStream : commandStreamTask; processBarrierWithPostSync(epilogueCommandStream, dispatchFlags, levelClosed, currentPipeControlForNooping, epiloguePipeControlLocation, hasStallingCmdsOnTaskStream, args); } diff --git a/shared/test/unit_test/command_stream/command_stream_receiver_tests.cpp b/shared/test/unit_test/command_stream/command_stream_receiver_tests.cpp index 3b4c0714545e6..d1288715c7b56 100644 --- a/shared/test/unit_test/command_stream/command_stream_receiver_tests.cpp +++ b/shared/test/unit_test/command_stream/command_stream_receiver_tests.cpp @@ -6473,6 +6473,51 @@ HWTEST_F(CommandStreamReceiverHwTest, givenEpilogueStreamAvailableWhenFlushTaskC commandStreamReceiver.getMemoryManager()->freeGraphicsMemoryImpl(commandBuffer); } +HWTEST_F(CommandStreamReceiverHwTest, givenUcResourceRequiresTagUpdateAndFullTaskStreamWithEpilogueStreamWhenFlushTaskCalledThenTagUpdateIsDispatchedIntoEpilogueStream) { + using PIPE_CONTROL = typename FamilyType::PIPE_CONTROL; + + auto &commandStreamReceiver = pDevice->getUltCommandStreamReceiver(); + if (commandStreamReceiver.heaplessModeEnabled) { + GTEST_SKIP(); + } + + GraphicsAllocation *commandBuffer = commandStreamReceiver.getMemoryManager()->allocateGraphicsMemoryWithProperties(MockAllocationProperties{commandStreamReceiver.getRootDeviceIndex(), MemoryConstants::pageSize}); + ASSERT_NE(nullptr, commandBuffer); + LinearStream epilogueStream(commandBuffer); + + flushTaskFlags.optionalEpilogueCmdStream = &epilogueStream; + commandStreamReceiver.ucResourceRequiresTagUpdate = true; + + // a regular command list dispatched as the primary batch buffer fills the task stream + commandStream.getSpace(commandStream.getAvailableSpace()); + + EXPECT_NO_THROW(commandStreamReceiver.flushTask(commandStream, + 0, + &dsh, + &ioh, + nullptr, + taskLevel, + flushTaskFlags, + *pDevice)); + EXPECT_EQ(commandStream.getMaxAvailableSpace(), commandStream.getUsed()); + EXPECT_FALSE(commandStreamReceiver.ucResourceRequiresTagUpdate); + + HardwareParse hwParser; + hwParser.parseCommands(epilogueStream, 0); + auto ucTagAddress = commandStreamReceiver.getUcTagGPUAddress(); + bool ucTagUpdateFound = false; + for (auto &cmd : findAll(hwParser.cmdList.begin(), hwParser.cmdList.end())) { + auto pipeControl = genCmdCast(*cmd); + uint64_t address = pipeControl->getAddressHigh(); + address <<= 32; + address |= pipeControl->getAddress(); + ucTagUpdateFound |= (address == ucTagAddress); + } + EXPECT_TRUE(ucTagUpdateFound); + + commandStreamReceiver.getMemoryManager()->freeGraphicsMemoryImpl(commandBuffer); +} + HWTEST2_F(CommandStreamReceiverHwTest, givenSpecialPipelineSelectModeChangedWhenGetCmdSizeForPielineSelectIsCalledThenCorrectSizeIsReturned, IsAtMostXeCore) { using PIPELINE_SELECT = typename FamilyType::PIPELINE_SELECT; using PIPE_CONTROL = typename FamilyType::PIPE_CONTROL;