diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 4ab0ef0..7b1b633 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -46,6 +46,10 @@ jobs: -DGFX_ENABLE_${{ matrix.enable-glfw }} -DGFX_ENABLE_${{ matrix.enable-imgui }} -DGFX_BUILD_${{ matrix.build-examples }} + -DGFX_BUILD_TESTS=ON - name: Build run: cmake --build build --config ${{ matrix.build-type }} --parallel + + - name: Test + run: ctest --test-dir build diff --git a/.github/workflows/macos-both.yml b/.github/workflows/macos-both.yml index 3186f0c..c0d6432 100644 --- a/.github/workflows/macos-both.yml +++ b/.github/workflows/macos-both.yml @@ -40,6 +40,10 @@ jobs: -DGFX_ENABLE_${{ matrix.enable-glfw }} -DGFX_ENABLE_${{ matrix.enable-imgui }} -DGFX_BUILD_${{ matrix.build-examples }} + -DGFX_BUILD_TESTS=ON - name: Build run: cmake --build build --config ${{ matrix.build-type }} --parallel + + - name: Test + run: ctest --test-dir build diff --git a/.github/workflows/macos-metal.yml b/.github/workflows/macos-metal.yml index 8083053..1893916 100644 --- a/.github/workflows/macos-metal.yml +++ b/.github/workflows/macos-metal.yml @@ -40,6 +40,10 @@ jobs: -DGFX_ENABLE_${{ matrix.enable-glfw }} -DGFX_ENABLE_${{ matrix.enable-imgui }} -DGFX_BUILD_${{ matrix.build-examples }} + -DGFX_BUILD_TESTS=ON - name: Build run: cmake --build build --config ${{ matrix.build-type }} --parallel + + - name: Test + run: ctest --test-dir build diff --git a/.github/workflows/macos-vulkan.yml b/.github/workflows/macos-vulkan.yml index 9febf20..cae767b 100644 --- a/.github/workflows/macos-vulkan.yml +++ b/.github/workflows/macos-vulkan.yml @@ -40,6 +40,10 @@ jobs: -DGFX_ENABLE_${{ matrix.enable-glfw }} -DGFX_ENABLE_${{ matrix.enable-imgui }} -DGFX_BUILD_${{ matrix.build-examples }} + -DGFX_BUILD_TESTS=ON - name: Build run: cmake --build build --config ${{ matrix.build-type }} --parallel + + - name: Test + run: ctest --test-dir build diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 9f4f9a5..2b877f8 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -39,6 +39,10 @@ jobs: -DGFX_ENABLE_${{ matrix.enable-glfw }} -DGFX_ENABLE_${{ matrix.enable-imgui }} -DGFX_BUILD_${{ matrix.build-examples }} + -DGFX_BUILD_TESTS=ON - name: Build run: cmake --build build --config ${{ matrix.build-type }} --parallel + + - name: Test + run: ctest --test-dir build diff --git a/CMakeLists.txt b/CMakeLists.txt index 04cbfec..4a56ed7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ option(GFX_ENABLE_IMGUI "Build with imgui capabilities" OFF) option(GFX_ENABLE_GLFW "Build with glfw capabilities" OFF) option(GFX_BUILD_EXAMPLES "Build Graphics examples executables" OFF) option(GFX_BUILD_TRACY "Build the tracy client" OFF) +option(GFX_BUILD_TESTS "Build the tests" OFF) option(GFX_INSTALL "Enable the install command" ON) if(GFX_BUILD_EXAMPLES) @@ -216,6 +217,11 @@ if(GFX_BUILD_EXAMPLES) add_subdirectory("examples") endif() +if (GFX_BUILD_TESTS) + enable_testing() # need to be in the top level cmakelists + add_subdirectory("tests") +endif() + if(GFX_INSTALL) install(TARGETS Graphics RUNTIME DESTINATION "bin" diff --git a/include/Graphics/Buffer.hpp b/include/Graphics/Buffer.hpp index 2ccc2f8..e57daf3 100644 --- a/include/Graphics/Buffer.hpp +++ b/include/Graphics/Buffer.hpp @@ -25,6 +25,8 @@ class Buffer size_t size = 0; BufferUsages usages = BufferUsage::uniformBuffer; ResourceStorageMode storageMode = ResourceStorageMode::hostVisible; + + auto operator<=>(const Descriptor&) const = default; }; public: diff --git a/include/Graphics/Device.hpp b/include/Graphics/Device.hpp index f5f3960..957e30c 100644 --- a/include/Graphics/Device.hpp +++ b/include/Graphics/Device.hpp @@ -36,6 +36,7 @@ class Device struct Descriptor { QueueCapabilities queueCaps; + auto operator<=>(const Descriptor&) const = default; }; public: diff --git a/include/Graphics/Enums.hpp b/include/Graphics/Enums.hpp index bfa87b3..4ee9a64 100644 --- a/include/Graphics/Enums.hpp +++ b/include/Graphics/Enums.hpp @@ -14,6 +14,7 @@ #include #include #include +#include // IWYU pragma: keep namespace gfx { @@ -29,9 +30,7 @@ class Flags [[nodiscard]] constexpr inline T value() const { return m_value; } - [[nodiscard]] constexpr inline bool operator==(const Flags& rhs) const { return m_value == rhs.m_value; } - [[nodiscard]] constexpr inline bool operator!=(const Flags& rhs) const { return m_value != rhs.m_value; } - [[nodiscard]] constexpr inline bool operator<(const Flags& rhs) const { return m_value < rhs.m_value; } + [[nodiscard]] constexpr inline auto operator<=>(const Flags& rhs) const = default; [[nodiscard]] constexpr inline Flags operator|(const Flags& rhs) const { return Flags(m_value | rhs.m_value); } [[nodiscard]] constexpr inline Flags operator&(const Flags& rhs) const { return Flags(m_value & rhs.m_value); } diff --git a/include/Graphics/GraphicsPipeline.hpp b/include/Graphics/GraphicsPipeline.hpp index 555bdb3..2a55fe7 100644 --- a/include/Graphics/GraphicsPipeline.hpp +++ b/include/Graphics/GraphicsPipeline.hpp @@ -10,7 +10,6 @@ #ifndef GRAPHICSPIPELINE_HPP #define GRAPHICSPIPELINE_HPP -#include "Graphics/ParameterBlock.hpp" #include "Graphics/ShaderFunction.hpp" #include "Graphics/Enums.hpp" #include "Graphics/VertexLayout.hpp" @@ -40,6 +39,8 @@ class GraphicsPipeline CullMode cullMode = CullMode::none; std::vector> parameterBlockLayouts; + + auto operator<=>(const Descriptor&) const = default; }; public: diff --git a/include/Graphics/Instance.hpp b/include/Graphics/Instance.hpp index 466eb6a..8f6c547 100644 --- a/include/Graphics/Instance.hpp +++ b/include/Graphics/Instance.hpp @@ -33,6 +33,8 @@ class Instance std::array appVersion; std::string engineName; std::array engineVersion; + + auto operator<=>(const Descriptor&) const = default; }; public: diff --git a/include/Graphics/ParameterBlock.hpp b/include/Graphics/ParameterBlock.hpp index 39fa514..e8215dc 100644 --- a/include/Graphics/ParameterBlock.hpp +++ b/include/Graphics/ParameterBlock.hpp @@ -10,7 +10,6 @@ #ifndef PARAMETERBLOCK_HPP #define PARAMETERBLOCK_HPP -#include "Graphics/Enums.hpp" #include "Graphics/Buffer.hpp" #include "Graphics/Texture.hpp" #include "Graphics/Sampler.hpp" diff --git a/include/Graphics/ParameterBlockLayout.hpp b/include/Graphics/ParameterBlockLayout.hpp index 96aba72..a88fe6a 100644 --- a/include/Graphics/ParameterBlockLayout.hpp +++ b/include/Graphics/ParameterBlockLayout.hpp @@ -21,6 +21,7 @@ struct ParameterBlockBinding { BindingType type = BindingType::uniformBuffer; BindingUsages usages = BindingUsage::vertexRead | BindingUsage::fragmentRead; + auto operator<=>(const ParameterBlockBinding&) const = default; }; class ParameterBlockLayout @@ -29,12 +30,13 @@ class ParameterBlockLayout struct Descriptor { std::vector bindings; + auto operator<=>(const Descriptor&) const = default; }; public: ParameterBlockLayout(const ParameterBlockLayout&) = delete; ParameterBlockLayout(ParameterBlockLayout&&) = delete; - + virtual const std::vector& bindings() const = 0; virtual ~ParameterBlockLayout() = default; diff --git a/include/Graphics/ParameterBlockPool.hpp b/include/Graphics/ParameterBlockPool.hpp index 762d347..03760c1 100644 --- a/include/Graphics/ParameterBlockPool.hpp +++ b/include/Graphics/ParameterBlockPool.hpp @@ -27,6 +27,7 @@ class ParameterBlockPool uint32_t maxUniformBuffers = 16; uint32_t maxTextures = 4; uint32_t maxSamplers = 4; + auto operator<=>(const Descriptor&) const = default; }; ParameterBlockPool(const ParameterBlockPool&) = delete; diff --git a/include/Graphics/QueueCapabilities.hpp b/include/Graphics/QueueCapabilities.hpp index 67a5493..69258cb 100644 --- a/include/Graphics/QueueCapabilities.hpp +++ b/include/Graphics/QueueCapabilities.hpp @@ -23,6 +23,8 @@ struct QueueCapabilities bool compute; bool transfer; std::vector present; + + auto operator<=>(const QueueCapabilities&) const = default; }; } diff --git a/include/Graphics/Sampler.hpp b/include/Graphics/Sampler.hpp index 919dae8..08ca9eb 100644 --- a/include/Graphics/Sampler.hpp +++ b/include/Graphics/Sampler.hpp @@ -25,6 +25,7 @@ class Sampler SamplerAddressMode rAddressMode = SamplerAddressMode::ClampToEdge; SamplerMinMagFilter minFilter = SamplerMinMagFilter::Nearest; SamplerMinMagFilter magFilter = SamplerMinMagFilter::Nearest; + auto operator<=>(const Descriptor&) const = default; }; public: diff --git a/include/Graphics/Swapchain.hpp b/include/Graphics/Swapchain.hpp index df142ef..f080c6e 100644 --- a/include/Graphics/Swapchain.hpp +++ b/include/Graphics/Swapchain.hpp @@ -31,6 +31,7 @@ class Swapchain uint32_t drawableCount = 3; PixelFormat pixelFormat = PixelFormat::BGRA8Unorm; PresentMode presentMode = PresentMode::fifo; + auto operator<=>(const Descriptor&) const = default; }; public: diff --git a/include/Graphics/Texture.hpp b/include/Graphics/Texture.hpp index 56fd9d2..ce9c070 100644 --- a/include/Graphics/Texture.hpp +++ b/include/Graphics/Texture.hpp @@ -27,6 +27,7 @@ class Texture PixelFormat pixelFormat = PixelFormat::RGBA8Unorm; TextureUsages usages = TextureUsage::shaderRead; ResourceStorageMode storageMode = ResourceStorageMode::deviceLocal; + auto operator<=>(const Descriptor&) const = default; }; public: diff --git a/include/Graphics/VertexLayout.hpp b/include/Graphics/VertexLayout.hpp index 57288f8..9910728 100644 --- a/include/Graphics/VertexLayout.hpp +++ b/include/Graphics/VertexLayout.hpp @@ -23,6 +23,7 @@ struct VertexAttribute VertexAttributeFormat format; size_t offset; // bufferIndex + auto operator<=>(const VertexAttribute&) const = default; }; struct VertexLayout @@ -31,6 +32,8 @@ struct VertexLayout // stepFunction // stepRate std::vector attributes; + + auto operator<=>(const VertexLayout&) const = default; }; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..cdafb00 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,35 @@ +# --------------------------------------------------- +# CMakeLists.txt +# +# Author: Thomas Choquet +# --------------------------------------------------- + +include(FetchContent) +include(GoogleTest) + + +add_executable(gfx_test) + +# test file only require 11, will be higher when linking to something that need higher +target_compile_features(gfx_test PUBLIC cxx_std_11) +set_target_properties(gfx_test PROPERTIES FOLDER "tests") + +file(GLOB_RECURSE SRC "*.cpp") +target_sources(gfx_test PRIVATE ${SRC}) + +target_include_directories(gfx_test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + +FetchContent_Declare(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG main + GIT_SHALLOW v1.15.2 +) +set(BUILD_GMOCK OFF) +set(INSTALL_GTEST OFF) +FetchContent_MakeAvailable(googletest) +set_target_properties(gtest PROPERTIES FOLDER "dependencies") +set_target_properties(gtest_main PROPERTIES FOLDER "dependencies") + +target_link_libraries(gfx_test PRIVATE Graphics GTest::gtest_main) + +gtest_discover_tests(gfx_test) diff --git a/tests/test_descriptor_operator.cpp b/tests/test_descriptor_operator.cpp new file mode 100644 index 0000000..b44072e --- /dev/null +++ b/tests/test_descriptor_operator.cpp @@ -0,0 +1,153 @@ +/* + * --------------------------------------------------- + * test_descriptor_operator.cpp + * + * Author: Thomas Choquet + * --------------------------------------------------- + */ + +#include "Graphics/Buffer.hpp" +#include "Graphics/Device.hpp" +#include "Graphics/GraphicsPipeline.hpp" +#include "Graphics/Instance.hpp" +#include "Graphics/ParameterBlockLayout.hpp" +#include "Graphics/ParameterBlockPool.hpp" +#include "Graphics/Sampler.hpp" +#include "Graphics/Swapchain.hpp" +#include "Graphics/Texture.hpp" + +#include + +#include + +namespace gfx_test +{ + +namespace +{ + template + void expectDescriptorComparableInMap(const T& lower, const T& higher) + { + EXPECT_TRUE(lower == lower); + EXPECT_TRUE(lower < higher); + EXPECT_TRUE(higher > lower); + + std::map values; + values.emplace(higher, 1); + values.emplace(lower, 2); + + EXPECT_EQ(values.size(), 2u); + EXPECT_EQ(values.begin()->first, lower); + EXPECT_EQ(values.begin()->second, 2); + + values[lower] = 5; + EXPECT_EQ(values.size(), 2u); + EXPECT_EQ(values.at(lower), 5); + } +} + +TEST(descriptor_operator, buffer_descriptor) +{ + gfx::Buffer::Descriptor lhs {}; + gfx::Buffer::Descriptor rhs = lhs; + rhs.size = 64; + + expectDescriptorComparableInMap(lhs, rhs); +} + +TEST(descriptor_operator, texture_descriptor) +{ + gfx::Texture::Descriptor lhs {}; + gfx::Texture::Descriptor rhs = lhs; + rhs.width = 32; + + expectDescriptorComparableInMap(lhs, rhs); +} + +TEST(descriptor_operator, sampler_descriptor) +{ + gfx::Sampler::Descriptor lhs {}; + gfx::Sampler::Descriptor rhs = lhs; + rhs.magFilter = gfx::SamplerMinMagFilter::Linear; + + expectDescriptorComparableInMap(lhs, rhs); +} + +TEST(descriptor_operator, parameter_block_layout_descriptor) +{ + gfx::ParameterBlockLayout::Descriptor lhs {}; + lhs.bindings = { + { + .type=gfx::BindingType::uniformBuffer, + .usages=gfx::BindingUsage::vertexRead + } + }; + + gfx::ParameterBlockLayout::Descriptor rhs = lhs; + rhs.bindings.push_back({ gfx::BindingType::sampler, gfx::BindingUsage::fragmentRead }); + + expectDescriptorComparableInMap(lhs, rhs); +} + +TEST(descriptor_operator, parameter_block_pool_descriptor) +{ + gfx::ParameterBlockPool::Descriptor lhs {}; + gfx::ParameterBlockPool::Descriptor rhs = lhs; + rhs.maxUniformBuffers = lhs.maxUniformBuffers + 1; + + expectDescriptorComparableInMap(lhs, rhs); +} + +TEST(descriptor_operator, swapchain_descriptor) +{ + gfx::Swapchain::Descriptor lhs {}; + gfx::Swapchain::Descriptor rhs = lhs; + rhs.width = 1280; + + expectDescriptorComparableInMap(lhs, rhs); +} + +TEST(descriptor_operator, device_descriptor) +{ + gfx::Device::Descriptor lhs {}; + lhs.queueCaps = { + .graphics=true, + .compute=false, + .transfer=false, + .present={} + }; + + gfx::Device::Descriptor rhs = lhs; + rhs.queueCaps.compute = true; + + expectDescriptorComparableInMap(lhs, rhs); +} + +TEST(descriptor_operator, instance_descriptor) +{ + gfx::Instance::Descriptor lhs { + .appName="App", + .appVersion={ 1, 0, 0 }, + .engineName="Engine", + .engineVersion={ 1, 0, 0 } + }; + gfx::Instance::Descriptor rhs = lhs; + rhs.appVersion = { 1, 0, 1 }; + + expectDescriptorComparableInMap(lhs, rhs); +} + +TEST(descriptor_operator, graphics_pipeline_descriptor) +{ + gfx::GraphicsPipeline::Descriptor lhs {}; + lhs.vertexShader = nullptr; + lhs.fragmentShader = nullptr; + lhs.cullMode = gfx::CullMode::none; + + gfx::GraphicsPipeline::Descriptor rhs = lhs; + rhs.cullMode = gfx::CullMode::back; + + expectDescriptorComparableInMap(lhs, rhs); +} + +}