1 /*
2  * Copyright (C) 2019-2021 Intel Corporation
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  */
7 
8 #include "shared/source/command_container/cmdcontainer.h"
9 #include "shared/source/memory_manager/allocations_list.h"
10 #include "shared/test/common/fixtures/device_fixture.h"
11 #include "shared/test/common/helpers/debug_manager_state_restore.h"
12 #include "shared/test/common/mocks/mock_graphics_allocation.h"
13 #include "shared/test/common/mocks/mock_memory_manager.h"
14 #include "shared/test/common/test_macros/test.h"
15 
16 using namespace NEO;
17 
18 constexpr uint32_t defaultNumIddsPerBlock = 64;
19 
20 class CommandContainerTest : public DeviceFixture,
21                              public ::testing::Test {
22 
23   public:
SetUp()24     void SetUp() override {
25         ::testing::Test::SetUp();
26         DeviceFixture::SetUp();
27     }
TearDown()28     void TearDown() override {
29         DeviceFixture::TearDown();
30         ::testing::Test::TearDown();
31     }
32 };
33 
34 struct CommandContainerHeapStateTests : public ::testing::Test {
35     class MyMockCommandContainer : public CommandContainer {
36       public:
37         using CommandContainer::dirtyHeaps;
38     };
39 
40     MyMockCommandContainer myCommandContainer;
41 };
42 
TEST_F(CommandContainerHeapStateTests,givenDirtyHeapsWhenSettingStateForAllThenValuesAreCorrect)43 TEST_F(CommandContainerHeapStateTests, givenDirtyHeapsWhenSettingStateForAllThenValuesAreCorrect) {
44     EXPECT_EQ(std::numeric_limits<uint32_t>::max(), myCommandContainer.dirtyHeaps);
45     EXPECT_TRUE(myCommandContainer.isAnyHeapDirty());
46 
47     myCommandContainer.setDirtyStateForAllHeaps(false);
48     EXPECT_EQ(0u, myCommandContainer.dirtyHeaps);
49     EXPECT_FALSE(myCommandContainer.isAnyHeapDirty());
50 
51     for (uint32_t i = 0; i < HeapType::NUM_TYPES; i++) {
52         HeapType heapType = static_cast<HeapType>(i);
53         EXPECT_FALSE(myCommandContainer.isHeapDirty(heapType));
54     }
55 
56     myCommandContainer.setDirtyStateForAllHeaps(true);
57     EXPECT_EQ(std::numeric_limits<uint32_t>::max(), myCommandContainer.dirtyHeaps);
58 
59     for (uint32_t i = 0; i < HeapType::NUM_TYPES; i++) {
60         HeapType heapType = static_cast<HeapType>(i);
61         EXPECT_TRUE(myCommandContainer.isHeapDirty(heapType));
62     }
63 }
64 
TEST_F(CommandContainerHeapStateTests,givenDirtyHeapsWhenSettingStateForSingleHeapThenValuesAreCorrect)65 TEST_F(CommandContainerHeapStateTests, givenDirtyHeapsWhenSettingStateForSingleHeapThenValuesAreCorrect) {
66     myCommandContainer.dirtyHeaps = 0;
67     EXPECT_FALSE(myCommandContainer.isAnyHeapDirty());
68 
69     uint32_t controlVariable = 0;
70     for (uint32_t i = 0; i < HeapType::NUM_TYPES; i++) {
71         HeapType heapType = static_cast<HeapType>(i);
72 
73         EXPECT_FALSE(myCommandContainer.isHeapDirty(heapType));
74         myCommandContainer.setHeapDirty(heapType);
75         EXPECT_TRUE(myCommandContainer.isHeapDirty(heapType));
76         EXPECT_TRUE(myCommandContainer.isAnyHeapDirty());
77 
78         controlVariable |= (1 << i);
79         EXPECT_EQ(controlVariable, myCommandContainer.dirtyHeaps);
80     }
81 
82     for (uint32_t i = 0; i < HeapType::NUM_TYPES; i++) {
83         HeapType heapType = static_cast<HeapType>(i);
84         EXPECT_TRUE(myCommandContainer.isHeapDirty(heapType));
85     }
86 }
87 
TEST_F(CommandContainerTest,givenCmdContainerWhenCreatingCommandBufferThenCorrectAllocationTypeIsSet)88 TEST_F(CommandContainerTest, givenCmdContainerWhenCreatingCommandBufferThenCorrectAllocationTypeIsSet) {
89     CommandContainer cmdContainer;
90     cmdContainer.initialize(pDevice, nullptr);
91 
92     ASSERT_NE(0u, cmdContainer.getCmdBufferAllocations().size());
93     EXPECT_EQ(GraphicsAllocation::AllocationType::COMMAND_BUFFER, cmdContainer.getCmdBufferAllocations()[0]->getAllocationType());
94 
95     cmdContainer.allocateNextCommandBuffer();
96 
97     ASSERT_LE(2u, cmdContainer.getCmdBufferAllocations().size());
98     EXPECT_EQ(GraphicsAllocation::AllocationType::COMMAND_BUFFER, cmdContainer.getCmdBufferAllocations()[1]->getAllocationType());
99 }
100 
TEST_F(CommandContainerTest,givenCmdContainerWhenAllocatingHeapsThenSetCorrectAllocationTypes)101 TEST_F(CommandContainerTest, givenCmdContainerWhenAllocatingHeapsThenSetCorrectAllocationTypes) {
102     CommandContainer cmdContainer;
103     cmdContainer.initialize(pDevice, nullptr);
104 
105     for (uint32_t i = 0; i < HeapType::NUM_TYPES; i++) {
106         HeapType heapType = static_cast<HeapType>(i);
107         auto heap = cmdContainer.getIndirectHeap(heapType);
108 
109         if (HeapType::INDIRECT_OBJECT == heapType) {
110             EXPECT_EQ(GraphicsAllocation::AllocationType::INTERNAL_HEAP, heap->getGraphicsAllocation()->getAllocationType());
111             EXPECT_NE(0u, heap->getHeapGpuStartOffset());
112         } else {
113             EXPECT_EQ(GraphicsAllocation::AllocationType::LINEAR_STREAM, heap->getGraphicsAllocation()->getAllocationType());
114             EXPECT_EQ(0u, heap->getHeapGpuStartOffset());
115         }
116     }
117 }
118 
TEST_F(CommandContainerTest,givenCommandContainerWhenInitializeThenEverythingIsInitialized)119 TEST_F(CommandContainerTest, givenCommandContainerWhenInitializeThenEverythingIsInitialized) {
120     CommandContainer cmdContainer;
121     auto status = cmdContainer.initialize(pDevice, nullptr);
122     EXPECT_EQ(ErrorCode::SUCCESS, status);
123 
124     EXPECT_EQ(pDevice, cmdContainer.getDevice());
125     EXPECT_NE(cmdContainer.getHeapHelper(), nullptr);
126     EXPECT_EQ(cmdContainer.getCmdBufferAllocations().size(), 1u);
127     EXPECT_NE(cmdContainer.getCommandStream(), nullptr);
128 
129     for (uint32_t i = 0; i < HeapType::NUM_TYPES; i++) {
130         auto indirectHeap = cmdContainer.getIndirectHeap(static_cast<HeapType>(i));
131         auto heapAllocation = cmdContainer.getIndirectHeapAllocation(static_cast<HeapType>(i));
132         EXPECT_EQ(indirectHeap->getGraphicsAllocation(), heapAllocation);
133     }
134 
135     EXPECT_EQ(cmdContainer.getIddBlock(), nullptr);
136     EXPECT_EQ(cmdContainer.getNumIddPerBlock(), defaultNumIddsPerBlock);
137 
138     auto &hwHelper = HwHelper::get(pDevice->getHardwareInfo().platform.eRenderCoreFamily);
139 
140     EXPECT_EQ(cmdContainer.getInstructionHeapBaseAddress(),
141               pDevice->getMemoryManager()->getInternalHeapBaseAddress(0, !hwHelper.useSystemMemoryPlacementForISA(pDevice->getHardwareInfo())));
142 }
143 
TEST_F(CommandContainerTest,givenEnabledLocalMemoryAndIsaInSystemMemoryWhenCmdContainerIsInitializedThenInstructionBaseAddressIsSetToInternalHeap)144 TEST_F(CommandContainerTest, givenEnabledLocalMemoryAndIsaInSystemMemoryWhenCmdContainerIsInitializedThenInstructionBaseAddressIsSetToInternalHeap) {
145     DebugManagerStateRestore dbgRestore;
146     DebugManager.flags.ForceSystemMemoryPlacement.set(1 << (static_cast<uint32_t>(GraphicsAllocation::AllocationType::KERNEL_ISA) - 1));
147 
148     auto executionEnvironment = new NEO::ExecutionEnvironment();
149     const size_t numDevices = 1;
150     executionEnvironment->prepareRootDeviceEnvironments(numDevices);
151     executionEnvironment->rootDeviceEnvironments[0]->setHwInfo(defaultHwInfo.get());
152 
153     auto hwInfo = executionEnvironment->rootDeviceEnvironments[0]->getMutableHardwareInfo();
154     hwInfo->featureTable.flags.ftrLocalMemory = true;
155 
156     auto device = std::unique_ptr<MockDevice>(Device::create<MockDevice>(executionEnvironment, 0u));
157 
158     auto instructionHeapBaseAddress = device->getMemoryManager()->getInternalHeapBaseAddress(0, false);
159 
160     CommandContainer cmdContainer;
161     auto status = cmdContainer.initialize(device.get(), nullptr);
162     EXPECT_EQ(ErrorCode::SUCCESS, status);
163 
164     EXPECT_EQ(instructionHeapBaseAddress, cmdContainer.getInstructionHeapBaseAddress());
165 }
166 
TEST_F(CommandContainerTest,givenCommandContainerDuringInitWhenAllocateGfxMemoryFailsThenErrorIsReturned)167 TEST_F(CommandContainerTest, givenCommandContainerDuringInitWhenAllocateGfxMemoryFailsThenErrorIsReturned) {
168     CommandContainer cmdContainer;
169     pDevice->executionEnvironment->memoryManager.reset(new FailMemoryManager(0, *pDevice->executionEnvironment));
170     auto status = cmdContainer.initialize(pDevice, nullptr);
171     EXPECT_EQ(ErrorCode::OUT_OF_DEVICE_MEMORY, status);
172 }
173 
TEST_F(CommandContainerTest,givenCmdContainerWithAllocsListWhenAllocateAndResetThenCmdBufferAllocIsReused)174 TEST_F(CommandContainerTest, givenCmdContainerWithAllocsListWhenAllocateAndResetThenCmdBufferAllocIsReused) {
175     AllocationsList allocList;
176     auto cmdContainer = std::make_unique<CommandContainer>();
177     cmdContainer->initialize(pDevice, &allocList);
178     auto &cmdBufferAllocs = cmdContainer->getCmdBufferAllocations();
179     auto memoryManager = static_cast<MockMemoryManager *>(pDevice->getMemoryManager());
180     EXPECT_EQ(memoryManager->handleFenceCompletionCalled, 0u);
181     EXPECT_EQ(cmdBufferAllocs.size(), 1u);
182     EXPECT_TRUE(allocList.peekIsEmpty());
183 
184     cmdContainer->allocateNextCommandBuffer();
185     EXPECT_EQ(cmdBufferAllocs.size(), 2u);
186 
187     auto cmdBuffer0 = cmdBufferAllocs[0];
188     auto cmdBuffer1 = cmdBufferAllocs[1];
189 
190     cmdContainer->reset();
191     EXPECT_EQ(memoryManager->handleFenceCompletionCalled, 1u);
192     EXPECT_EQ(cmdBufferAllocs.size(), 1u);
193     EXPECT_EQ(cmdBufferAllocs[0], cmdBuffer0);
194     EXPECT_FALSE(allocList.peekIsEmpty());
195 
196     cmdContainer->allocateNextCommandBuffer();
197     EXPECT_EQ(cmdBufferAllocs.size(), 2u);
198     EXPECT_EQ(cmdBufferAllocs[0], cmdBuffer0);
199     EXPECT_EQ(cmdBufferAllocs[1], cmdBuffer1);
200     EXPECT_TRUE(allocList.peekIsEmpty());
201 
202     cmdContainer.reset();
203     EXPECT_EQ(memoryManager->handleFenceCompletionCalled, 3u);
204     EXPECT_FALSE(allocList.peekIsEmpty());
205     allocList.freeAllGraphicsAllocations(pDevice);
206 }
207 
TEST_F(CommandContainerTest,givenCommandContainerDuringInitWhenAllocateHeapMemoryFailsThenErrorIsReturned)208 TEST_F(CommandContainerTest, givenCommandContainerDuringInitWhenAllocateHeapMemoryFailsThenErrorIsReturned) {
209     CommandContainer cmdContainer;
210     auto temp_memoryManager = pDevice->executionEnvironment->memoryManager.release();
211     pDevice->executionEnvironment->memoryManager.reset(new FailMemoryManager(1, *pDevice->executionEnvironment));
212     auto status = cmdContainer.initialize(pDevice, nullptr);
213     EXPECT_EQ(ErrorCode::OUT_OF_DEVICE_MEMORY, status);
214     delete temp_memoryManager;
215 }
216 
TEST_F(CommandContainerTest,givenCommandContainerWhenSettingIndirectHeapAllocationThenAllocationIsSet)217 TEST_F(CommandContainerTest, givenCommandContainerWhenSettingIndirectHeapAllocationThenAllocationIsSet) {
218     CommandContainer cmdContainer;
219     MockGraphicsAllocation mockAllocation;
220     auto heapType = HeapType::DYNAMIC_STATE;
221     cmdContainer.setIndirectHeapAllocation(heapType, &mockAllocation);
222     EXPECT_EQ(cmdContainer.getIndirectHeapAllocation(heapType), &mockAllocation);
223 }
224 
TEST_F(CommandContainerTest,givenHeapAllocationsWhenDestroyCommandContainerThenHeapAllocationsAreReused)225 TEST_F(CommandContainerTest, givenHeapAllocationsWhenDestroyCommandContainerThenHeapAllocationsAreReused) {
226     std::unique_ptr<CommandContainer> cmdContainer(new CommandContainer);
227     cmdContainer->initialize(pDevice, nullptr);
228     auto heapAllocationsAddress = cmdContainer->getIndirectHeapAllocation(HeapType::DYNAMIC_STATE)->getUnderlyingBuffer();
229     cmdContainer.reset(new CommandContainer);
230     cmdContainer->initialize(pDevice, nullptr);
231     bool status = false;
232     for (uint32_t i = 0; i < HeapType::NUM_TYPES && !status; i++) {
233         status = cmdContainer->getIndirectHeapAllocation(static_cast<HeapType>(i))->getUnderlyingBuffer() == heapAllocationsAddress;
234     }
235     EXPECT_TRUE(status);
236 }
237 
TEST_F(CommandContainerTest,givenCommandContainerWhenResetThenStateIsReset)238 TEST_F(CommandContainerTest, givenCommandContainerWhenResetThenStateIsReset) {
239     CommandContainer cmdContainer;
240     cmdContainer.initialize(pDevice, nullptr);
241     LinearStream stream;
242     uint32_t usedSize = 1;
243     cmdContainer.lastSentNumGrfRequired = 64;
244     cmdContainer.getCommandStream()->getSpace(usedSize);
245     EXPECT_EQ(usedSize, cmdContainer.getCommandStream()->getUsed());
246     cmdContainer.reset();
247     EXPECT_NE(usedSize, cmdContainer.getCommandStream()->getUsed());
248     EXPECT_EQ(0u, cmdContainer.getCommandStream()->getUsed());
249     EXPECT_EQ(0u, cmdContainer.lastSentNumGrfRequired);
250     EXPECT_EQ(cmdContainer.getIddBlock(), nullptr);
251     EXPECT_EQ(cmdContainer.getNumIddPerBlock(), defaultNumIddsPerBlock);
252 }
253 
TEST_F(CommandContainerTest,givenCommandContainerWhenWantToAddNullPtrToResidencyContainerThenNothingIsAdded)254 TEST_F(CommandContainerTest, givenCommandContainerWhenWantToAddNullPtrToResidencyContainerThenNothingIsAdded) {
255     CommandContainer cmdContainer;
256     cmdContainer.initialize(pDevice, nullptr);
257     auto size = cmdContainer.getResidencyContainer().size();
258     cmdContainer.addToResidencyContainer(nullptr);
259     EXPECT_EQ(cmdContainer.getResidencyContainer().size(), size);
260 }
261 
TEST_F(CommandContainerTest,givenCommandContainerWhenWantToAddAlreadyAddedAllocationAndDuplicatesRemovedThenExpectedSizeIsReturned)262 TEST_F(CommandContainerTest, givenCommandContainerWhenWantToAddAlreadyAddedAllocationAndDuplicatesRemovedThenExpectedSizeIsReturned) {
263     CommandContainer cmdContainer;
264     cmdContainer.initialize(pDevice, nullptr);
265     MockGraphicsAllocation mockAllocation;
266 
267     auto sizeBefore = cmdContainer.getResidencyContainer().size();
268 
269     cmdContainer.addToResidencyContainer(&mockAllocation);
270     auto sizeAfterFirstAdd = cmdContainer.getResidencyContainer().size();
271 
272     EXPECT_NE(sizeBefore, sizeAfterFirstAdd);
273 
274     cmdContainer.addToResidencyContainer(&mockAllocation);
275     auto sizeAfterSecondAdd = cmdContainer.getResidencyContainer().size();
276 
277     EXPECT_NE(sizeAfterFirstAdd, sizeAfterSecondAdd);
278 
279     cmdContainer.removeDuplicatesFromResidencyContainer();
280     auto sizeAfterDuplicatesRemoved = cmdContainer.getResidencyContainer().size();
281 
282     EXPECT_EQ(sizeAfterFirstAdd, sizeAfterDuplicatesRemoved);
283 }
284 
HWTEST_F(CommandContainerTest,givenCmdContainerWhenInitializeCalledThenSSHHeapHasBindlessOffsetReserved)285 HWTEST_F(CommandContainerTest, givenCmdContainerWhenInitializeCalledThenSSHHeapHasBindlessOffsetReserved) {
286     using RENDER_SURFACE_STATE = typename FamilyType::RENDER_SURFACE_STATE;
287     std::unique_ptr<CommandContainer> cmdContainer(new CommandContainer);
288     cmdContainer->setReservedSshSize(4 * MemoryConstants::pageSize);
289     cmdContainer->initialize(pDevice, nullptr);
290     cmdContainer->setDirtyStateForAllHeaps(false);
291 
292     auto heap = cmdContainer->getIndirectHeap(HeapType::SURFACE_STATE);
293 
294     ASSERT_NE(nullptr, heap);
295     EXPECT_EQ(4 * MemoryConstants::pageSize, heap->getUsed());
296 }
297 
HWTEST_F(CommandContainerTest,givenNotEnoughSpaceInSSHWhenGettingHeapWithRequiredSizeAndAlignmentThenSSHHeapHasBindlessOffsetReserved)298 HWTEST_F(CommandContainerTest, givenNotEnoughSpaceInSSHWhenGettingHeapWithRequiredSizeAndAlignmentThenSSHHeapHasBindlessOffsetReserved) {
299     using RENDER_SURFACE_STATE = typename FamilyType::RENDER_SURFACE_STATE;
300     std::unique_ptr<CommandContainer> cmdContainer(new CommandContainer);
301     cmdContainer->setReservedSshSize(4 * MemoryConstants::pageSize);
302     cmdContainer->initialize(pDevice, nullptr);
303     cmdContainer->setDirtyStateForAllHeaps(false);
304 
305     auto heap = cmdContainer->getIndirectHeap(HeapType::SURFACE_STATE);
306     ASSERT_NE(nullptr, heap);
307     heap->getSpace(heap->getAvailableSpace());
308 
309     cmdContainer->getHeapWithRequiredSizeAndAlignment(HeapType::SURFACE_STATE, sizeof(RENDER_SURFACE_STATE), 0);
310 
311     EXPECT_EQ(4 * MemoryConstants::pageSize, heap->getUsed());
312     EXPECT_EQ(cmdContainer->sshAllocations.size(), 1u);
313 }
314 
TEST_F(CommandContainerTest,givenAvailableSpaceWhenGetHeapWithRequiredSizeAndAlignmentCalledThenExistingAllocationIsReturned)315 TEST_F(CommandContainerTest, givenAvailableSpaceWhenGetHeapWithRequiredSizeAndAlignmentCalledThenExistingAllocationIsReturned) {
316     std::unique_ptr<CommandContainer> cmdContainer(new CommandContainer);
317     cmdContainer->initialize(pDevice, nullptr);
318     cmdContainer->setDirtyStateForAllHeaps(false);
319     HeapType types[] = {HeapType::SURFACE_STATE,
320                         HeapType::DYNAMIC_STATE};
321 
322     for (auto type : types) {
323         auto heapAllocation = cmdContainer->getIndirectHeapAllocation(type);
324         auto heap = cmdContainer->getIndirectHeap(type);
325 
326         const size_t sizeRequested = 32;
327         const size_t alignment = 32;
328 
329         EXPECT_GE(heap->getAvailableSpace(), sizeRequested + alignment);
330         auto sizeBefore = heap->getUsed();
331 
332         auto heapRequested = cmdContainer->getHeapWithRequiredSizeAndAlignment(type, sizeRequested, alignment);
333         auto newAllocation = heapRequested->getGraphicsAllocation();
334 
335         EXPECT_EQ(heap, heapRequested);
336         EXPECT_EQ(heapAllocation, newAllocation);
337 
338         EXPECT_TRUE((reinterpret_cast<size_t>(heapRequested->getSpace(0)) & (alignment - 1)) == 0);
339         EXPECT_FALSE(cmdContainer->isHeapDirty(type));
340 
341         auto sizeAfter = heapRequested->getUsed();
342         EXPECT_EQ(sizeBefore, sizeAfter);
343     }
344 }
345 
TEST_F(CommandContainerTest,givenUnalignedAvailableSpaceWhenGetHeapWithRequiredSizeAndAlignmentCalledThenHeapReturnedIsCorrectlyAligned)346 TEST_F(CommandContainerTest, givenUnalignedAvailableSpaceWhenGetHeapWithRequiredSizeAndAlignmentCalledThenHeapReturnedIsCorrectlyAligned) {
347     std::unique_ptr<CommandContainer> cmdContainer(new CommandContainer);
348     cmdContainer->initialize(pDevice, nullptr);
349     cmdContainer->setDirtyStateForAllHeaps(false);
350     auto heapAllocation = cmdContainer->getIndirectHeapAllocation(HeapType::SURFACE_STATE);
351     auto heap = cmdContainer->getIndirectHeap(HeapType::SURFACE_STATE);
352 
353     const size_t sizeRequested = 32;
354     const size_t alignment = 32;
355 
356     heap->getSpace(sizeRequested / 2);
357 
358     EXPECT_GE(heap->getAvailableSpace(), sizeRequested + alignment);
359 
360     auto heapRequested = cmdContainer->getHeapWithRequiredSizeAndAlignment(HeapType::SURFACE_STATE, sizeRequested, alignment);
361     auto newAllocation = heapRequested->getGraphicsAllocation();
362 
363     EXPECT_EQ(heap, heapRequested);
364     EXPECT_EQ(heapAllocation, newAllocation);
365 
366     EXPECT_TRUE((reinterpret_cast<size_t>(heapRequested->getSpace(0)) & (alignment - 1)) == 0);
367     EXPECT_FALSE(cmdContainer->isHeapDirty(HeapType::SURFACE_STATE));
368 }
369 
TEST_F(CommandContainerTest,givenNoAlignmentAndAvailableSpaceWhenGetHeapWithRequiredSizeAndAlignmentCalledThenHeapReturnedIsNotAligned)370 TEST_F(CommandContainerTest, givenNoAlignmentAndAvailableSpaceWhenGetHeapWithRequiredSizeAndAlignmentCalledThenHeapReturnedIsNotAligned) {
371     std::unique_ptr<CommandContainer> cmdContainer(new CommandContainer);
372     cmdContainer->initialize(pDevice, nullptr);
373     cmdContainer->setDirtyStateForAllHeaps(false);
374     auto heapAllocation = cmdContainer->getIndirectHeapAllocation(HeapType::SURFACE_STATE);
375     auto heap = cmdContainer->getIndirectHeap(HeapType::SURFACE_STATE);
376 
377     const size_t sizeRequested = 32;
378     const size_t alignment = 0;
379 
380     heap->getSpace(sizeRequested / 2);
381 
382     EXPECT_GE(heap->getAvailableSpace(), sizeRequested + alignment);
383 
384     auto heapRequested = cmdContainer->getHeapWithRequiredSizeAndAlignment(HeapType::SURFACE_STATE, sizeRequested, alignment);
385     auto newAllocation = heapRequested->getGraphicsAllocation();
386 
387     EXPECT_EQ(heap, heapRequested);
388     EXPECT_EQ(heapAllocation, newAllocation);
389 
390     EXPECT_TRUE((reinterpret_cast<size_t>(heapRequested->getSpace(0)) & (sizeRequested / 2)) == sizeRequested / 2);
391     EXPECT_FALSE(cmdContainer->isHeapDirty(HeapType::SURFACE_STATE));
392 }
393 
TEST_F(CommandContainerTest,givenNotEnoughSpaceWhenGetHeapWithRequiredSizeAndAlignmentCalledThenNewAllocationIsReturned)394 TEST_F(CommandContainerTest, givenNotEnoughSpaceWhenGetHeapWithRequiredSizeAndAlignmentCalledThenNewAllocationIsReturned) {
395     std::unique_ptr<CommandContainer> cmdContainer(new CommandContainer);
396     cmdContainer->initialize(pDevice, nullptr);
397     cmdContainer->setDirtyStateForAllHeaps(false);
398     HeapType types[] = {HeapType::SURFACE_STATE,
399                         HeapType::DYNAMIC_STATE};
400 
401     for (auto type : types) {
402         auto heapAllocation = cmdContainer->getIndirectHeapAllocation(type);
403         auto heap = cmdContainer->getIndirectHeap(type);
404 
405         const size_t sizeRequested = 32;
406         const size_t alignment = 32;
407         size_t availableSize = heap->getAvailableSpace();
408 
409         heap->getSpace(availableSize - sizeRequested / 2);
410 
411         EXPECT_LT(heap->getAvailableSpace(), sizeRequested + alignment);
412 
413         auto heapRequested = cmdContainer->getHeapWithRequiredSizeAndAlignment(type, sizeRequested, alignment);
414         auto newAllocation = heapRequested->getGraphicsAllocation();
415 
416         EXPECT_EQ(heap, heapRequested);
417         EXPECT_NE(heapAllocation, newAllocation);
418 
419         EXPECT_TRUE((reinterpret_cast<size_t>(heapRequested->getSpace(0)) & (alignment - 1)) == 0);
420         EXPECT_TRUE(cmdContainer->isHeapDirty(type));
421     }
422     for (auto deallocation : cmdContainer->getDeallocationContainer()) {
423         cmdContainer->getDevice()->getMemoryManager()->freeGraphicsMemory(deallocation);
424     }
425     cmdContainer->getDeallocationContainer().clear();
426 }
427 
TEST_F(CommandContainerTest,givenNotEnoughSpaceWhenCreatedAlocationHaveDifferentBaseThenHeapIsDirty)428 TEST_F(CommandContainerTest, givenNotEnoughSpaceWhenCreatedAlocationHaveDifferentBaseThenHeapIsDirty) {
429     std::unique_ptr<CommandContainer> cmdContainer(new CommandContainer);
430     cmdContainer->initialize(pDevice, nullptr);
431     cmdContainer->setDirtyStateForAllHeaps(false);
432     HeapType type = HeapType::INDIRECT_OBJECT;
433 
434     auto heapAllocation = cmdContainer->getIndirectHeapAllocation(type);
435     auto heap = cmdContainer->getIndirectHeap(type);
436 
437     const size_t sizeRequested = 32;
438     const size_t alignment = 32;
439     size_t availableSize = heap->getAvailableSpace();
440 
441     heap->getSpace(availableSize - sizeRequested / 2);
442 
443     EXPECT_LT(heap->getAvailableSpace(), sizeRequested + alignment);
444 
445     auto heapRequested = cmdContainer->getHeapWithRequiredSizeAndAlignment(type, sizeRequested, alignment);
446     auto newAllocation = heapRequested->getGraphicsAllocation();
447 
448     EXPECT_EQ(heap, heapRequested);
449     EXPECT_NE(heapAllocation, newAllocation);
450 
451     EXPECT_TRUE((reinterpret_cast<size_t>(heapRequested->getSpace(0)) & (alignment - 1)) == 0);
452     EXPECT_FALSE(cmdContainer->isHeapDirty(type));
453 
454     for (auto deallocation : cmdContainer->getDeallocationContainer()) {
455         cmdContainer->getDevice()->getMemoryManager()->freeGraphicsMemory(deallocation);
456     }
457     cmdContainer->getDeallocationContainer().clear();
458 }
459 
TEST_F(CommandContainerTest,whenAllocateNextCmdBufferIsCalledThenNewAllocationIsCreatedAndCommandStreamReplaced)460 TEST_F(CommandContainerTest, whenAllocateNextCmdBufferIsCalledThenNewAllocationIsCreatedAndCommandStreamReplaced) {
461     std::unique_ptr<CommandContainer> cmdContainer(new CommandContainer);
462     cmdContainer->initialize(pDevice, nullptr);
463     auto stream = cmdContainer->getCommandStream();
464     ASSERT_NE(nullptr, stream);
465 
466     auto initialBuffer = stream->getSpace(0);
467     EXPECT_NE(nullptr, initialBuffer);
468 
469     cmdContainer->allocateNextCommandBuffer();
470 
471     auto nextBuffer = stream->getSpace(0);
472     auto sizeUsed = stream->getUsed();
473     auto availableSize = stream->getMaxAvailableSpace();
474 
475     EXPECT_NE(nullptr, nextBuffer);
476     EXPECT_EQ(0u, sizeUsed);
477     EXPECT_NE(initialBuffer, nextBuffer);
478     const size_t cmdBufSize = CommandContainer::defaultListCmdBufferSize;
479     EXPECT_EQ(cmdBufSize, availableSize);
480 
481     ASSERT_EQ(2u, cmdContainer->getCmdBufferAllocations().size());
482     EXPECT_EQ(cmdContainer->getCmdBufferAllocations()[1], cmdContainer->getCommandStream()->getGraphicsAllocation());
483 
484     EXPECT_EQ(cmdContainer->getCmdBufferAllocations()[1], cmdContainer->getResidencyContainer().back());
485 }
486 
TEST_F(CommandContainerTest,whenResettingCommandContainerThenStoredCmdBuffersAreFreedAndStreamIsReplacedWithInitialBuffer)487 TEST_F(CommandContainerTest, whenResettingCommandContainerThenStoredCmdBuffersAreFreedAndStreamIsReplacedWithInitialBuffer) {
488     std::unique_ptr<CommandContainer> cmdContainer(new CommandContainer);
489     cmdContainer->initialize(pDevice, nullptr);
490 
491     cmdContainer->allocateNextCommandBuffer();
492     cmdContainer->allocateNextCommandBuffer();
493 
494     EXPECT_EQ(3u, cmdContainer->getCmdBufferAllocations().size());
495 
496     cmdContainer->reset();
497 
498     ASSERT_EQ(1u, cmdContainer->getCmdBufferAllocations().size());
499 
500     auto stream = cmdContainer->getCommandStream();
501     ASSERT_NE(nullptr, stream);
502 
503     auto buffer = stream->getSpace(0);
504     const size_t cmdBufSize = CommandContainer::defaultListCmdBufferSize;
505 
506     EXPECT_EQ(cmdContainer->getCmdBufferAllocations()[0]->getUnderlyingBuffer(), buffer);
507     EXPECT_EQ(cmdBufSize, stream->getMaxAvailableSpace());
508 }
509 
510 class CommandContainerHeaps : public DeviceFixture,
511                               public ::testing::TestWithParam<IndirectHeap::Type> {
512   public:
SetUp()513     void SetUp() override {
514         DeviceFixture::SetUp();
515     }
516 
TearDown()517     void TearDown() override {
518         DeviceFixture::TearDown();
519     }
520 };
521 
522 INSTANTIATE_TEST_CASE_P(
523     Device,
524     CommandContainerHeaps,
525     testing::Values(
526         IndirectHeap::DYNAMIC_STATE,
527         IndirectHeap::INDIRECT_OBJECT,
528         IndirectHeap::SURFACE_STATE));
529 
TEST_P(CommandContainerHeaps,givenCommandContainerWhenGetAllowHeapGrowCalledThenHeapIsReturned)530 TEST_P(CommandContainerHeaps, givenCommandContainerWhenGetAllowHeapGrowCalledThenHeapIsReturned) {
531     HeapType heap = GetParam();
532 
533     CommandContainer cmdContainer;
534     cmdContainer.initialize(pDevice, nullptr);
535     auto usedSpaceBefore = cmdContainer.getIndirectHeap(heap)->getUsed();
536     size_t size = 5000;
537     void *ptr = cmdContainer.getHeapSpaceAllowGrow(heap, size);
538     ASSERT_NE(nullptr, ptr);
539 
540     auto usedSpaceAfter = cmdContainer.getIndirectHeap(heap)->getUsed();
541     ASSERT_EQ(usedSpaceBefore + size, usedSpaceAfter);
542 }
543 
TEST_P(CommandContainerHeaps,givenCommandContainerWhenGetingMoreThanAvailableSizeThenBiggerHeapIsReturned)544 TEST_P(CommandContainerHeaps, givenCommandContainerWhenGetingMoreThanAvailableSizeThenBiggerHeapIsReturned) {
545     HeapType heap = GetParam();
546 
547     CommandContainer cmdContainer;
548     cmdContainer.initialize(pDevice, nullptr);
549     cmdContainer.setDirtyStateForAllHeaps(false);
550 
551     auto usedSpaceBefore = cmdContainer.getIndirectHeap(heap)->getUsed();
552     auto availableSizeBefore = cmdContainer.getIndirectHeap(heap)->getAvailableSpace();
553 
554     void *ptr = cmdContainer.getHeapSpaceAllowGrow(heap, availableSizeBefore + 1);
555     ASSERT_NE(nullptr, ptr);
556 
557     auto usedSpaceAfter = cmdContainer.getIndirectHeap(heap)->getUsed();
558     auto availableSizeAfter = cmdContainer.getIndirectHeap(heap)->getAvailableSpace();
559     EXPECT_GT(usedSpaceAfter + availableSizeAfter, usedSpaceBefore + availableSizeBefore);
560     EXPECT_EQ(!cmdContainer.isHeapDirty(heap), heap == IndirectHeap::INDIRECT_OBJECT);
561 }
562 
TEST_P(CommandContainerHeaps,givenCommandContainerForDifferentRootDevicesThenHeapsAreCreatedWithCorrectRootDeviceIndex)563 TEST_P(CommandContainerHeaps, givenCommandContainerForDifferentRootDevicesThenHeapsAreCreatedWithCorrectRootDeviceIndex) {
564     HeapType heap = GetParam();
565 
566     auto executionEnvironment = new NEO::ExecutionEnvironment();
567     const size_t numDevices = 2;
568     executionEnvironment->prepareRootDeviceEnvironments(numDevices);
569     for (auto i = 0u; i < numDevices; i++) {
570         executionEnvironment->rootDeviceEnvironments[i]->setHwInfo(defaultHwInfo.get());
571     }
572     auto device0 = std::unique_ptr<MockDevice>(Device::create<MockDevice>(executionEnvironment, 0u));
573     auto device1 = std::unique_ptr<MockDevice>(Device::create<MockDevice>(executionEnvironment, 1u));
574 
575     CommandContainer cmdContainer0;
576     cmdContainer0.initialize(device0.get(), nullptr);
577     uint32_t heapRootDeviceIndex0 = cmdContainer0.getIndirectHeap(heap)->getGraphicsAllocation()->getRootDeviceIndex();
578     EXPECT_EQ(device0->getRootDeviceIndex(), heapRootDeviceIndex0);
579 
580     CommandContainer cmdContainer1;
581     cmdContainer1.initialize(device1.get(), nullptr);
582     uint32_t heapRootDeviceIndex1 = cmdContainer1.getIndirectHeap(heap)->getGraphicsAllocation()->getRootDeviceIndex();
583     EXPECT_EQ(device1->getRootDeviceIndex(), heapRootDeviceIndex1);
584 }
585 
TEST_F(CommandContainerHeaps,givenCommandContainerForDifferentRootDevicesThenCmdBufferAllocationIsCreatedWithCorrectRootDeviceIndex)586 TEST_F(CommandContainerHeaps, givenCommandContainerForDifferentRootDevicesThenCmdBufferAllocationIsCreatedWithCorrectRootDeviceIndex) {
587     auto executionEnvironment = new NEO::ExecutionEnvironment();
588     const size_t numDevices = 2;
589     executionEnvironment->prepareRootDeviceEnvironments(numDevices);
590     for (auto i = 0u; i < numDevices; i++) {
591         executionEnvironment->rootDeviceEnvironments[i]->setHwInfo(defaultHwInfo.get());
592     }
593     auto device0 = std::unique_ptr<MockDevice>(Device::create<MockDevice>(executionEnvironment, 0u));
594     auto device1 = std::unique_ptr<MockDevice>(Device::create<MockDevice>(executionEnvironment, 1u));
595 
596     CommandContainer cmdContainer0;
597     cmdContainer0.initialize(device0.get(), nullptr);
598     EXPECT_EQ(1u, cmdContainer0.getCmdBufferAllocations().size());
599     uint32_t cmdBufferAllocationIndex0 = cmdContainer0.getCmdBufferAllocations().front()->getRootDeviceIndex();
600     EXPECT_EQ(device0->getRootDeviceIndex(), cmdBufferAllocationIndex0);
601 
602     CommandContainer cmdContainer1;
603     cmdContainer1.initialize(device1.get(), nullptr);
604     EXPECT_EQ(1u, cmdContainer1.getCmdBufferAllocations().size());
605     uint32_t cmdBufferAllocationIndex1 = cmdContainer1.getCmdBufferAllocations().front()->getRootDeviceIndex();
606     EXPECT_EQ(device1->getRootDeviceIndex(), cmdBufferAllocationIndex1);
607 }
608 
TEST_F(CommandContainerHeaps,givenCommandContainerForDifferentRootDevicesThenInternalHeapIsCreatedWithCorrectRootDeviceIndex)609 TEST_F(CommandContainerHeaps, givenCommandContainerForDifferentRootDevicesThenInternalHeapIsCreatedWithCorrectRootDeviceIndex) {
610     auto executionEnvironment = new NEO::ExecutionEnvironment();
611     const size_t numDevices = 2;
612     executionEnvironment->prepareRootDeviceEnvironments(numDevices);
613     for (auto i = 0u; i < numDevices; i++) {
614         executionEnvironment->rootDeviceEnvironments[i]->setHwInfo(defaultHwInfo.get());
615     }
616     auto device0 = std::unique_ptr<MockDevice>(Device::create<MockDevice>(executionEnvironment, 0u));
617     auto device1 = std::unique_ptr<MockDevice>(Device::create<MockDevice>(executionEnvironment, 1u));
618 
619     auto &hwHelper0 = HwHelper::get(device0->getHardwareInfo().platform.eRenderCoreFamily);
620     auto &hwHelper1 = HwHelper::get(device1->getHardwareInfo().platform.eRenderCoreFamily);
621 
622     CommandContainer cmdContainer0;
623     cmdContainer0.initialize(device0.get(), nullptr);
624     bool useLocalMemory0 = !hwHelper0.useSystemMemoryPlacementForISA(device0->getHardwareInfo());
625     uint64_t baseAddressHeapDevice0 = device0.get()->getMemoryManager()->getInternalHeapBaseAddress(device0->getRootDeviceIndex(), useLocalMemory0);
626     EXPECT_EQ(cmdContainer0.getInstructionHeapBaseAddress(), baseAddressHeapDevice0);
627 
628     CommandContainer cmdContainer1;
629     cmdContainer1.initialize(device1.get(), nullptr);
630     bool useLocalMemory1 = !hwHelper1.useSystemMemoryPlacementForISA(device0->getHardwareInfo());
631     uint64_t baseAddressHeapDevice1 = device1.get()->getMemoryManager()->getInternalHeapBaseAddress(device1->getRootDeviceIndex(), useLocalMemory1);
632     EXPECT_EQ(cmdContainer1.getInstructionHeapBaseAddress(), baseAddressHeapDevice1);
633 }
634 
TEST_F(CommandContainerTest,givenCommandContainerWhenDestructionThenNonHeapAllocationAreNotDestroyed)635 TEST_F(CommandContainerTest, givenCommandContainerWhenDestructionThenNonHeapAllocationAreNotDestroyed) {
636     std::unique_ptr<CommandContainer> cmdContainer(new CommandContainer());
637     MockGraphicsAllocation alloc;
638     size_t size = 0x1000;
639     alloc.setSize(size);
640     cmdContainer->initialize(pDevice, nullptr);
641     cmdContainer->getDeallocationContainer().push_back(&alloc);
642     cmdContainer.reset();
643     EXPECT_EQ(alloc.getUnderlyingBufferSize(), size);
644 }
645 
TEST_F(CommandContainerTest,givenContainerAllocatesNextCommandBufferWhenResetingContainerThenExpectFirstCommandBufferAllocationIsReused)646 TEST_F(CommandContainerTest, givenContainerAllocatesNextCommandBufferWhenResetingContainerThenExpectFirstCommandBufferAllocationIsReused) {
647     auto cmdContainer = std::make_unique<CommandContainer>();
648     cmdContainer->initialize(pDevice, nullptr);
649 
650     auto stream = cmdContainer->getCommandStream();
651     ASSERT_NE(nullptr, stream);
652     auto firstCmdBufferAllocation = stream->getGraphicsAllocation();
653     ASSERT_NE(nullptr, firstCmdBufferAllocation);
654     auto firstCmdBufferCpuPointer = stream->getSpace(0);
655     EXPECT_EQ(firstCmdBufferCpuPointer, firstCmdBufferAllocation->getUnderlyingBuffer());
656 
657     cmdContainer->allocateNextCommandBuffer();
658     auto secondCmdBufferAllocation = stream->getGraphicsAllocation();
659     ASSERT_NE(nullptr, secondCmdBufferAllocation);
660     EXPECT_NE(firstCmdBufferAllocation, secondCmdBufferAllocation);
661     auto secondCmdBufferCpuPointer = stream->getSpace(0);
662     EXPECT_EQ(secondCmdBufferCpuPointer, secondCmdBufferAllocation->getUnderlyingBuffer());
663     EXPECT_NE(firstCmdBufferCpuPointer, secondCmdBufferCpuPointer);
664 
665     cmdContainer->reset();
666 
667     auto aferResetCmdBufferAllocation = stream->getGraphicsAllocation();
668     ASSERT_NE(nullptr, aferResetCmdBufferAllocation);
669     auto afterResetCmdBufferCpuPointer = stream->getSpace(0);
670     EXPECT_EQ(afterResetCmdBufferCpuPointer, aferResetCmdBufferAllocation->getUnderlyingBuffer());
671 
672     EXPECT_EQ(firstCmdBufferAllocation, aferResetCmdBufferAllocation);
673     EXPECT_EQ(firstCmdBufferCpuPointer, afterResetCmdBufferCpuPointer);
674 
675     bool firstAllocationFound = false;
676     auto &residencyContainer = cmdContainer->getResidencyContainer();
677     for (auto *allocation : residencyContainer) {
678         if (allocation == firstCmdBufferAllocation) {
679             firstAllocationFound = true;
680             break;
681         }
682     }
683     EXPECT_TRUE(firstAllocationFound);
684 }
685