123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include "RHITestFixture.h"
- #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
- #include <AzCore/Name/NameDictionary.h>
- namespace UnitTest
- {
- using namespace AZ;
- using namespace RHI;
- class InputStreamLayoutBuilderTests
- : public RHITestFixture
- {
- protected:
- void ExpectEq(AZStd::span<const StreamBufferDescriptor> expected, AZStd::span<const StreamBufferDescriptor> actual)
- {
- EXPECT_EQ(expected.size(), actual.size());
- for (int i = 0; i < expected.size() && i < actual.size(); ++i)
- {
- EXPECT_EQ(expected[i].m_stepRate, actual[i].m_stepRate);
- EXPECT_EQ(expected[i].m_stepFunction, actual[i].m_stepFunction);
- EXPECT_EQ(expected[i].m_byteStride, actual[i].m_byteStride);
- }
- }
- void ExpectEq(AZStd::span<const StreamChannelDescriptor> expected, AZStd::span<const StreamChannelDescriptor> actual)
- {
- EXPECT_EQ(expected.size(), actual.size());
- for (int i = 0; i < expected.size() && i < actual.size(); ++i)
- {
- EXPECT_EQ(expected[i].m_bufferIndex, actual[i].m_bufferIndex);
- EXPECT_EQ(expected[i].m_byteOffset, actual[i].m_byteOffset);
- EXPECT_EQ(expected[i].m_format, actual[i].m_format);
- EXPECT_EQ(expected[i].m_semantic, actual[i].m_semantic);
- }
- }
- void ExpectEq(const InputStreamLayout& expected, const InputStreamLayout& actual)
- {
- EXPECT_EQ(expected.IsFinalized(), actual.IsFinalized());
- EXPECT_EQ(expected.GetTopology(), actual.GetTopology());
- ExpectEq(expected.GetStreamBuffers(), actual.GetStreamBuffers());
- ExpectEq(expected.GetStreamChannels(), actual.GetStreamChannels());
- }
- };
- TEST_F(InputStreamLayoutBuilderTests, TestDefault)
- {
- InputStreamLayout expected;
- expected.SetTopology(PrimitiveTopology::TriangleList);
- expected.Finalize();
- InputStreamLayout actual = InputStreamLayoutBuilder().End();
- ExpectEq(expected, actual);
- }
- TEST_F(InputStreamLayoutBuilderTests, TestInterleavedBuffer)
- {
- InputStreamLayout expected;
- {
- expected.SetTopology(RHI::PrimitiveTopology::TriangleList);
- RHI::StreamChannelDescriptor positionDescriptor;
- positionDescriptor.m_bufferIndex = 0;
- positionDescriptor.m_byteOffset = 0;
- positionDescriptor.m_format = RHI::Format::R32G32_FLOAT;
- positionDescriptor.m_semantic.m_name = Name{ "POSITION" };
- expected.AddStreamChannel(positionDescriptor);
- RHI::StreamChannelDescriptor uvDescriptor;
- uvDescriptor.m_bufferIndex = 0;
- uvDescriptor.m_byteOffset = sizeof(float) * 2;
- uvDescriptor.m_format = RHI::Format::R32G32_FLOAT;
- uvDescriptor.m_semantic.m_name = Name{ "UV" };
- expected.AddStreamChannel(uvDescriptor);
- RHI::StreamChannelDescriptor colorDescriptor;
- colorDescriptor.m_bufferIndex = 0;
- colorDescriptor.m_byteOffset = sizeof(float) * 4;
- colorDescriptor.m_format = RHI::Format::R8G8B8A8_UNORM;
- colorDescriptor.m_semantic.m_name = Name{ "COLOR" };
- expected.AddStreamChannel(colorDescriptor);
- RHI::StreamBufferDescriptor bufferDescriptor;
- bufferDescriptor.m_byteStride = sizeof(float) * 4 + 4;
- expected.AddStreamBuffer(bufferDescriptor);
- expected.Finalize();
- }
-
- InputStreamLayout actual;
- {
- RHI::InputStreamLayoutBuilder layoutBuilder;
- layoutBuilder.AddBuffer()
- ->Channel("POSITION", RHI::Format::R32G32_FLOAT)
- ->Channel("UV", RHI::Format::R32G32_FLOAT)
- ->Channel("COLOR", RHI::Format::R8G8B8A8_UNORM);
- actual = layoutBuilder.End();
- }
- ExpectEq(expected, actual);
- }
- TEST_F(InputStreamLayoutBuilderTests, TestIndependentBuffers)
- {
- InputStreamLayout expected;
- {
- expected.SetTopology(RHI::PrimitiveTopology::TriangleList);
- RHI::StreamChannelDescriptor positionDescriptor;
- positionDescriptor.m_bufferIndex = 0;
- positionDescriptor.m_byteOffset = 0;
- positionDescriptor.m_format = RHI::Format::R32G32B32_FLOAT;
- positionDescriptor.m_semantic.m_name = Name{ "POSITION" };
- expected.AddStreamChannel(positionDescriptor);
- RHI::StreamChannelDescriptor colorDescriptor;
- colorDescriptor.m_bufferIndex = 1;
- colorDescriptor.m_byteOffset = 0;
- colorDescriptor.m_format = RHI::Format::R32G32B32A32_FLOAT;
- colorDescriptor.m_semantic.m_name = Name{ "COLOR" };
- expected.AddStreamChannel(colorDescriptor);
- RHI::StreamChannelDescriptor uvDescriptor;
- uvDescriptor.m_bufferIndex = 2;
- uvDescriptor.m_byteOffset = 0;
- uvDescriptor.m_format = RHI::Format::R32G32_FLOAT;
- uvDescriptor.m_semantic.m_name = Name{ "UV" };
- expected.AddStreamChannel(uvDescriptor);
- RHI::StreamBufferDescriptor bufferDescriptor;
- bufferDescriptor.m_byteStride = 3 * sizeof(float);
- expected.AddStreamBuffer(bufferDescriptor);
- bufferDescriptor.m_byteStride = 4 * sizeof(float);
- expected.AddStreamBuffer(bufferDescriptor);
- bufferDescriptor.m_byteStride = 2 * sizeof(float);
- expected.AddStreamBuffer(bufferDescriptor);
- expected.Finalize();
- }
- InputStreamLayout actual;
- {
- RHI::InputStreamLayoutBuilder layoutBuilder;
- layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
- layoutBuilder.AddBuffer()->Channel("COLOR", RHI::Format::R32G32B32A32_FLOAT);
- layoutBuilder.AddBuffer()->Channel("UV", RHI::Format::R32G32_FLOAT);
- actual = layoutBuilder.End();
- }
- ExpectEq(expected, actual);
- }
- TEST_F(InputStreamLayoutBuilderTests, TestMultipleInterleavedBuffersWithPadding)
- {
- InputStreamLayout expected;
- {
- expected.SetTopology(RHI::PrimitiveTopology::TriangleList);
- // Buffer 0 ...
- RHI::StreamChannelDescriptor positionDescriptor;
- positionDescriptor.m_bufferIndex = 0;
- positionDescriptor.m_byteOffset = 0;
- positionDescriptor.m_format = RHI::Format::R32G32B32_FLOAT;
- positionDescriptor.m_semantic.m_name = Name{ "POSITION" };
- expected.AddStreamChannel(positionDescriptor);
- RHI::StreamChannelDescriptor colorDescriptor;
- colorDescriptor.m_bufferIndex = 0;
- colorDescriptor.m_byteOffset = sizeof(float) * 4; // Includes 4 bytes of padding between channels
- colorDescriptor.m_format = RHI::Format::R32G32B32A32_FLOAT;
- colorDescriptor.m_semantic.m_name = Name{ "COLOR" };
- expected.AddStreamChannel(colorDescriptor);
- RHI::StreamBufferDescriptor bufferDescriptor;
- bufferDescriptor.m_byteStride = 8 * sizeof(float);
- expected.AddStreamBuffer(bufferDescriptor);
- // Buffer 1 ...
- RHI::StreamChannelDescriptor uvDescriptor;
- uvDescriptor.m_bufferIndex = 1;
- uvDescriptor.m_byteOffset = 0;
- uvDescriptor.m_format = RHI::Format::R32G32_FLOAT;
- uvDescriptor.m_semantic = ShaderSemantic{ "UV", 0 };
- expected.AddStreamChannel(uvDescriptor);
- uvDescriptor.m_byteOffset = sizeof(float) * 2;
- uvDescriptor.m_format = RHI::Format::R32G32_FLOAT;
- uvDescriptor.m_semantic = ShaderSemantic{ "UV", 1 };
- expected.AddStreamChannel(uvDescriptor);
- // UV1 is present in the buffer but not used for this shader
- uvDescriptor.m_byteOffset = sizeof(float) * 6;
- uvDescriptor.m_format = RHI::Format::R32G32_FLOAT;
- uvDescriptor.m_semantic = ShaderSemantic{ "UV", 3 };
- expected.AddStreamChannel(uvDescriptor);
- uvDescriptor.m_byteOffset = sizeof(float) * 8;
- uvDescriptor.m_format = RHI::Format::R32G32_FLOAT;
- uvDescriptor.m_semantic = ShaderSemantic{ "UV", 4 };
- expected.AddStreamChannel(uvDescriptor);
- bufferDescriptor.m_byteStride = 10 * sizeof(float);
- expected.AddStreamBuffer(bufferDescriptor);
- expected.Finalize();
- }
- InputStreamLayout actual;
- {
- RHI::InputStreamLayoutBuilder layoutBuilder;
- layoutBuilder.AddBuffer()
- ->Channel("POSITION", RHI::Format::R32G32B32_FLOAT)
- ->Padding(sizeof(float))
- ->Channel("COLOR", RHI::Format::R32G32B32A32_FLOAT);
- layoutBuilder.AddBuffer()
- ->Channel("UV0", RHI::Format::R32G32_FLOAT)
- ->Channel("UV1", RHI::Format::R32G32_FLOAT)
- ->Padding(sizeof(float) * 2)
- ->Channel("UV3", RHI::Format::R32G32_FLOAT)
- ->Channel("UV4", RHI::Format::R32G32_FLOAT);
- actual = layoutBuilder.End();
- }
- ExpectEq(expected, actual);
- }
- TEST_F(InputStreamLayoutBuilderTests, TestTooManyBuffers)
- {
- const uint32_t maxBuffers = RHI::Limits::Pipeline::StreamCountMax;
- // The expected layout will have exactly the max number of buffers, which demonstrates that
- // InputStreamLayoutBuilder attempts to recover from the error.
- InputStreamLayout expected;
- {
- expected.SetTopology(RHI::PrimitiveTopology::TriangleList);
- for (uint32_t i = 0; i < maxBuffers; ++i)
- {
- RHI::StreamChannelDescriptor positionDescriptor;
- positionDescriptor.m_bufferIndex = i;
- positionDescriptor.m_byteOffset = 0;
- positionDescriptor.m_format = RHI::Format::R32G32_FLOAT;
- positionDescriptor.m_semantic = ShaderSemantic{ "UV", i };
- expected.AddStreamChannel(positionDescriptor);
- RHI::StreamBufferDescriptor bufferDescriptor;
- bufferDescriptor.m_byteStride = 2 * sizeof(float);
- expected.AddStreamBuffer(bufferDescriptor);
- }
- expected.Finalize();
- }
- InputStreamLayout actual;
- {
- RHI::InputStreamLayoutBuilder layoutBuilder;
- for (uint32_t i = 0; i < maxBuffers; ++i)
- {
- layoutBuilder.AddBuffer()->Channel(ShaderSemantic{ "UV", i }, RHI::Format::R32G32_FLOAT);
- }
- AZ_TEST_START_ASSERTTEST;
- // Registering a channel on the failed buffer should not crash, is ignored.
- layoutBuilder.AddBuffer()->Channel(ShaderSemantic{ "UV", maxBuffers }, RHI::Format::R32G32_FLOAT);
- AZ_TEST_STOP_ASSERTTEST(1);
- actual = layoutBuilder.End();
- }
- ExpectEq(expected, actual);
- }
- }
|