IndirectBufferTests.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "RHITestFixture.h"
  9. #include <Tests/Factory.h>
  10. #include <Tests/Device.h>
  11. #include <Tests/Buffer.h>
  12. #include <Tests/IndirectBuffer.h>
  13. #include <Atom/RHI/FrameEventBus.h>
  14. #include <Atom/RHI.Reflect/ReflectSystemComponent.h>
  15. #include <AzCore/Serialization/ObjectStream.h>
  16. #include <AzCore/Serialization/Utils.h>
  17. namespace UnitTest
  18. {
  19. using namespace AZ;
  20. class IndirectBufferTests
  21. : public RHITestFixture
  22. {
  23. public:
  24. IndirectBufferTests()
  25. : RHITestFixture()
  26. {
  27. }
  28. ~IndirectBufferTests()
  29. {
  30. }
  31. private:
  32. void SetUp() override
  33. {
  34. RHITestFixture::SetUp();
  35. m_factory.reset(aznew Factory());
  36. m_device = MakeTestDevice();
  37. m_serializeContext = AZStd::make_unique<SerializeContext>();
  38. RHI::ReflectSystemComponent::Reflect(m_serializeContext.get());
  39. AZ::Name::Reflect(m_serializeContext.get());
  40. m_commands.clear();
  41. m_commands.push_back(RHI::IndirectCommandType::RootConstants);
  42. m_commands.push_back(RHI::IndirectBufferViewArguments{ s_vertexSlotIndex });
  43. m_commands.push_back(RHI::IndirectCommandType::IndexBufferView);
  44. m_commands.push_back(RHI::IndirectCommandType::DrawIndexed);
  45. m_bufferPool = static_cast<BufferPool*>(RHI::Factory::Get().CreateBufferPool().get());
  46. RHI::BufferPoolDescriptor poolDesc;
  47. poolDesc.m_bindFlags = RHI::BufferBindFlags::ShaderReadWrite;
  48. m_bufferPool->Init(*m_device, poolDesc);
  49. m_buffer = static_cast<Buffer*>(RHI::Factory::Get().CreateBuffer().get());
  50. RHI::DeviceBufferInitRequest initRequest;
  51. initRequest.m_buffer = m_buffer.get();
  52. initRequest.m_descriptor.m_byteCount = m_writerCommandStride * m_writerNumCommands;
  53. initRequest.m_descriptor.m_bindFlags = poolDesc.m_bindFlags;
  54. m_bufferPool->InitBuffer(initRequest);
  55. m_writerSignature = CreateInitializedSignature();
  56. EXPECT_CALL(*m_writerSignature, GetByteStrideInternal())
  57. .WillRepeatedly(
  58. testing::Return(m_writerCommandStride));
  59. }
  60. void TearDown() override
  61. {
  62. m_buffer.reset();
  63. m_bufferPool.reset();
  64. m_writerSignature.reset();
  65. m_factory.reset();
  66. m_device.reset();
  67. m_serializeContext.reset();
  68. RHITestFixture::TearDown();
  69. }
  70. protected:
  71. RHI::IndirectBufferLayout CreateUnfinalizedLayout()
  72. {
  73. RHI::IndirectBufferLayout layout;
  74. for (const auto& descriptor : m_commands)
  75. {
  76. EXPECT_TRUE(layout.AddIndirectCommand(descriptor));
  77. }
  78. return layout;
  79. }
  80. RHI::IndirectBufferLayout CreateFinalizedLayout()
  81. {
  82. auto layout = CreateUnfinalizedLayout();
  83. EXPECT_TRUE(layout.Finalize());
  84. return layout;
  85. }
  86. RHI::IndirectBufferLayout CreateSerializedLayout(const RHI::IndirectBufferLayout& layout)
  87. {
  88. AZStd::vector<char, AZ::OSStdAllocator> buffer;
  89. AZ::IO::ByteContainerStream<AZStd::vector<char, AZ::OSStdAllocator> > outStream(&buffer);
  90. {
  91. AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&outStream, *m_serializeContext.get(), AZ::ObjectStream::ST_BINARY);
  92. bool writeOK = objStream->WriteClass(&layout);
  93. EXPECT_TRUE(writeOK);
  94. bool finalizeOK = objStream->Finalize();
  95. EXPECT_TRUE(finalizeOK);
  96. }
  97. outStream.Seek(0, IO::GenericStream::ST_SEEK_BEGIN);
  98. AZ::ObjectStream::FilterDescriptor filterDesc;
  99. RHI::IndirectBufferLayout deserializedLayout;
  100. bool deserializedOK = AZ::Utils::LoadObjectFromStreamInPlace<RHI::IndirectBufferLayout>(outStream, deserializedLayout, m_serializeContext.get(), filterDesc);
  101. EXPECT_TRUE(deserializedOK);
  102. return deserializedLayout;
  103. }
  104. void ValidateLayout(const RHI::IndirectBufferLayout& layout)
  105. {
  106. EXPECT_TRUE(layout.IsFinalized());
  107. auto layoutCommands = layout.GetCommands();
  108. EXPECT_EQ(m_commands.size(), layoutCommands.size());
  109. for (uint32_t i = 0; i < m_commands.size(); ++i)
  110. {
  111. EXPECT_EQ(m_commands[i], layoutCommands[i]);
  112. EXPECT_EQ(layout.FindCommandIndex(m_commands[i]), RHI::IndirectCommandIndex(i));
  113. }
  114. }
  115. RHI::Ptr<IndirectBufferSignature> CreateInitializedSignature()
  116. {
  117. using namespace ::testing;
  118. auto signature = aznew NiceIndirectBufferSignature;
  119. m_signatureDescriptor.m_layout = CreateFinalizedLayout();
  120. EXPECT_CALL(*signature, InitInternal(_, _))
  121. .Times(1)
  122. .WillOnce(
  123. Return(AZ::RHI::ResultCode::Success));
  124. EXPECT_EQ(signature->Init(*m_device, m_signatureDescriptor), RHI::ResultCode::Success);
  125. return signature;
  126. }
  127. RHI::Ptr<IndirectBufferSignature> CreateUnInitializedSignature()
  128. {
  129. auto signature = aznew NiceIndirectBufferSignature;
  130. return signature;
  131. }
  132. RHI::Ptr<IndirectBufferWriter> CreateInitializedWriter()
  133. {
  134. auto writer = aznew NiceIndirectBufferWriter;
  135. EXPECT_EQ(writer->Init(*m_buffer, m_writerOffset, m_writerCommandStride, m_writerNumCommands, *m_writerSignature), RHI::ResultCode::Success);
  136. return writer;
  137. }
  138. void ValidateSignature(const RHI::DeviceIndirectBufferSignature& signature)
  139. {
  140. ValidateLayout(signature.GetLayout());
  141. EXPECT_TRUE(signature.IsInitialized());
  142. }
  143. void ValidateWriter(const IndirectBufferWriter& writer)
  144. {
  145. EXPECT_EQ(writer.GetData(), static_cast<const uint8_t*>(m_buffer->GetData().data()));
  146. EXPECT_EQ(writer.GetCurrentSequenceIndex(), 0);
  147. EXPECT_TRUE(m_buffer->IsMapped());
  148. }
  149. AZStd::unique_ptr<Factory> m_factory;
  150. RHI::Ptr<RHI::Device> m_device;
  151. static const uint32_t s_vertexSlotIndex = 3;
  152. AZStd::vector<RHI::IndirectCommandDescriptor> m_commands;
  153. AZStd::unique_ptr<SerializeContext> m_serializeContext;
  154. RHI::DeviceIndirectBufferSignatureDescriptor m_signatureDescriptor;
  155. RHI::Ptr<BufferPool> m_bufferPool;
  156. RHI::Ptr<Buffer> m_buffer;
  157. size_t m_writerOffset = 0;
  158. uint32_t m_writerCommandStride = 2;
  159. uint32_t m_writerNumCommands = 1024;
  160. RHI::Ptr<IndirectBufferSignature> m_writerSignature;
  161. };
  162. TEST_F(IndirectBufferTests, TestLayout)
  163. {
  164. // Normal layout initialization
  165. {
  166. auto layout = CreateFinalizedLayout();
  167. ValidateLayout(layout);
  168. }
  169. // Double finalize.
  170. {
  171. auto layout = CreateFinalizedLayout();
  172. AZ_TEST_START_TRACE_SUPPRESSION;
  173. EXPECT_FALSE(layout.Finalize());
  174. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  175. }
  176. // Add a command to a finalized layout
  177. {
  178. auto layout = CreateFinalizedLayout();
  179. AZ_TEST_START_TRACE_SUPPRESSION;
  180. EXPECT_FALSE(layout.AddIndirectCommand(RHI::IndirectBufferViewArguments{ 1337 }));
  181. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  182. }
  183. // Get list of commands of non finalized layout
  184. {
  185. auto layout = CreateUnfinalizedLayout();
  186. AZ_TEST_START_TRACE_SUPPRESSION;
  187. EXPECT_EQ(layout.GetCommands().size(), 0);
  188. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  189. }
  190. // Same hash
  191. {
  192. auto layout1 = CreateFinalizedLayout();
  193. auto layout2 = CreateFinalizedLayout();
  194. EXPECT_EQ(layout1.GetHash(), layout2.GetHash());
  195. }
  196. // Different hash
  197. {
  198. auto layout1 = CreateUnfinalizedLayout();
  199. auto layout2 = layout1;
  200. EXPECT_TRUE(layout2.AddIndirectCommand(RHI::IndirectBufferViewArguments{ 1337 }));
  201. EXPECT_TRUE(layout1.Finalize());
  202. EXPECT_TRUE(layout2.Finalize());
  203. EXPECT_NE(layout1.GetHash(), layout2.GetHash());
  204. }
  205. // Duplicate command
  206. {
  207. auto layout = CreateUnfinalizedLayout();
  208. AZ_TEST_START_TRACE_SUPPRESSION;
  209. for (const auto& desc : m_commands)
  210. {
  211. EXPECT_FALSE(layout.AddIndirectCommand(desc));
  212. }
  213. AZ_TEST_STOP_TRACE_SUPPRESSION(m_commands.size());
  214. }
  215. // Duplicate main command (only one draw, drawIndexed or dispatch is allowed)
  216. {
  217. auto layout = CreateUnfinalizedLayout();
  218. EXPECT_TRUE(layout.AddIndirectCommand(RHI::IndirectCommandType::Dispatch));
  219. AZ_TEST_START_TRACE_SUPPRESSION;
  220. EXPECT_FALSE(layout.Finalize());
  221. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  222. }
  223. // Find invalid command
  224. {
  225. auto layout = CreateFinalizedLayout();
  226. auto index = layout.FindCommandIndex(RHI::IndirectCommandType::Draw);
  227. EXPECT_TRUE(index.IsNull());
  228. }
  229. // Test serialization
  230. {
  231. auto layout = CreateFinalizedLayout();
  232. auto serializedLayout = CreateSerializedLayout(layout);
  233. ValidateLayout(serializedLayout);
  234. EXPECT_EQ(layout.GetHash(), serializedLayout.GetHash());
  235. }
  236. // Layout type
  237. {
  238. auto layout = CreateFinalizedLayout();
  239. EXPECT_EQ(layout.GetType(), RHI::IndirectBufferLayoutType::IndexedDraw);
  240. }
  241. }
  242. TEST_F(IndirectBufferTests, TestSignature)
  243. {
  244. // Normal initialization
  245. {
  246. auto signature = CreateInitializedSignature();
  247. EXPECT_TRUE(signature != nullptr);
  248. ValidateSignature(*signature);
  249. }
  250. // Failure initializing.
  251. {
  252. auto signature = CreateUnInitializedSignature();
  253. EXPECT_CALL(*signature, InitInternal(testing::_, testing::_))
  254. .Times(1)
  255. .WillOnce(
  256. testing::Return(RHI::ResultCode::InvalidOperation));
  257. RHI::DeviceIndirectBufferSignatureDescriptor descriptor;
  258. EXPECT_TRUE(signature->Init(*m_device, descriptor) == RHI::ResultCode::InvalidOperation);
  259. EXPECT_FALSE(signature->IsInitialized());
  260. }
  261. // GetByteStride()
  262. {
  263. auto signature = CreateInitializedSignature();
  264. uint32_t byteStride = 1337;
  265. EXPECT_CALL(*signature, GetByteStrideInternal())
  266. .Times(1)
  267. .WillOnce(
  268. testing::Return(byteStride));
  269. EXPECT_EQ(signature->GetByteStride(), byteStride);
  270. }
  271. // GetByteStride() on uninitialized signature.
  272. {
  273. auto signature = CreateUnInitializedSignature();
  274. EXPECT_CALL(*signature, GetByteStrideInternal())
  275. .Times(1)
  276. .WillOnce(
  277. testing::Return(0));
  278. AZ_TEST_START_TRACE_SUPPRESSION;
  279. signature->GetByteStride();
  280. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  281. }
  282. // GetOffset()
  283. {
  284. auto signature = CreateInitializedSignature();
  285. uint32_t offset = 1337;
  286. RHI::IndirectCommandIndex index(m_commands.size() - 1);
  287. EXPECT_CALL(*signature, GetOffsetInternal(index))
  288. .Times(1)
  289. .WillOnce(
  290. testing::Return(offset));
  291. EXPECT_EQ(signature->GetOffset(index), offset);
  292. }
  293. // GetOffset with null index
  294. {
  295. auto signature = CreateInitializedSignature();
  296. RHI::IndirectCommandIndex index = RHI::IndirectCommandIndex::Null;
  297. AZ_TEST_START_TRACE_SUPPRESSION;
  298. signature->GetOffset(index);
  299. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  300. }
  301. // GetOffset with invalid index
  302. {
  303. auto signature = CreateInitializedSignature();
  304. RHI::IndirectCommandIndex index(m_commands.size());
  305. AZ_TEST_START_TRACE_SUPPRESSION;
  306. signature->GetOffset(index);
  307. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  308. }
  309. // Shutdown
  310. {
  311. auto signature = CreateInitializedSignature();
  312. EXPECT_CALL(*signature, ShutdownInternal())
  313. .Times(1);
  314. }
  315. }
  316. TEST_F(IndirectBufferTests, TestWriter)
  317. {
  318. // Normal Initialization
  319. {
  320. auto writer = CreateInitializedWriter();
  321. EXPECT_TRUE(writer != nullptr);
  322. ValidateWriter(*writer);
  323. }
  324. // Initialization with invalid size
  325. {
  326. RHI::Ptr<IndirectBufferWriter> writer = aznew NiceIndirectBufferWriter;
  327. AZ_TEST_START_TRACE_SUPPRESSION;
  328. EXPECT_EQ(writer->Init(*m_buffer, 1, m_writerCommandStride, m_writerNumCommands, *m_writerSignature), RHI::ResultCode::InvalidArgument);
  329. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  330. }
  331. // Initialization with invalid stride
  332. {
  333. RHI::Ptr<IndirectBufferWriter> writer = aznew NiceIndirectBufferWriter;
  334. AZ_TEST_START_TRACE_SUPPRESSION;
  335. EXPECT_EQ(writer->Init(*m_buffer, m_writerOffset, 0, m_writerNumCommands, *m_writerSignature), RHI::ResultCode::InvalidArgument);
  336. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  337. }
  338. // Initialization with invalid max num sequences
  339. {
  340. RHI::Ptr<IndirectBufferWriter> writer = aznew NiceIndirectBufferWriter;
  341. AZ_TEST_START_TRACE_SUPPRESSION;
  342. EXPECT_EQ(writer->Init(*m_buffer, m_writerOffset, m_writerCommandStride, 0, *m_writerSignature), RHI::ResultCode::InvalidArgument);
  343. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  344. }
  345. // Initialization with small invalid stride
  346. {
  347. RHI::Ptr<IndirectBufferWriter> writer = aznew NiceIndirectBufferWriter;
  348. AZ_TEST_START_TRACE_SUPPRESSION;
  349. EXPECT_EQ(writer->Init(*m_buffer, m_writerOffset, m_writerCommandStride - 1, m_writerNumCommands, *m_writerSignature), RHI::ResultCode::InvalidArgument);
  350. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  351. }
  352. // Initialization with invalid signature
  353. {
  354. RHI::Ptr<IndirectBufferWriter> writer = aznew NiceIndirectBufferWriter;
  355. auto signature = CreateUnInitializedSignature();
  356. AZ_TEST_START_TRACE_SUPPRESSION;
  357. EXPECT_EQ(writer->Init(*m_buffer, m_writerOffset, m_writerCommandStride, m_writerNumCommands, *signature), RHI::ResultCode::InvalidArgument);
  358. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  359. }
  360. // Initialization with offset
  361. {
  362. RHI::Ptr<IndirectBufferWriter> writer = aznew NiceIndirectBufferWriter;
  363. size_t offset = 16;
  364. EXPECT_EQ(writer->Init(*m_buffer, offset, m_writerCommandStride, 5, *m_writerSignature), RHI::ResultCode::Success);
  365. EXPECT_EQ(writer->GetData(), m_buffer->GetData().data() + offset);
  366. }
  367. // Initialization with memory pointer
  368. {
  369. RHI::Ptr<IndirectBufferWriter> writer = aznew NiceIndirectBufferWriter;
  370. EXPECT_EQ(writer->Init(const_cast<uint8_t*>(m_buffer->GetData().data()), m_writerCommandStride, m_writerNumCommands, *m_writerSignature), RHI::ResultCode::Success);
  371. EXPECT_EQ(writer->GetData(), m_buffer->GetData().data());
  372. }
  373. // Double Init
  374. {
  375. auto writer = CreateInitializedWriter();
  376. AZ_TEST_START_TRACE_SUPPRESSION;
  377. EXPECT_EQ(writer->Init(*m_buffer, m_writerOffset, m_writerCommandStride, m_writerNumCommands, *m_writerSignature), RHI::ResultCode::InvalidOperation);
  378. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  379. }
  380. // Valid Seek
  381. {
  382. auto writer = CreateInitializedWriter();
  383. uint32_t seekPos = 2;
  384. EXPECT_TRUE(writer->Seek(seekPos));
  385. EXPECT_EQ(writer->GetCurrentSequenceIndex(), seekPos);
  386. seekPos += 6;
  387. EXPECT_TRUE(writer->Seek(seekPos));
  388. EXPECT_EQ(writer->GetCurrentSequenceIndex(), seekPos);
  389. }
  390. // Invalid Seek
  391. {
  392. auto writer = CreateInitializedWriter();
  393. EXPECT_FALSE(writer->Seek(m_writerNumCommands + 1));
  394. EXPECT_EQ(writer->GetCurrentSequenceIndex(), 0);
  395. }
  396. // Valid NextSequence
  397. {
  398. auto writer = CreateInitializedWriter();
  399. EXPECT_TRUE(writer->NextSequence());
  400. EXPECT_EQ(writer->GetCurrentSequenceIndex(), 1);
  401. }
  402. // Invalid NextSequence
  403. {
  404. auto writer = CreateInitializedWriter();
  405. EXPECT_TRUE(writer->Seek(m_writerNumCommands - 1));
  406. EXPECT_FALSE(writer->NextSequence());
  407. EXPECT_EQ(writer->GetCurrentSequenceIndex(), m_writerNumCommands - 1);
  408. }
  409. // Valid Command
  410. {
  411. auto writer = CreateInitializedWriter();
  412. for (const auto& command : m_commands)
  413. {
  414. switch (command.m_type)
  415. {
  416. case RHI::IndirectCommandType::VertexBufferView:
  417. {
  418. auto index = m_signatureDescriptor.m_layout.FindCommandIndex(RHI::IndirectBufferViewArguments{ s_vertexSlotIndex });
  419. EXPECT_FALSE(index.IsNull());
  420. AZ::RHI::DeviceStreamBufferView bufferView(*m_buffer, 0, 12, 10);
  421. EXPECT_CALL(*writer, SetVertexViewInternal(index, testing::_)).Times(1);
  422. writer->SetVertexView(s_vertexSlotIndex, bufferView);
  423. break;
  424. }
  425. case RHI::IndirectCommandType::IndexBufferView:
  426. {
  427. auto index = m_signatureDescriptor.m_layout.FindCommandIndex(command.m_type);
  428. EXPECT_FALSE(index.IsNull());
  429. AZ::RHI::DeviceIndexBufferView indexView(*m_buffer, 0, 12, RHI::IndexFormat::Uint16);
  430. EXPECT_CALL(*writer, SetIndexViewInternal(index, testing::_)).Times(1);
  431. writer->SetIndexView(indexView);
  432. break;
  433. }
  434. case RHI::IndirectCommandType::DrawIndexed:
  435. {
  436. auto index = m_signatureDescriptor.m_layout.FindCommandIndex(command.m_type);
  437. EXPECT_FALSE(index.IsNull());
  438. AZ::RHI::DrawIndexed arguments(1, 2, 3, 4, 5);
  439. EXPECT_CALL(*writer, DrawIndexedInternal(index, testing::_)).Times(1);
  440. writer->DrawIndexed(arguments);
  441. break;
  442. }
  443. case RHI::IndirectCommandType::RootConstants:
  444. {
  445. auto index = m_signatureDescriptor.m_layout.FindCommandIndex(command.m_type);
  446. EXPECT_FALSE(index.IsNull());
  447. size_t rootConstant;
  448. EXPECT_CALL(*m_writerSignature, GetOffsetInternal(index)).
  449. Times(1)
  450. .WillOnce(testing::Return(0));
  451. auto nextIndex = RHI::IndirectCommandIndex(index.GetIndex() + 1);
  452. EXPECT_CALL(*m_writerSignature, GetOffsetInternal(nextIndex)).
  453. Times(1)
  454. .WillOnce(testing::Return(static_cast<uint32_t>(sizeof(rootConstant))));
  455. EXPECT_CALL(*writer, SetRootConstantsInternal(index, reinterpret_cast<uint8_t*>(&rootConstant), sizeof(rootConstant))).Times(1);
  456. writer->SetRootConstants(reinterpret_cast<uint8_t*>(&rootConstant), sizeof(rootConstant));
  457. break;
  458. }
  459. default:
  460. break;
  461. }
  462. }
  463. }
  464. // Invalid command
  465. {
  466. auto writer = CreateInitializedWriter();
  467. RHI::DispatchDirect args;
  468. AZ_TEST_START_TRACE_SUPPRESSION;
  469. writer->Dispatch(args);
  470. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  471. }
  472. // Write command on uninitialized writer
  473. {
  474. RHI::Ptr<IndirectBufferWriter> writer = aznew NiceIndirectBufferWriter;
  475. ;
  476. AZ::RHI::DrawIndexed arguments(1, 2, 3, 4, 5);
  477. EXPECT_CALL(*writer, DrawIndexedInternal(testing::_, testing::_)).Times(0);
  478. AZ_TEST_START_TRACE_SUPPRESSION;
  479. writer->DrawIndexed(arguments);
  480. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  481. }
  482. // Flush
  483. {
  484. auto writer = CreateInitializedWriter();
  485. writer->Flush();
  486. EXPECT_FALSE(m_buffer->IsMapped());
  487. AZ::RHI::DeviceIndexBufferView indexView(*m_buffer, 0, 12, RHI::IndexFormat::Uint16);
  488. EXPECT_CALL(*writer, SetIndexViewInternal(testing::_, testing::_)).Times(1);
  489. writer->SetIndexView(indexView);
  490. EXPECT_TRUE(m_buffer->IsMapped());
  491. }
  492. // Inline Constants Command with incorrect size
  493. {
  494. auto writer = CreateInitializedWriter();
  495. auto findIt = AZStd::find_if(m_commands.begin(), m_commands.end(), [](const auto& element) { return element.m_type == RHI::IndirectCommandType::RootConstants; });
  496. EXPECT_NE(findIt, m_commands.end());
  497. auto commandIndex = m_writerSignature->GetLayout().FindCommandIndex(*findIt);
  498. EXPECT_FALSE(commandIndex.IsNull());
  499. auto nextCommandIndex = RHI::IndirectCommandIndex(commandIndex.GetIndex() + 1);
  500. uint32_t commandOffsett = 12;
  501. uint32_t nextCommandOffset = 16;
  502. EXPECT_CALL(*m_writerSignature, GetOffsetInternal(commandIndex))
  503. .Times(1)
  504. .WillOnce(
  505. testing::Return(commandOffsett));
  506. EXPECT_CALL(*m_writerSignature, GetOffsetInternal(nextCommandIndex))
  507. .Times(1)
  508. .WillOnce(
  509. testing::Return(nextCommandOffset));
  510. AZ_TEST_START_TRACE_SUPPRESSION;
  511. uint64_t data;
  512. writer->SetRootConstants(reinterpret_cast<uint8_t*>(&data), sizeof(data));
  513. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  514. }
  515. // Shutdown
  516. {
  517. auto writer = CreateInitializedWriter();
  518. writer->Shutdown();
  519. EXPECT_FALSE(m_buffer->IsMapped());
  520. EXPECT_TRUE(writer->GetData() == nullptr);
  521. }
  522. }
  523. }