Compare commits
9
Commits
3c19e0e931
..
Vulkan
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fcb2fd64c | ||
|
|
df985d0397 | ||
|
|
130ea26f4f | ||
|
|
1799ff01c4 | ||
|
|
3cde56717f | ||
|
|
cd5f7b3823 | ||
|
|
e1e16268a2 | ||
|
|
c4e9f6f7d9 | ||
|
|
6ee035843e |
+8
-13
@@ -20,7 +20,7 @@ jobs:
|
|||||||
- { value: "RelWithDebInfo", profile: "relwithdebinfo" }
|
- { value: "RelWithDebInfo", profile: "relwithdebinfo" }
|
||||||
- { value: "Release", profile: "release" }
|
- { value: "Release", profile: "release" }
|
||||||
unity_build: ["ON", "OFF"]
|
unity_build: ["ON", "OFF"]
|
||||||
conan_profile: ["./ConanProfiles/host/clang", "./ConanProfiles/host/clang_asan"]
|
conan_profile: ["clang", "clang_asan"]
|
||||||
variant:
|
variant:
|
||||||
- { value: "True", name: "toolmode" }
|
- { value: "True", name: "toolmode" }
|
||||||
- { value: "False", name: "game" }
|
- { value: "False", name: "game" }
|
||||||
@@ -36,22 +36,17 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
CONFIG_PROFILE=./ConanProfiles/Configurations/${{ matrix.build_type.profile }}
|
bash ./generate_bigfoot.sh missing ${{ matrix.build_type.value }} --profile=${{ matrix.conan_profile }} --variant=${{ matrix.variant.name }} --unity=${{ matrix.unity_build }} --tracy=False
|
||||||
if [ "${{ matrix.build_type.profile }}" = "release" ] && [[ "${{ matrix.conan_profile }}" == *asan* ]]; then
|
. ./build-linux-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/conanbuild.sh
|
||||||
CONFIG_PROFILE=./ConanProfiles/Configurations/release_noipo
|
cmake --build build-linux-${{ matrix.variant.name }}/${{ matrix.build_type.value }} --parallel $(nproc)
|
||||||
fi
|
. ./build-linux-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/deactivate_conanbuild.sh
|
||||||
conan install . --remote=bigfootpackages -pr:h=${{ matrix.conan_profile }} -pr:h=$CONFIG_PROFILE -pr:b=./ConanProfiles/build/clang -pr:b=$CONFIG_PROFILE --build=missing -o bigfoot/*:build_tests=True -o bigfoot/*:build_benchmarks=True -o bigfoot/*:tracy=False -o bigfoot/*:vulkan=True -o bigfoot/*:toolmode=${{ matrix.variant.value }} -of build-${{ matrix.variant.name }}
|
|
||||||
. ./build-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/conanbuild.sh
|
|
||||||
cmake -S . -B ./build-${{ matrix.variant.name }}/${{ matrix.build_type.value }} --toolchain ./build-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type.value }} -DCMAKE_UNITY_BUILD=${{ matrix.unity_build }} -G "Ninja"
|
|
||||||
cmake --build build-${{ matrix.variant.name }}/${{ matrix.build_type.value }} --parallel $(nproc)
|
|
||||||
. ./build-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/deactivate_conanbuild.sh
|
|
||||||
|
|
||||||
- name: Unit Tests
|
- name: Unit Tests
|
||||||
run: |
|
run: |
|
||||||
cd ./build-${{ matrix.variant.name }}/${{ matrix.build_type.value }}
|
cd ./build-linux-${{ matrix.variant.name }}/${{ matrix.build_type.value }}
|
||||||
. ../../build-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/conanbuild.sh
|
. ../../build-linux-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/conanbuild.sh
|
||||||
weston-run ctest . --output-on-failure
|
weston-run ctest . --output-on-failure
|
||||||
. ../../build-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/deactivate_conanbuild.sh
|
. ../../build-linux-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/deactivate_conanbuild.sh
|
||||||
|
|
||||||
clang-format:
|
clang-format:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -42,24 +42,23 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
conan install . --remote=bigfootpackages -pr:h=./ConanProfiles/host/clang_coverage -pr:b=./ConanProfiles/build/clang --build=missing -s build_type=Debug -o bigfoot/*:build_tests=True -o bigfoot/*:build_benchmarks=True -o bigfoot/*:tracy=False -o bigfoot/*:toolmode=${{ matrix.variant.value }} -o bigfoot/*:vulkan=True -of build-${{ matrix.variant.name }}
|
bash ./generate_bigfoot.sh missing Debug --profile=clang_coverage --variant=${{ matrix.variant.name }} --tracy=False
|
||||||
. ./build-${{ matrix.variant.name }}/build/Debug/generators/conanbuild.sh
|
. ./build-linux-${{ matrix.variant.name }}/build/Debug/generators/conanbuild.sh
|
||||||
cmake -S . -B ./build-${{ matrix.variant.name }}/Debug --toolchain ./build-${{ matrix.variant.name }}/build/Debug/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -G "Ninja"
|
cmake --build build-linux-${{ matrix.variant.name }}/Debug --parallel $(nproc)
|
||||||
cmake --build build-${{ matrix.variant.name }}/Debug --parallel $(nproc)
|
. ./build-linux-${{ matrix.variant.name }}/build/Debug/generators/deactivate_conanbuild.sh
|
||||||
. ./build-${{ matrix.variant.name }}/build/Debug/generators/deactivate_conanbuild.sh
|
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: |
|
run: |
|
||||||
cd ./build-${{ matrix.variant.name }}/Debug
|
cd ./build-linux-${{ matrix.variant.name }}/Debug
|
||||||
. ../../build-${{ matrix.variant.name }}/build/Debug/generators/conanbuild.sh
|
. ../../build-linux-${{ matrix.variant.name }}/build/Debug/generators/conanbuild.sh
|
||||||
LLVM_PROFILE_FILE="%p.profraw%c" weston-run ctest --output-on-failure
|
LLVM_PROFILE_FILE="%p.profraw%c" weston-run ctest --output-on-failure
|
||||||
. ../../build-${{ matrix.variant.name }}/build/Debug/generators/deactivate_conanbuild.sh
|
. ../../build-linux-${{ matrix.variant.name }}/build/Debug/generators/deactivate_conanbuild.sh
|
||||||
|
|
||||||
- name: Clang-Tidy
|
- name: Clang-Tidy
|
||||||
run: run-clang-tidy -p ./build-${{ matrix.variant.name }}/Debug/ > tidy_result.txt
|
run: run-clang-tidy -p ./build-linux-${{ matrix.variant.name }}/Debug/ > tidy_result.txt
|
||||||
|
|
||||||
- name: Infer
|
- name: Infer
|
||||||
run: infer run --compilation-database build-${{ matrix.variant.name }}/Debug/compile_commands.json
|
run: infer run --compilation-database build-linux-${{ matrix.variant.name }}/Debug/compile_commands.json
|
||||||
|
|
||||||
- name: Generate coverage report
|
- name: Generate coverage report
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -69,8 +68,8 @@ jobs:
|
|||||||
# rejects outright ("Wrong major version"). Bypassing gcovr's JSON
|
# rejects outright ("Wrong major version"). Bypassing gcovr's JSON
|
||||||
# path entirely: llvm-cov's lcov exporter is a separate, unaffected
|
# path entirely: llvm-cov's lcov exporter is a separate, unaffected
|
||||||
# code path, so merge -> export lcov -> convert lcov to Cobertura.
|
# code path, so merge -> export lcov -> convert lcov to Cobertura.
|
||||||
llvm-profdata merge -sparse $(find build-${{ matrix.variant.name }}/Debug -name "*.profraw") -o merged.profdata
|
llvm-profdata merge -sparse $(find build-linux-${{ matrix.variant.name }}/Debug -name "*.profraw") -o merged.profdata
|
||||||
BINARIES=($(find build-${{ matrix.variant.name }}/Debug -maxdepth 8 -type f -executable -iname "*Tests"))
|
BINARIES=($(find build-linux-${{ matrix.variant.name }}/Debug -maxdepth 8 -type f -executable -iname "*Tests"))
|
||||||
OBJECT_ARGS=$(printf -- '-object %s ' "${BINARIES[@]:1}")
|
OBJECT_ARGS=$(printf -- '-object %s ' "${BINARIES[@]:1}")
|
||||||
llvm-cov export -format=lcov -instr-profile=merged.profdata "${BINARIES[0]}" $OBJECT_ARGS > coverage.lcov
|
llvm-cov export -format=lcov -instr-profile=merged.profdata "${BINARIES[0]}" $OBJECT_ARGS > coverage.lcov
|
||||||
# lcov_cobertura isn't preinstalled on the image; inject it into
|
# lcov_cobertura isn't preinstalled on the image; inject it into
|
||||||
@@ -85,8 +84,8 @@ jobs:
|
|||||||
-Dsonar.projectKey=${{ matrix.variant.projectKey }}
|
-Dsonar.projectKey=${{ matrix.variant.projectKey }}
|
||||||
"-Dsonar.projectName=${{ matrix.variant.projectName }}"
|
"-Dsonar.projectName=${{ matrix.variant.projectName }}"
|
||||||
-Dsonar.projectVersion=${{ steps.version.outputs.version }}
|
-Dsonar.projectVersion=${{ steps.version.outputs.version }}
|
||||||
-Dsonar.cxx.jsonCompilationDatabase=./build-${{ matrix.variant.name }}/Debug/compile_commands.json
|
-Dsonar.cxx.jsonCompilationDatabase=./build-linux-${{ matrix.variant.name }}/Debug/compile_commands.json
|
||||||
-Dsonar.cxx.xunit.reportPaths=build-${{ matrix.variant.name }}/Debug/TestResults/*.xml
|
-Dsonar.cxx.xunit.reportPaths=build-linux-${{ matrix.variant.name }}/Debug/TestResults/*.xml
|
||||||
-Dsonar.qualitygate.wait=true
|
-Dsonar.qualitygate.wait=true
|
||||||
${{ github.event_name == 'pull_request' &&
|
${{ github.event_name == 'pull_request' &&
|
||||||
format('-Dsonar.pullrequest.key={0} -Dsonar.pullrequest.branch={1} -Dsonar.pullrequest.base={2} -Dsonar.analysis.sqbot={3}',
|
format('-Dsonar.pullrequest.key={0} -Dsonar.pullrequest.branch={1} -Dsonar.pullrequest.base={2} -Dsonar.analysis.sqbot={3}',
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class ReferenceFixture: public benchmark::Fixture
|
|||||||
|
|
||||||
void TearDown(benchmark::State&) override
|
void TearDown(benchmark::State&) override
|
||||||
{
|
{
|
||||||
SetActiveAssetLibrary(&g_assetLibrary);
|
SetActiveAssetLibrary(g_assetLibrary);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetLibrary m_library;
|
AssetLibrary m_library;
|
||||||
|
|||||||
@@ -19,13 +19,14 @@
|
|||||||
return AssetType::GetTypeID(); \
|
return AssetType::GetTypeID(); \
|
||||||
} \
|
} \
|
||||||
AssetContainer<AssetType> g_containerFor##AssetName; \
|
AssetContainer<AssetType> g_containerFor##AssetName; \
|
||||||
const bool g_insertedContainerFor##AssetName = []() \
|
bool RegisterAssetContainerFor##AssetName() \
|
||||||
{ \
|
{ \
|
||||||
const bool inserted = g_assetLibrary.Insert(&g_containerFor##AssetName); \
|
const bool inserted = g_assetLibrary->Insert(&g_containerFor##AssetName); \
|
||||||
CRITICAL_ASSERT(EngineAssertHandler, \
|
CRITICAL_ASSERT(EngineAssertHandler, \
|
||||||
inserted, \
|
inserted, \
|
||||||
"AssetTypeID collision or duplicate registration for asset type '" #AssetName "'"); \
|
"AssetTypeID collision or duplicate registration for asset type '" #AssetName "'"); \
|
||||||
return inserted; \
|
return inserted; \
|
||||||
}(); \
|
} \
|
||||||
|
const bool g_insertedContainerFor##AssetName = RegisterAssetContainerFor##AssetName(); \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#include <Engine/Asset/AssetContainer.hpp>
|
#include <Engine/Asset/AssetContainer.hpp>
|
||||||
#include <Engine/Asset/AssetTypeID.hpp>
|
#include <Engine/Asset/AssetTypeID.hpp>
|
||||||
|
|
||||||
|
#include <Utils/LazyGlobal.hpp>
|
||||||
|
|
||||||
#include <ankerl/unordered_dense.h>
|
#include <ankerl/unordered_dense.h>
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
@@ -109,8 +111,44 @@ class AssetLibrary
|
|||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
// The global asset library for Bigfoot
|
// The global asset library for Bigfoot
|
||||||
inline AssetLibrary g_assetLibrary;
|
inline LazyGlobal<AssetLibrary> g_assetLibrary;
|
||||||
inline AssetLibrary* g_activeAssetLibrary = &g_assetLibrary;
|
|
||||||
|
class ActiveAssetLibrary
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ActiveAssetLibrary& operator=(AssetLibrary* p_assetLibrary)
|
||||||
|
{
|
||||||
|
Get() = p_assetLibrary;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
AssetLibrary* operator->() const
|
||||||
|
{
|
||||||
|
return Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
operator AssetLibrary*() const
|
||||||
|
{
|
||||||
|
return Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Get the ActiveAssetLibrary
|
||||||
|
*
|
||||||
|
* \return The ActiveAssetLibrary
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
static AssetLibrary*& Get()
|
||||||
|
{
|
||||||
|
static AssetLibrary* activeLibrary = g_assetLibrary;
|
||||||
|
return activeLibrary;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline ActiveAssetLibrary g_activeAssetLibrary;
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file GraphicsContext.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <GraphicsCore/GraphicsContext.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsCore/GraphicsCoreAssertHandler.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
GraphicsContext::GraphicsContext(const GraphicsContextCreateInfo& p_createInfo)
|
||||||
|
{
|
||||||
|
m_instance = g_graphicsInstanceFactory->Create(p_createInfo.m_api,
|
||||||
|
p_createInfo.m_applicationName,
|
||||||
|
p_createInfo.m_applicationVersion);
|
||||||
|
CRITICAL_ASSERT(GraphicsCoreAssertHandler,
|
||||||
|
m_instance != nullptr,
|
||||||
|
"No graphics instance registered for GraphicsAPI '{}'",
|
||||||
|
EnumNameGraphicsAPI(p_createInfo.m_api));
|
||||||
|
|
||||||
|
m_surface = g_graphicsSurfaceFactory->Create(p_createInfo.m_api, *m_instance, p_createInfo.m_surfaceCreateInfo);
|
||||||
|
CRITICAL_ASSERT(GraphicsCoreAssertHandler,
|
||||||
|
m_surface != nullptr,
|
||||||
|
"No graphics surface registered for GraphicsAPI '{}'",
|
||||||
|
EnumNameGraphicsAPI(p_createInfo.m_api));
|
||||||
|
|
||||||
|
const DeviceCreateInfo deviceCreateInfo {p_createInfo.m_deviceNameHint, m_surface.get()};
|
||||||
|
m_device = g_graphicsDeviceFactory->Create(p_createInfo.m_api, *m_instance, deviceCreateInfo);
|
||||||
|
CRITICAL_ASSERT(GraphicsCoreAssertHandler,
|
||||||
|
m_device != nullptr,
|
||||||
|
"No graphics device registered for GraphicsAPI '{}'",
|
||||||
|
EnumNameGraphicsAPI(p_createInfo.m_api));
|
||||||
|
|
||||||
|
const SwapchainCreateInfo swapchainCreateInfo {m_device.get(), m_surface.get(), p_createInfo.m_extent};
|
||||||
|
m_swapchain = g_graphicsSwapchainFactory->Create(p_createInfo.m_api, swapchainCreateInfo);
|
||||||
|
CRITICAL_ASSERT(GraphicsCoreAssertHandler,
|
||||||
|
m_swapchain != nullptr,
|
||||||
|
"No graphics swapchain registered for GraphicsAPI '{}'",
|
||||||
|
EnumNameGraphicsAPI(p_createInfo.m_api));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
GraphicsInstance& GraphicsContext::GetInstance() const
|
||||||
|
{
|
||||||
|
return *m_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
GraphicsSurface& GraphicsContext::GetSurface() const
|
||||||
|
{
|
||||||
|
return *m_surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
GraphicsDevice& GraphicsContext::GetDevice() const
|
||||||
|
{
|
||||||
|
return *m_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
GraphicsSwapchain& GraphicsContext::GetSwapchain() const
|
||||||
|
{
|
||||||
|
return *m_swapchain;
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file GraphicsContext.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_GRAPHICSCORE_GRAPHICSCONTEXT_HPP
|
||||||
|
#define BIGFOOT_GRAPHICSCORE_GRAPHICSCONTEXT_HPP
|
||||||
|
#include <GraphicsInterface/GraphicsDevice.hpp>
|
||||||
|
#include <GraphicsInterface/GraphicsInstance.hpp>
|
||||||
|
#include <GraphicsInterface/GraphicsSurface.hpp>
|
||||||
|
#include <GraphicsInterface/GraphicsSwapchain.hpp>
|
||||||
|
|
||||||
|
#include <Utils/Version.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsInterface/GraphicsAPI_generated.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/string_view.h>
|
||||||
|
#include <EASTL/unique_ptr.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
struct GraphicsContextCreateInfo
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The graphics API to use
|
||||||
|
*/
|
||||||
|
GraphicsAPI m_api = GraphicsAPI::Vulkan;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the application
|
||||||
|
*/
|
||||||
|
eastl::string_view m_applicationName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version of the application
|
||||||
|
*/
|
||||||
|
Version m_applicationVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The native window handles
|
||||||
|
*/
|
||||||
|
SurfaceCreateInfo m_surfaceCreateInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pick a specific physical device by name.
|
||||||
|
*/
|
||||||
|
eastl::string_view m_deviceNameHint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The desired size of the swapchain images.
|
||||||
|
*/
|
||||||
|
glm::uvec2 m_extent = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class GraphicsContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* \param p_createInfo The create info
|
||||||
|
*/
|
||||||
|
explicit GraphicsContext(const GraphicsContextCreateInfo& p_createInfo);
|
||||||
|
|
||||||
|
GraphicsContext(const GraphicsContext& p_context) = delete;
|
||||||
|
GraphicsContext(GraphicsContext&& p_context) = delete;
|
||||||
|
|
||||||
|
GraphicsContext& operator=(const GraphicsContext& p_context) = delete;
|
||||||
|
GraphicsContext& operator=(GraphicsContext&& p_context) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the graphics instance
|
||||||
|
*
|
||||||
|
* \return The graphics instance
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
GraphicsInstance& GetInstance() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the graphics surface
|
||||||
|
*
|
||||||
|
* \return The graphics surface
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
GraphicsSurface& GetSurface() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the graphics device
|
||||||
|
*
|
||||||
|
* \return The graphics device
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
GraphicsDevice& GetDevice() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the graphics swapchain
|
||||||
|
*
|
||||||
|
* \return The graphics swapchain
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
GraphicsSwapchain& GetSwapchain() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* The graphics instance.
|
||||||
|
*/
|
||||||
|
eastl::unique_ptr<GraphicsInstance> m_instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The graphics surface.
|
||||||
|
*/
|
||||||
|
eastl::unique_ptr<GraphicsSurface> m_surface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The graphics device.
|
||||||
|
*/
|
||||||
|
eastl::unique_ptr<GraphicsDevice> m_device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The graphics swapchain.
|
||||||
|
*/
|
||||||
|
eastl::unique_ptr<GraphicsSwapchain> m_swapchain;
|
||||||
|
};
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file GraphicsDevice.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSDEVICE_HPP
|
||||||
|
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSDEVICE_HPP
|
||||||
|
#include <GraphicsInterface/GraphicsInstance.hpp>
|
||||||
|
#include <GraphicsInterface/GraphicsQueue.hpp>
|
||||||
|
#include <GraphicsInterface/GraphicsSurface.hpp>
|
||||||
|
|
||||||
|
#include <Utils/Factory.hpp>
|
||||||
|
#include <Utils/LazyGlobal.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsInterface/GraphicsAPI_generated.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/functional.h>
|
||||||
|
#include <EASTL/string_view.h>
|
||||||
|
#include <EASTL/unique_ptr.h>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
|
||||||
|
struct DeviceCreateInfo
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* When empty, the most suitable discrete GPU is preferred.
|
||||||
|
*/
|
||||||
|
eastl::string_view m_deviceNameHint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The surface the device must be able to present to.
|
||||||
|
*/
|
||||||
|
const GraphicsSurface* m_surface = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GraphicsDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~GraphicsDevice() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a queue of the given type
|
||||||
|
*
|
||||||
|
* \param p_type The kind of work the queue should support
|
||||||
|
* \return The queue, or nullptr if the device has no queue of this type
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual const GraphicsQueue* GetQueue(GraphicsQueueType p_type) const = 0;
|
||||||
|
|
||||||
|
GraphicsDevice(const GraphicsDevice& p_device) = delete;
|
||||||
|
GraphicsDevice(GraphicsDevice&& p_device) = delete;
|
||||||
|
|
||||||
|
GraphicsDevice& operator=(const GraphicsDevice& p_device) = delete;
|
||||||
|
GraphicsDevice& operator=(GraphicsDevice&& p_device) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
GraphicsDevice() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
using GraphicsDeviceFactory =
|
||||||
|
Factory<GraphicsDevice,
|
||||||
|
GraphicsAPI,
|
||||||
|
eastl::function<eastl::unique_ptr<GraphicsDevice>(const GraphicsInstance&, const DeviceCreateInfo&)>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The global factory graphics libraries register themselves into, keyed by GraphicsAPI
|
||||||
|
*/
|
||||||
|
inline LazyGlobal<GraphicsDeviceFactory> g_graphicsDeviceFactory;
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file GraphicsImage.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSIMAGE_HPP
|
||||||
|
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSIMAGE_HPP
|
||||||
|
#include <GraphicsInterface/PixelFormat_generated.hpp>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
class GraphicsImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~GraphicsImage() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the pixel format of the image
|
||||||
|
*
|
||||||
|
* \return The image format
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual PixelFormat GetFormat() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of the image
|
||||||
|
*
|
||||||
|
* \return The image extent, in pixels
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual glm::uvec2 GetExtent() const = 0;
|
||||||
|
|
||||||
|
GraphicsImage(const GraphicsImage& p_image) = delete;
|
||||||
|
GraphicsImage(GraphicsImage&& p_image) = delete;
|
||||||
|
|
||||||
|
GraphicsImage& operator=(const GraphicsImage& p_image) = delete;
|
||||||
|
GraphicsImage& operator=(GraphicsImage&& p_image) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
GraphicsImage() = default;
|
||||||
|
};
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINSTANCE_HPP
|
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINSTANCE_HPP
|
||||||
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINSTANCE_HPP
|
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINSTANCE_HPP
|
||||||
#include <Utils/Factory.hpp>
|
#include <Utils/Factory.hpp>
|
||||||
|
#include <Utils/LazyGlobal.hpp>
|
||||||
#include <Utils/Version.hpp>
|
#include <Utils/Version.hpp>
|
||||||
|
|
||||||
#include <GraphicsInterface/GraphicsAPI_generated.hpp>
|
#include <GraphicsInterface/GraphicsAPI_generated.hpp>
|
||||||
@@ -38,6 +39,10 @@ using GraphicsInstanceFactory =
|
|||||||
Factory<GraphicsInstance,
|
Factory<GraphicsInstance,
|
||||||
GraphicsAPI,
|
GraphicsAPI,
|
||||||
eastl::function<eastl::unique_ptr<GraphicsInstance>(eastl::string_view, Version)>>;
|
eastl::function<eastl::unique_ptr<GraphicsInstance>(eastl::string_view, Version)>>;
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
inline LazyGlobal<GraphicsInstanceFactory> g_graphicsInstanceFactory;
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-11
@@ -6,20 +6,10 @@
|
|||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSQUEUE_HPP
|
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSQUEUE_HPP
|
||||||
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSQUEUE_HPP
|
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSQUEUE_HPP
|
||||||
|
#include <GraphicsInterface/GraphicsQueueType_generated.hpp>
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* The kind of work a GraphicsQueue submit
|
|
||||||
*/
|
|
||||||
enum class GraphicsQueueType
|
|
||||||
{
|
|
||||||
Graphics,
|
|
||||||
Compute,
|
|
||||||
Transfer,
|
|
||||||
Present
|
|
||||||
};
|
|
||||||
|
|
||||||
class GraphicsQueue
|
class GraphicsQueue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Bigfoot;
|
||||||
|
|
||||||
|
enum GraphicsQueueType: byte
|
||||||
|
{
|
||||||
|
Graphics,
|
||||||
|
Compute,
|
||||||
|
Transfer,
|
||||||
|
Present
|
||||||
|
}
|
||||||
+83
@@ -0,0 +1,83 @@
|
|||||||
|
// automatically generated by the FlatBuffers compiler, do not modify
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_GENERATED_GRAPHICSQUEUETYPE_BIGFOOT_H_
|
||||||
|
#define FLATBUFFERS_GENERATED_GRAPHICSQUEUETYPE_BIGFOOT_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/flatbuffers.h"
|
||||||
|
|
||||||
|
// Ensure the included flatbuffers.h is the same version as when this file was
|
||||||
|
// generated, otherwise it may not be compatible.
|
||||||
|
static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
||||||
|
FLATBUFFERS_VERSION_MINOR == 12 &&
|
||||||
|
FLATBUFFERS_VERSION_REVISION == 19,
|
||||||
|
"Non-compatible flatbuffers version included");
|
||||||
|
// Ensure the included flatbuffers.h is Bigfoot's fork - stock
|
||||||
|
// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.
|
||||||
|
#ifndef FLATBUFFERS_BIGFOOT_VERSION
|
||||||
|
#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible"
|
||||||
|
#endif
|
||||||
|
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
|
||||||
|
"Non-compatible Bigfoot flatbuffers fork version included");
|
||||||
|
|
||||||
|
#include "EASTL/unique_ptr.h"
|
||||||
|
#include "EASTL/string.h"
|
||||||
|
#include "EASTL/vector.h"
|
||||||
|
|
||||||
|
namespace Bigfoot {
|
||||||
|
|
||||||
|
enum class GraphicsQueueType : int8_t {
|
||||||
|
Graphics = 0,
|
||||||
|
Compute = 1,
|
||||||
|
Transfer = 2,
|
||||||
|
Present = 3,
|
||||||
|
MIN = Graphics,
|
||||||
|
MAX = Present
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const GraphicsQueueType (&EnumValuesGraphicsQueueType())[4] {
|
||||||
|
static const GraphicsQueueType values[] = {
|
||||||
|
GraphicsQueueType::Graphics,
|
||||||
|
GraphicsQueueType::Compute,
|
||||||
|
GraphicsQueueType::Transfer,
|
||||||
|
GraphicsQueueType::Present
|
||||||
|
};
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char * const *EnumNamesGraphicsQueueType() {
|
||||||
|
static const char * const names[5] = {
|
||||||
|
"Graphics",
|
||||||
|
"Compute",
|
||||||
|
"Transfer",
|
||||||
|
"Present",
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char *EnumNameGraphicsQueueType(GraphicsQueueType e) {
|
||||||
|
if (::flatbuffers::IsOutRange(e, GraphicsQueueType::Graphics, GraphicsQueueType::Present)) return "";
|
||||||
|
const size_t index = static_cast<size_t>(e);
|
||||||
|
return EnumNamesGraphicsQueueType()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const ::flatbuffers::TypeTable *GraphicsQueueTypeTypeTable() {
|
||||||
|
static const ::flatbuffers::TypeCode type_codes[] = {
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 }
|
||||||
|
};
|
||||||
|
static const ::flatbuffers::TypeFunction type_refs[] = {
|
||||||
|
Bigfoot::GraphicsQueueTypeTypeTable
|
||||||
|
};
|
||||||
|
static const ::flatbuffers::TypeTable tt = {
|
||||||
|
::flatbuffers::ST_ENUM, 4, type_codes, type_refs, nullptr, nullptr, nullptr
|
||||||
|
};
|
||||||
|
return &tt;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_GENERATED_GRAPHICSQUEUETYPE_BIGFOOT_H_
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <GraphicsInterface/GraphicsInstance.hpp>
|
#include <GraphicsInterface/GraphicsInstance.hpp>
|
||||||
|
|
||||||
#include <Utils/Factory.hpp>
|
#include <Utils/Factory.hpp>
|
||||||
|
#include <Utils/LazyGlobal.hpp>
|
||||||
#include <Utils/TargetMacros.h>
|
#include <Utils/TargetMacros.h>
|
||||||
|
|
||||||
#include <GraphicsInterface/GraphicsAPI_generated.hpp>
|
#include <GraphicsInterface/GraphicsAPI_generated.hpp>
|
||||||
@@ -60,6 +61,10 @@ using GraphicsSurfaceFactory =
|
|||||||
Factory<GraphicsSurface,
|
Factory<GraphicsSurface,
|
||||||
GraphicsAPI,
|
GraphicsAPI,
|
||||||
eastl::function<eastl::unique_ptr<GraphicsSurface>(const GraphicsInstance&, const SurfaceCreateInfo&)>>;
|
eastl::function<eastl::unique_ptr<GraphicsSurface>(const GraphicsInstance&, const SurfaceCreateInfo&)>>;
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
inline LazyGlobal<GraphicsSurfaceFactory> g_graphicsSurfaceFactory;
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file GraphicsSwapchain.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSSWAPCHAIN_HPP
|
||||||
|
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSSWAPCHAIN_HPP
|
||||||
|
#include <GraphicsInterface/GraphicsDevice.hpp>
|
||||||
|
#include <GraphicsInterface/GraphicsImage.hpp>
|
||||||
|
#include <GraphicsInterface/GraphicsInstance.hpp>
|
||||||
|
#include <GraphicsInterface/GraphicsSurface.hpp>
|
||||||
|
|
||||||
|
#include <Utils/Factory.hpp>
|
||||||
|
#include <Utils/LazyGlobal.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsInterface/GraphicsAPI_generated.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/functional.h>
|
||||||
|
#include <EASTL/unique_ptr.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
struct SwapchainCreateInfo
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The device to create the swapchain from. Must be able to present to m_surface.
|
||||||
|
*/
|
||||||
|
const GraphicsDevice* m_device = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The surface the swapchain will present to.
|
||||||
|
*/
|
||||||
|
const GraphicsSurface* m_surface = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The desired size of the swapchain images.
|
||||||
|
*/
|
||||||
|
glm::uvec2 m_extent = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class GraphicsSwapchain
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~GraphicsSwapchain() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of images owned by the swapchain
|
||||||
|
*
|
||||||
|
* \return The image count
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual std::uint32_t GetImageCount() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get one of the images owned by the swapchain
|
||||||
|
*
|
||||||
|
* \param p_index The index of the image to get.
|
||||||
|
* \return The image
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual const GraphicsImage& GetImage(std::uint32_t p_index) const = 0;
|
||||||
|
|
||||||
|
GraphicsSwapchain(const GraphicsSwapchain& p_swapchain) = delete;
|
||||||
|
GraphicsSwapchain(GraphicsSwapchain&& p_swapchain) = delete;
|
||||||
|
|
||||||
|
GraphicsSwapchain& operator=(const GraphicsSwapchain& p_swapchain) = delete;
|
||||||
|
GraphicsSwapchain& operator=(GraphicsSwapchain&& p_swapchain) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
GraphicsSwapchain() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
using GraphicsSwapchainFactory =
|
||||||
|
Factory<GraphicsSwapchain,
|
||||||
|
GraphicsAPI,
|
||||||
|
eastl::function<eastl::unique_ptr<GraphicsSwapchain>(const SwapchainCreateInfo&)>>;
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
inline LazyGlobal<GraphicsSwapchainFactory> g_graphicsSwapchainFactory;
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Bigfoot;
|
||||||
|
|
||||||
|
enum PixelFormat: byte
|
||||||
|
{
|
||||||
|
Undefined,
|
||||||
|
R8G8B8A8Unorm,
|
||||||
|
R8G8B8A8Srgb,
|
||||||
|
B8G8R8A8Unorm,
|
||||||
|
B8G8R8A8Srgb,
|
||||||
|
A2B10G10R10UnormPack32,
|
||||||
|
R16G16B16A16Sfloat
|
||||||
|
}
|
||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
// automatically generated by the FlatBuffers compiler, do not modify
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_GENERATED_PIXELFORMAT_BIGFOOT_H_
|
||||||
|
#define FLATBUFFERS_GENERATED_PIXELFORMAT_BIGFOOT_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/flatbuffers.h"
|
||||||
|
|
||||||
|
// Ensure the included flatbuffers.h is the same version as when this file was
|
||||||
|
// generated, otherwise it may not be compatible.
|
||||||
|
static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
||||||
|
FLATBUFFERS_VERSION_MINOR == 12 &&
|
||||||
|
FLATBUFFERS_VERSION_REVISION == 19,
|
||||||
|
"Non-compatible flatbuffers version included");
|
||||||
|
// Ensure the included flatbuffers.h is Bigfoot's fork - stock
|
||||||
|
// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.
|
||||||
|
#ifndef FLATBUFFERS_BIGFOOT_VERSION
|
||||||
|
#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible"
|
||||||
|
#endif
|
||||||
|
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
|
||||||
|
"Non-compatible Bigfoot flatbuffers fork version included");
|
||||||
|
|
||||||
|
#include "EASTL/unique_ptr.h"
|
||||||
|
#include "EASTL/string.h"
|
||||||
|
#include "EASTL/vector.h"
|
||||||
|
|
||||||
|
namespace Bigfoot {
|
||||||
|
|
||||||
|
enum class PixelFormat : int8_t {
|
||||||
|
Undefined = 0,
|
||||||
|
R8G8B8A8Unorm = 1,
|
||||||
|
R8G8B8A8Srgb = 2,
|
||||||
|
B8G8R8A8Unorm = 3,
|
||||||
|
B8G8R8A8Srgb = 4,
|
||||||
|
A2B10G10R10UnormPack32 = 5,
|
||||||
|
R16G16B16A16Sfloat = 6,
|
||||||
|
MIN = Undefined,
|
||||||
|
MAX = R16G16B16A16Sfloat
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const PixelFormat (&EnumValuesPixelFormat())[7] {
|
||||||
|
static const PixelFormat values[] = {
|
||||||
|
PixelFormat::Undefined,
|
||||||
|
PixelFormat::R8G8B8A8Unorm,
|
||||||
|
PixelFormat::R8G8B8A8Srgb,
|
||||||
|
PixelFormat::B8G8R8A8Unorm,
|
||||||
|
PixelFormat::B8G8R8A8Srgb,
|
||||||
|
PixelFormat::A2B10G10R10UnormPack32,
|
||||||
|
PixelFormat::R16G16B16A16Sfloat
|
||||||
|
};
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char * const *EnumNamesPixelFormat() {
|
||||||
|
static const char * const names[8] = {
|
||||||
|
"Undefined",
|
||||||
|
"R8G8B8A8Unorm",
|
||||||
|
"R8G8B8A8Srgb",
|
||||||
|
"B8G8R8A8Unorm",
|
||||||
|
"B8G8R8A8Srgb",
|
||||||
|
"A2B10G10R10UnormPack32",
|
||||||
|
"R16G16B16A16Sfloat",
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char *EnumNamePixelFormat(PixelFormat e) {
|
||||||
|
if (::flatbuffers::IsOutRange(e, PixelFormat::Undefined, PixelFormat::R16G16B16A16Sfloat)) return "";
|
||||||
|
const size_t index = static_cast<size_t>(e);
|
||||||
|
return EnumNamesPixelFormat()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const ::flatbuffers::TypeTable *PixelFormatTypeTable() {
|
||||||
|
static const ::flatbuffers::TypeCode type_codes[] = {
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 }
|
||||||
|
};
|
||||||
|
static const ::flatbuffers::TypeFunction type_refs[] = {
|
||||||
|
Bigfoot::PixelFormatTypeTable
|
||||||
|
};
|
||||||
|
static const ::flatbuffers::TypeTable tt = {
|
||||||
|
::flatbuffers::ST_ENUM, 7, type_codes, type_refs, nullptr, nullptr, nullptr
|
||||||
|
};
|
||||||
|
return &tt;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_GENERATED_PIXELFORMAT_BIGFOOT_H_
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file VulkanDevice.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANDEVICE_HPP
|
||||||
|
#define BIGFOOT_GRAPHICSVULKAN_VULKANDEVICE_HPP
|
||||||
|
#include <GraphicsVulkan/VulkanInclude.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanInstance.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanQueue.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanSurface.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsInterface/GraphicsDevice.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/array.h>
|
||||||
|
#include <EASTL/optional.h>
|
||||||
|
#include <EASTL/string_view.h>
|
||||||
|
|
||||||
|
namespace Bigfoot::Vulkan
|
||||||
|
{
|
||||||
|
class VulkanDevice final: public GraphicsDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* \param p_instance The instance to create the device from
|
||||||
|
* \param p_surface The surface the device must be able to present to. Can be null to create a device with no
|
||||||
|
* present queue
|
||||||
|
* \param p_deviceNameHint Pick a specific physical device by name.
|
||||||
|
*/
|
||||||
|
VulkanDevice(const VulkanInstance& p_instance, const VulkanSurface* p_surface, eastl::string_view p_deviceNameHint);
|
||||||
|
|
||||||
|
~VulkanDevice() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a queue of the given type
|
||||||
|
*
|
||||||
|
* \param p_type The kind of work the queue should support
|
||||||
|
* \return The queue, or nullptr if the device has no queue of this type
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
const GraphicsQueue* GetQueue(GraphicsQueueType p_type) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the underlying Vulkan physical device handle
|
||||||
|
*
|
||||||
|
* \return The vk::PhysicalDevice handle
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
vk::PhysicalDevice GetPhysicalDeviceHandle() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the underlying Vulkan device handle
|
||||||
|
*
|
||||||
|
* \return The vk::Device handle
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
vk::Device GetHandle() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* The physical device this device was created from
|
||||||
|
*/
|
||||||
|
vk::PhysicalDevice m_physicalDevice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logical device
|
||||||
|
*/
|
||||||
|
vk::Device m_device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The queues. A slot is empty if the device has no queue of that type
|
||||||
|
*/
|
||||||
|
eastl::array<eastl::optional<VulkanQueue>, static_cast<size_t>(GraphicsQueueType::MAX) + 1> m_queues;
|
||||||
|
};
|
||||||
|
} // namespace Bigfoot::Vulkan
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file VulkanImage.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANIMAGE_HPP
|
||||||
|
#define BIGFOOT_GRAPHICSVULKAN_VULKANIMAGE_HPP
|
||||||
|
#include <GraphicsVulkan/VulkanInclude.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsInterface/GraphicsImage.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot::Vulkan
|
||||||
|
{
|
||||||
|
class VulkanImage final: public GraphicsImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* \param p_image The underlying Vulkan image handle
|
||||||
|
* \param p_format The pixel format of the image
|
||||||
|
* \param p_extent The size of the image
|
||||||
|
*/
|
||||||
|
VulkanImage(vk::Image p_image, PixelFormat p_format, vk::Extent2D p_extent);
|
||||||
|
|
||||||
|
VulkanImage(const VulkanImage& p_image) = delete;
|
||||||
|
VulkanImage(VulkanImage&& p_image) noexcept;
|
||||||
|
|
||||||
|
VulkanImage& operator=(const VulkanImage& p_image) = delete;
|
||||||
|
VulkanImage& operator=(VulkanImage&& p_image) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the pixel format of the image
|
||||||
|
*
|
||||||
|
* \return The image format
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
PixelFormat GetFormat() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of the image
|
||||||
|
*
|
||||||
|
* \return The image extent, in pixels
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
glm::uvec2 GetExtent() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the underlying Vulkan image handle
|
||||||
|
*
|
||||||
|
* \return The vk::Image handle
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
vk::Image GetHandle() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* The vulkan image
|
||||||
|
*/
|
||||||
|
vk::Image m_image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The pixel format of the image
|
||||||
|
*/
|
||||||
|
PixelFormat m_format;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the image
|
||||||
|
*/
|
||||||
|
vk::Extent2D m_extent;
|
||||||
|
};
|
||||||
|
} // namespace Bigfoot::Vulkan
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file VulkanPixelFormat.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANPIXELFORMAT_HPP
|
||||||
|
#define BIGFOOT_GRAPHICSVULKAN_VULKANPIXELFORMAT_HPP
|
||||||
|
#include <GraphicsVulkan/VulkanInclude.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsInterface/PixelFormat_generated.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot::Vulkan
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Convert PixelFormat to its vk::Format equivalent
|
||||||
|
*
|
||||||
|
* \param p_format The format to convert
|
||||||
|
* \return The equivalent vk::Format
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
vk::Format ToVulkanFormat(PixelFormat p_format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a vk::Format to its PixelFormat equivalent
|
||||||
|
*
|
||||||
|
* \param p_format The format to convert
|
||||||
|
* \return The equivalent PixelFormat
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
PixelFormat FromVulkanFormat(vk::Format p_format);
|
||||||
|
} // namespace Bigfoot::Vulkan
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -26,6 +26,12 @@ class VulkanQueue final: public GraphicsQueue
|
|||||||
*/
|
*/
|
||||||
VulkanQueue(vk::Queue p_queue, std::uint32_t p_familyIndex, GraphicsQueueType p_type);
|
VulkanQueue(vk::Queue p_queue, std::uint32_t p_familyIndex, GraphicsQueueType p_type);
|
||||||
|
|
||||||
|
VulkanQueue(const VulkanQueue& p_queue) = delete;
|
||||||
|
VulkanQueue(VulkanQueue&& p_queue) noexcept;
|
||||||
|
|
||||||
|
VulkanQueue& operator=(const VulkanQueue& p_queue) = delete;
|
||||||
|
VulkanQueue& operator=(VulkanQueue&& p_queue) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the kind of work this queue can be submitted
|
* Get the kind of work this queue can be submitted
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file VulkanSwapchain.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANSWAPCHAIN_HPP
|
||||||
|
#define BIGFOOT_GRAPHICSVULKAN_VULKANSWAPCHAIN_HPP
|
||||||
|
#include <GraphicsVulkan/VulkanDevice.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanImage.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanInclude.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanSurface.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsInterface/GraphicsSwapchain.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/span.h>
|
||||||
|
#include <EASTL/vector.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Bigfoot::Vulkan
|
||||||
|
{
|
||||||
|
class VulkanSwapchain final: public GraphicsSwapchain
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* \param p_device The device to create the swapchain from.
|
||||||
|
* \param p_surface The surface the swapchain will present to.
|
||||||
|
* \param p_extent The desired size of the swapchain images.
|
||||||
|
*/
|
||||||
|
VulkanSwapchain(const VulkanDevice& p_device, const VulkanSurface& p_surface, glm::uvec2 p_extent);
|
||||||
|
|
||||||
|
~VulkanSwapchain() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of images owned by the swapchain
|
||||||
|
*
|
||||||
|
* \return The image count
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
std::uint32_t GetImageCount() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get one of the images owned by the swapchain
|
||||||
|
*
|
||||||
|
* \param p_index The index of the image to get. Must be less than GetImageCount()
|
||||||
|
* \return The image
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
const GraphicsImage& GetImage(std::uint32_t p_index) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the underlying Vulkan swapchain handle
|
||||||
|
*
|
||||||
|
* \return The vk::SwapchainKHR handle
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
vk::SwapchainKHR GetHandle() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the swapchain images
|
||||||
|
*
|
||||||
|
* \return The images owned by the swapchain
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::span<const VulkanImage> GetImages() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* The device the swapchain was created from
|
||||||
|
*/
|
||||||
|
const VulkanDevice& m_device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The swapchain
|
||||||
|
*/
|
||||||
|
vk::SwapchainKHR m_swapchain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The images owned by the swapchain
|
||||||
|
*/
|
||||||
|
eastl::vector<VulkanImage> m_images;
|
||||||
|
};
|
||||||
|
} // namespace Bigfoot::Vulkan
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,352 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file VulkanDevice.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <GraphicsVulkan/VulkanDevice.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsVulkan/GraphicsVulkanAssertHandler.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanFormatters.hpp>
|
||||||
|
|
||||||
|
#include <Utils/String.hpp>
|
||||||
|
#include <Utils/TargetMacros.h>
|
||||||
|
|
||||||
|
#include <EASTL/algorithm.h>
|
||||||
|
#include <EASTL/optional.h>
|
||||||
|
#include <EASTL/span.h>
|
||||||
|
#include <EASTL/vector.h>
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Bigfoot::Vulkan
|
||||||
|
{
|
||||||
|
[[nodiscard]]
|
||||||
|
std::uint32_t GetPhysicalDeviceTypeRank(const vk::PhysicalDeviceType p_type)
|
||||||
|
{
|
||||||
|
switch (p_type)
|
||||||
|
{
|
||||||
|
case vk::PhysicalDeviceType::eDiscreteGpu:
|
||||||
|
return 0;
|
||||||
|
case vk::PhysicalDeviceType::eIntegratedGpu:
|
||||||
|
return 1;
|
||||||
|
case vk::PhysicalDeviceType::eVirtualGpu:
|
||||||
|
return 2;
|
||||||
|
case vk::PhysicalDeviceType::eCpu:
|
||||||
|
return 3;
|
||||||
|
case vk::PhysicalDeviceType::eOther:
|
||||||
|
default:
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
struct SelectedQueueFamilies
|
||||||
|
{
|
||||||
|
eastl::optional<std::uint32_t> m_graphics;
|
||||||
|
eastl::optional<std::uint32_t> m_compute;
|
||||||
|
eastl::optional<std::uint32_t> m_transfer;
|
||||||
|
eastl::optional<std::uint32_t> m_present;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::optional<std::uint32_t> FindQueueFamily(const std::span<const vk::QueueFamilyProperties> p_families,
|
||||||
|
const vk::QueueFlagBits p_required)
|
||||||
|
{
|
||||||
|
eastl::optional<std::uint32_t> best;
|
||||||
|
int bestBitCount = 0;
|
||||||
|
|
||||||
|
for (std::uint32_t index = 0; index < p_families.size(); ++index)
|
||||||
|
{
|
||||||
|
const vk::QueueFlags flags = p_families[index].queueFlags;
|
||||||
|
if (!(flags & p_required))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int bitCount = std::popcount(static_cast<vk::QueueFlags::MaskType>(flags));
|
||||||
|
if (!best.has_value() || bitCount < bestBitCount)
|
||||||
|
{
|
||||||
|
best = index;
|
||||||
|
bestBitCount = bitCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::optional<std::uint32_t> FindPresentQueueFamily(const vk::PhysicalDevice p_physicalDevice,
|
||||||
|
const vk::SurfaceKHR p_surface,
|
||||||
|
const std::uint32_t p_familyCount,
|
||||||
|
const eastl::optional<std::uint32_t> p_graphicsFamily)
|
||||||
|
{
|
||||||
|
if (p_graphicsFamily.has_value())
|
||||||
|
{
|
||||||
|
const vk::ResultValue<vk::Bool32> support = p_physicalDevice.getSurfaceSupportKHR(*p_graphicsFamily, p_surface);
|
||||||
|
if (support.result == vk::Result::eSuccess && support.value)
|
||||||
|
{
|
||||||
|
return *p_graphicsFamily;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::uint32_t index = 0; index < p_familyCount; ++index)
|
||||||
|
{
|
||||||
|
const vk::ResultValue<vk::Bool32> support = p_physicalDevice.getSurfaceSupportKHR(index, p_surface);
|
||||||
|
if (support.result == vk::Result::eSuccess && support.value)
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return eastl::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
SelectedQueueFamilies SelectQueueFamilies(const vk::PhysicalDevice p_physicalDevice, const vk::SurfaceKHR p_surface)
|
||||||
|
{
|
||||||
|
const std::vector<vk::QueueFamilyProperties> families = p_physicalDevice.getQueueFamilyProperties();
|
||||||
|
|
||||||
|
SelectedQueueFamilies selected;
|
||||||
|
selected.m_graphics = FindQueueFamily(families, vk::QueueFlagBits::eGraphics);
|
||||||
|
selected.m_compute = FindQueueFamily(families, vk::QueueFlagBits::eCompute);
|
||||||
|
selected.m_transfer = FindQueueFamily(families, vk::QueueFlagBits::eTransfer);
|
||||||
|
if (!selected.m_transfer.has_value())
|
||||||
|
{
|
||||||
|
// Per the Vulkan spec, any queue family supporting Graphics or Compute implicitly supports
|
||||||
|
// Transfer even when it doesn't explicitly report the bit, so the graphics family always works.
|
||||||
|
selected.m_transfer = selected.m_graphics;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_surface)
|
||||||
|
{
|
||||||
|
selected.m_present = FindPresentQueueFamily(p_physicalDevice,
|
||||||
|
p_surface,
|
||||||
|
static_cast<std::uint32_t>(families.size()),
|
||||||
|
selected.m_graphics);
|
||||||
|
}
|
||||||
|
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool IsPhysicalDeviceSuitable(const SelectedQueueFamilies& p_families, const bool p_needsPresent)
|
||||||
|
{
|
||||||
|
return p_families.m_graphics.has_value() && p_families.m_compute.has_value() &&
|
||||||
|
(!p_needsPresent || p_families.m_present.has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
struct PhysicalDeviceCandidate
|
||||||
|
{
|
||||||
|
vk::PhysicalDevice m_handle;
|
||||||
|
vk::PhysicalDeviceProperties m_properties;
|
||||||
|
SelectedQueueFamilies m_queueFamilies;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const PhysicalDeviceCandidate& SelectPhysicalDevice(const eastl::span<const PhysicalDeviceCandidate> p_candidates,
|
||||||
|
const eastl::string_view p_deviceNameHint)
|
||||||
|
{
|
||||||
|
if (!p_deviceNameHint.empty())
|
||||||
|
{
|
||||||
|
const auto it = eastl::find_if(p_candidates.begin(),
|
||||||
|
p_candidates.end(),
|
||||||
|
[p_deviceNameHint](const PhysicalDeviceCandidate& p_candidate)
|
||||||
|
{
|
||||||
|
return EqualNoCase(p_candidate.m_properties.deviceName.data(),
|
||||||
|
p_deviceNameHint);
|
||||||
|
});
|
||||||
|
if (it != p_candidates.end())
|
||||||
|
{
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
BIGFOOT_LOG_WARN(GRAPHICSVULKAN_LOGGER,
|
||||||
|
"No Vulkan device matching hint '{}' found, falling back to automatic selection",
|
||||||
|
p_deviceNameHint);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *eastl::min_element(p_candidates.begin(),
|
||||||
|
p_candidates.end(),
|
||||||
|
[](const PhysicalDeviceCandidate& p_lhs, const PhysicalDeviceCandidate& p_rhs)
|
||||||
|
{
|
||||||
|
return GetPhysicalDeviceTypeRank(p_lhs.m_properties.deviceType) <
|
||||||
|
GetPhysicalDeviceTypeRank(p_rhs.m_properties.deviceType);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::optional<VulkanQueue> CreateQueue(const vk::Device p_device,
|
||||||
|
const eastl::optional<std::uint32_t> p_familyIndex,
|
||||||
|
const GraphicsQueueType p_type)
|
||||||
|
{
|
||||||
|
if (!p_familyIndex.has_value())
|
||||||
|
{
|
||||||
|
return eastl::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VulkanQueue {p_device.getQueue(*p_familyIndex, 0), *p_familyIndex, p_type};
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
VulkanDevice::VulkanDevice(const VulkanInstance& p_instance,
|
||||||
|
const VulkanSurface* p_surface,
|
||||||
|
const eastl::string_view p_deviceNameHint)
|
||||||
|
{
|
||||||
|
const vk::SurfaceKHR surfaceHandle = p_surface != nullptr ? p_surface->GetHandle() : vk::SurfaceKHR {};
|
||||||
|
|
||||||
|
const vk::ResultValue<std::vector<vk::PhysicalDevice>> physicalDevices = p_instance.GetHandle()
|
||||||
|
.enumeratePhysicalDevices();
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||||
|
physicalDevices.result == vk::Result::eSuccess,
|
||||||
|
"({}) Failed to enumerate Vulkan physical devices",
|
||||||
|
physicalDevices.result);
|
||||||
|
|
||||||
|
eastl::vector<PhysicalDeviceCandidate> candidates;
|
||||||
|
for (const vk::PhysicalDevice physicalDevice: physicalDevices.value)
|
||||||
|
{
|
||||||
|
SelectedQueueFamilies queueFamilies = SelectQueueFamilies(physicalDevice, surfaceHandle);
|
||||||
|
if (!IsPhysicalDeviceSuitable(queueFamilies, static_cast<bool>(surfaceHandle)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
candidates.push_back({physicalDevice, physicalDevice.getProperties(), eastl::move(queueFamilies)});
|
||||||
|
}
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler, !candidates.empty(), "No suitable Vulkan physical device found");
|
||||||
|
|
||||||
|
const PhysicalDeviceCandidate& selected = SelectPhysicalDevice(candidates, p_deviceNameHint);
|
||||||
|
m_physicalDevice = selected.m_handle;
|
||||||
|
|
||||||
|
BIGFOOT_LOG_INFO(GRAPHICSVULKAN_LOGGER,
|
||||||
|
"Selected Vulkan physical device '{}' ({})",
|
||||||
|
selected.m_properties.deviceName.data(),
|
||||||
|
vk::to_string(selected.m_properties.deviceType));
|
||||||
|
|
||||||
|
eastl::vector<std::uint32_t> uniqueFamilies;
|
||||||
|
for (const eastl::optional<std::uint32_t> family: {selected.m_queueFamilies.m_graphics,
|
||||||
|
selected.m_queueFamilies.m_compute,
|
||||||
|
selected.m_queueFamilies.m_transfer,
|
||||||
|
selected.m_queueFamilies.m_present})
|
||||||
|
{
|
||||||
|
if (family.has_value() &&
|
||||||
|
eastl::find(uniqueFamilies.begin(), uniqueFamilies.end(), *family) == uniqueFamilies.end())
|
||||||
|
{
|
||||||
|
uniqueFamilies.push_back(*family);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr float queuePriority = 1.0f;
|
||||||
|
eastl::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
|
||||||
|
queueCreateInfos.reserve(uniqueFamilies.size());
|
||||||
|
for (const std::uint32_t family: uniqueFamilies)
|
||||||
|
{
|
||||||
|
queueCreateInfos.push_back({{}, family, 1u, &queuePriority});
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<const char*> enabledExtensions;
|
||||||
|
if (surfaceHandle)
|
||||||
|
{
|
||||||
|
enabledExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
const vk::DeviceCreateInfo deviceCreateInfo {{}, queueCreateInfos, {}, enabledExtensions};
|
||||||
|
|
||||||
|
vk::ResultValue<vk::Device> device {vk::Result::eSuccess, vk::Device {}};
|
||||||
|
{
|
||||||
|
BIGFOOT_LSAN_ONLY(const __lsan::ScopedDisabler lsanDisabler;)
|
||||||
|
device = m_physicalDevice.createDevice(deviceCreateInfo);
|
||||||
|
}
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||||
|
device.result == vk::Result::eSuccess,
|
||||||
|
"({}) Failed to create Vulkan device",
|
||||||
|
device.result);
|
||||||
|
m_device = device.value;
|
||||||
|
|
||||||
|
m_queues[static_cast<size_t>(GraphicsQueueType::Graphics)] = CreateQueue(m_device,
|
||||||
|
selected.m_queueFamilies.m_graphics,
|
||||||
|
GraphicsQueueType::Graphics);
|
||||||
|
m_queues[static_cast<size_t>(GraphicsQueueType::Compute)] = CreateQueue(m_device,
|
||||||
|
selected.m_queueFamilies.m_compute,
|
||||||
|
GraphicsQueueType::Compute);
|
||||||
|
m_queues[static_cast<size_t>(GraphicsQueueType::Transfer)] = CreateQueue(m_device,
|
||||||
|
selected.m_queueFamilies.m_transfer,
|
||||||
|
GraphicsQueueType::Transfer);
|
||||||
|
m_queues[static_cast<size_t>(GraphicsQueueType::Present)] = CreateQueue(m_device,
|
||||||
|
selected.m_queueFamilies.m_present,
|
||||||
|
GraphicsQueueType::Present);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
VulkanDevice::~VulkanDevice()
|
||||||
|
{
|
||||||
|
m_device.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
const GraphicsQueue* VulkanDevice::GetQueue(const GraphicsQueueType p_type) const
|
||||||
|
{
|
||||||
|
const eastl::optional<VulkanQueue>& queue = m_queues[static_cast<size_t>(p_type)];
|
||||||
|
return queue.has_value() ? &*queue : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
vk::PhysicalDevice VulkanDevice::GetPhysicalDeviceHandle() const
|
||||||
|
{
|
||||||
|
return m_physicalDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
vk::Device VulkanDevice::GetHandle() const
|
||||||
|
{
|
||||||
|
return m_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::unique_ptr<GraphicsDevice> CreateVulkanDevice(const GraphicsInstance& p_instance,
|
||||||
|
const DeviceCreateInfo& p_createInfo)
|
||||||
|
{
|
||||||
|
return eastl::make_unique<VulkanDevice>(static_cast<const VulkanInstance&>(p_instance),
|
||||||
|
static_cast<const VulkanSurface*>(p_createInfo.m_surface),
|
||||||
|
p_createInfo.m_deviceNameHint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool RegisterVulkanDeviceFactory()
|
||||||
|
{
|
||||||
|
const bool inserted = g_graphicsDeviceFactory->Register(GraphicsAPI::Vulkan, &CreateVulkanDevice);
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler, inserted, "Failed to register the Vulkan graphics device factory");
|
||||||
|
return inserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
const bool g_vulkanDeviceFactoryRegistered = RegisterVulkanDeviceFactory();
|
||||||
|
} // namespace Bigfoot::Vulkan
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file VulkanImage.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <GraphicsVulkan/VulkanImage.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot::Vulkan
|
||||||
|
{
|
||||||
|
VulkanImage::VulkanImage(const vk::Image p_image, const PixelFormat p_format, const vk::Extent2D p_extent):
|
||||||
|
m_image(p_image),
|
||||||
|
m_format(p_format),
|
||||||
|
m_extent(p_extent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
VulkanImage::VulkanImage(VulkanImage&& p_image) noexcept:
|
||||||
|
GraphicsImage(),
|
||||||
|
m_image(p_image.m_image),
|
||||||
|
m_format(p_image.m_format),
|
||||||
|
m_extent(p_image.m_extent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
VulkanImage& VulkanImage::operator=(VulkanImage&& p_image) noexcept
|
||||||
|
{
|
||||||
|
m_image = p_image.m_image;
|
||||||
|
m_format = p_image.m_format;
|
||||||
|
m_extent = p_image.m_extent;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
PixelFormat VulkanImage::GetFormat() const
|
||||||
|
{
|
||||||
|
return m_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
glm::uvec2 VulkanImage::GetExtent() const
|
||||||
|
{
|
||||||
|
return {m_extent.width, m_extent.height};
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
vk::Image VulkanImage::GetHandle() const
|
||||||
|
{
|
||||||
|
return m_image;
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot::Vulkan
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
#include <GraphicsVulkan/GraphicsVulkanAssertHandler.hpp>
|
#include <GraphicsVulkan/GraphicsVulkanAssertHandler.hpp>
|
||||||
#include <GraphicsVulkan/VulkanFormatters.hpp>
|
#include <GraphicsVulkan/VulkanFormatters.hpp>
|
||||||
|
|
||||||
|
#include <Utils/TargetMacros.h>
|
||||||
|
|
||||||
#include <Engine/EngineInfo_generated.hpp>
|
#include <Engine/EngineInfo_generated.hpp>
|
||||||
|
|
||||||
#include <EASTL/algorithm.h>
|
#include <EASTL/algorithm.h>
|
||||||
@@ -106,7 +108,11 @@ VulkanInstance::VulkanInstance(const eastl::string_view p_applicationName, const
|
|||||||
|
|
||||||
const vk::InstanceCreateInfo instanceCreateInfo {{}, &applicationInfo, enabledLayers, enabledExtensions};
|
const vk::InstanceCreateInfo instanceCreateInfo {{}, &applicationInfo, enabledLayers, enabledExtensions};
|
||||||
|
|
||||||
const vk::ResultValue<vk::Instance> instance = vk::createInstance(instanceCreateInfo);
|
vk::ResultValue<vk::Instance> instance {vk::Result::eSuccess, vk::Instance {}};
|
||||||
|
{
|
||||||
|
BIGFOOT_LSAN_ONLY(const __lsan::ScopedDisabler lsanDisabler;)
|
||||||
|
instance = vk::createInstance(instanceCreateInfo);
|
||||||
|
}
|
||||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||||
instance.result == vk::Result::eSuccess,
|
instance.result == vk::Result::eSuccess,
|
||||||
"({}) Failed to create Vulkan instance",
|
"({}) Failed to create Vulkan instance",
|
||||||
@@ -157,4 +163,27 @@ vk::Instance VulkanInstance::GetHandle() const
|
|||||||
{
|
{
|
||||||
return m_instance;
|
return m_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::unique_ptr<GraphicsInstance> CreateVulkanInstance(const eastl::string_view p_applicationName,
|
||||||
|
const Version p_applicationVersion)
|
||||||
|
{
|
||||||
|
return eastl::make_unique<VulkanInstance>(p_applicationName, p_applicationVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool RegisterVulkanInstanceFactory()
|
||||||
|
{
|
||||||
|
const bool inserted = g_graphicsInstanceFactory->Register(GraphicsAPI::Vulkan, &CreateVulkanInstance);
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler, inserted, "Failed to register the Vulkan graphics instance factory");
|
||||||
|
return inserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
const bool g_vulkanInstanceFactoryRegistered = RegisterVulkanInstanceFactory();
|
||||||
} // namespace Bigfoot::Vulkan
|
} // namespace Bigfoot::Vulkan
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file VulkanPixelFormat.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <GraphicsVulkan/VulkanPixelFormat.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot::Vulkan
|
||||||
|
{
|
||||||
|
vk::Format ToVulkanFormat(const PixelFormat p_format)
|
||||||
|
{
|
||||||
|
switch (p_format)
|
||||||
|
{
|
||||||
|
case PixelFormat::R8G8B8A8Unorm:
|
||||||
|
return vk::Format::eR8G8B8A8Unorm;
|
||||||
|
case PixelFormat::R8G8B8A8Srgb:
|
||||||
|
return vk::Format::eR8G8B8A8Srgb;
|
||||||
|
case PixelFormat::B8G8R8A8Unorm:
|
||||||
|
return vk::Format::eB8G8R8A8Unorm;
|
||||||
|
case PixelFormat::B8G8R8A8Srgb:
|
||||||
|
return vk::Format::eB8G8R8A8Srgb;
|
||||||
|
case PixelFormat::A2B10G10R10UnormPack32:
|
||||||
|
return vk::Format::eA2B10G10R10UnormPack32;
|
||||||
|
case PixelFormat::R16G16B16A16Sfloat:
|
||||||
|
return vk::Format::eR16G16B16A16Sfloat;
|
||||||
|
case PixelFormat::Undefined:
|
||||||
|
default:
|
||||||
|
return vk::Format::eUndefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
PixelFormat FromVulkanFormat(const vk::Format p_format)
|
||||||
|
{
|
||||||
|
switch (p_format)
|
||||||
|
{
|
||||||
|
case vk::Format::eR8G8B8A8Unorm:
|
||||||
|
return PixelFormat::R8G8B8A8Unorm;
|
||||||
|
case vk::Format::eR8G8B8A8Srgb:
|
||||||
|
return PixelFormat::R8G8B8A8Srgb;
|
||||||
|
case vk::Format::eB8G8R8A8Unorm:
|
||||||
|
return PixelFormat::B8G8R8A8Unorm;
|
||||||
|
case vk::Format::eB8G8R8A8Srgb:
|
||||||
|
return PixelFormat::B8G8R8A8Srgb;
|
||||||
|
case vk::Format::eA2B10G10R10UnormPack32:
|
||||||
|
return PixelFormat::A2B10G10R10UnormPack32;
|
||||||
|
case vk::Format::eR16G16B16A16Sfloat:
|
||||||
|
return PixelFormat::R16G16B16A16Sfloat;
|
||||||
|
default:
|
||||||
|
return PixelFormat::Undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot::Vulkan
|
||||||
@@ -17,6 +17,26 @@ VulkanQueue::VulkanQueue(const vk::Queue p_queue, const std::uint32_t p_familyIn
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
VulkanQueue::VulkanQueue(VulkanQueue&& p_queue) noexcept:
|
||||||
|
GraphicsQueue(),
|
||||||
|
m_queue(p_queue.m_queue),
|
||||||
|
m_familyIndex(p_queue.m_familyIndex),
|
||||||
|
m_type(p_queue.m_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
VulkanQueue& VulkanQueue::operator=(VulkanQueue&& p_queue) noexcept
|
||||||
|
{
|
||||||
|
m_queue = p_queue.m_queue;
|
||||||
|
m_familyIndex = p_queue.m_familyIndex;
|
||||||
|
m_type = p_queue.m_type;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
GraphicsQueueType VulkanQueue::GetType() const
|
GraphicsQueueType VulkanQueue::GetType() const
|
||||||
{
|
{
|
||||||
return m_type;
|
return m_type;
|
||||||
|
|||||||
@@ -44,4 +44,27 @@ vk::SurfaceKHR VulkanSurface::GetHandle() const
|
|||||||
{
|
{
|
||||||
return m_surface;
|
return m_surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::unique_ptr<GraphicsSurface> CreateVulkanSurface(const GraphicsInstance& p_instance,
|
||||||
|
const SurfaceCreateInfo& p_surfaceCreateInfo)
|
||||||
|
{
|
||||||
|
return eastl::make_unique<VulkanSurface>(static_cast<const VulkanInstance&>(p_instance), p_surfaceCreateInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool RegisterVulkanSurfaceFactory()
|
||||||
|
{
|
||||||
|
const bool inserted = g_graphicsSurfaceFactory->Register(GraphicsAPI::Vulkan, &CreateVulkanSurface);
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler, inserted, "Failed to register the Vulkan graphics surface factory");
|
||||||
|
return inserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
const bool g_vulkanSurfaceFactoryRegistered = RegisterVulkanSurfaceFactory();
|
||||||
} // namespace Bigfoot::Vulkan
|
} // namespace Bigfoot::Vulkan
|
||||||
|
|||||||
@@ -0,0 +1,235 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file VulkanSwapchain.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <GraphicsVulkan/VulkanSwapchain.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsVulkan/GraphicsVulkanAssertHandler.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanFormatters.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanPixelFormat.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanQueue.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/algorithm.h>
|
||||||
|
#include <EASTL/vector.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <span>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Bigfoot::Vulkan
|
||||||
|
{
|
||||||
|
[[nodiscard]]
|
||||||
|
vk::SurfaceFormatKHR SelectSurfaceFormat(const std::span<const vk::SurfaceFormatKHR> p_formats)
|
||||||
|
{
|
||||||
|
const auto it = eastl::find_if(p_formats.begin(),
|
||||||
|
p_formats.end(),
|
||||||
|
[](const vk::SurfaceFormatKHR& p_format)
|
||||||
|
{
|
||||||
|
return p_format.format == vk::Format::eB8G8R8A8Srgb &&
|
||||||
|
p_format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear;
|
||||||
|
});
|
||||||
|
|
||||||
|
return it != p_formats.end() ? *it : p_formats.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
vk::PresentModeKHR SelectPresentMode(const std::span<const vk::PresentModeKHR> p_presentModes)
|
||||||
|
{
|
||||||
|
const auto it = eastl::find(p_presentModes.begin(), p_presentModes.end(), vk::PresentModeKHR::eMailbox);
|
||||||
|
|
||||||
|
// eFifo is guaranteed by the spec to always be supported
|
||||||
|
return it != p_presentModes.end() ? *it : vk::PresentModeKHR::eFifo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
vk::Extent2D SelectExtent(const vk::SurfaceCapabilitiesKHR& p_capabilities, const glm::uvec2 p_extent)
|
||||||
|
{
|
||||||
|
constexpr std::uint32_t undefinedExtent = std::numeric_limits<std::uint32_t>::max();
|
||||||
|
if (p_capabilities.currentExtent.width != undefinedExtent)
|
||||||
|
{
|
||||||
|
return p_capabilities.currentExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {eastl::clamp(p_extent.x, p_capabilities.minImageExtent.width, p_capabilities.maxImageExtent.width),
|
||||||
|
eastl::clamp(p_extent.y, p_capabilities.minImageExtent.height, p_capabilities.maxImageExtent.height)};
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
vk::CompositeAlphaFlagBitsKHR SelectCompositeAlpha(const vk::CompositeAlphaFlagsKHR p_supportedCompositeAlpha)
|
||||||
|
{
|
||||||
|
for (const vk::CompositeAlphaFlagBitsKHR candidate: {vk::CompositeAlphaFlagBitsKHR::eOpaque,
|
||||||
|
vk::CompositeAlphaFlagBitsKHR::ePreMultiplied,
|
||||||
|
vk::CompositeAlphaFlagBitsKHR::ePostMultiplied,
|
||||||
|
vk::CompositeAlphaFlagBitsKHR::eInherit})
|
||||||
|
{
|
||||||
|
if (p_supportedCompositeAlpha & candidate)
|
||||||
|
{
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vk::CompositeAlphaFlagBitsKHR::eOpaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
VulkanSwapchain::VulkanSwapchain(const VulkanDevice& p_device,
|
||||||
|
const VulkanSurface& p_surface,
|
||||||
|
const glm::uvec2 p_extent):
|
||||||
|
m_device(p_device)
|
||||||
|
{
|
||||||
|
const vk::PhysicalDevice physicalDevice = p_device.GetPhysicalDeviceHandle();
|
||||||
|
const vk::SurfaceKHR surface = p_surface.GetHandle();
|
||||||
|
|
||||||
|
const vk::ResultValue<vk::SurfaceCapabilitiesKHR> capabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface);
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||||
|
capabilities.result == vk::Result::eSuccess,
|
||||||
|
"({}) Failed to get Vulkan surface capabilities",
|
||||||
|
capabilities.result);
|
||||||
|
|
||||||
|
const vk::ResultValue<std::vector<vk::SurfaceFormatKHR>> formats = physicalDevice.getSurfaceFormatsKHR(surface);
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||||
|
formats.result == vk::Result::eSuccess && !formats.value.empty(),
|
||||||
|
"({}) Failed to get Vulkan surface formats",
|
||||||
|
formats.result);
|
||||||
|
|
||||||
|
const vk::ResultValue<std::vector<vk::PresentModeKHR>> presentModes = physicalDevice.getSurfacePresentModesKHR(
|
||||||
|
surface);
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||||
|
presentModes.result == vk::Result::eSuccess && !presentModes.value.empty(),
|
||||||
|
"({}) Failed to get Vulkan surface present modes",
|
||||||
|
presentModes.result);
|
||||||
|
|
||||||
|
const vk::SurfaceFormatKHR surfaceFormat = SelectSurfaceFormat(formats.value);
|
||||||
|
const vk::PresentModeKHR presentMode = SelectPresentMode(presentModes.value);
|
||||||
|
const vk::Extent2D extent = SelectExtent(capabilities.value, p_extent);
|
||||||
|
|
||||||
|
std::uint32_t imageCount = capabilities.value.minImageCount + 1;
|
||||||
|
if (capabilities.value.maxImageCount > 0)
|
||||||
|
{
|
||||||
|
imageCount = eastl::min(imageCount, capabilities.value.maxImageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* const graphicsQueue = static_cast<const VulkanQueue*>(p_device.GetQueue(GraphicsQueueType::Graphics));
|
||||||
|
const auto* const presentQueue = static_cast<const VulkanQueue*>(p_device.GetQueue(GraphicsQueueType::Present));
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||||
|
graphicsQueue != nullptr && presentQueue != nullptr,
|
||||||
|
"Cannot create a swapchain on a device with no graphics or present queue");
|
||||||
|
|
||||||
|
const bool sameQueueFamily = graphicsQueue->GetFamilyIndex() == presentQueue->GetFamilyIndex();
|
||||||
|
|
||||||
|
eastl::vector<std::uint32_t> queueFamilyIndices;
|
||||||
|
if (!sameQueueFamily)
|
||||||
|
{
|
||||||
|
queueFamilyIndices = {graphicsQueue->GetFamilyIndex(), presentQueue->GetFamilyIndex()};
|
||||||
|
}
|
||||||
|
|
||||||
|
const vk::SwapchainCreateInfoKHR swapchainCreateInfo {
|
||||||
|
{},
|
||||||
|
surface,
|
||||||
|
imageCount,
|
||||||
|
surfaceFormat.format,
|
||||||
|
surfaceFormat.colorSpace,
|
||||||
|
extent,
|
||||||
|
1,
|
||||||
|
vk::ImageUsageFlagBits::eColorAttachment,
|
||||||
|
sameQueueFamily ? vk::SharingMode::eExclusive : vk::SharingMode::eConcurrent,
|
||||||
|
queueFamilyIndices,
|
||||||
|
capabilities.value.currentTransform,
|
||||||
|
SelectCompositeAlpha(capabilities.value.supportedCompositeAlpha),
|
||||||
|
presentMode,
|
||||||
|
VK_TRUE};
|
||||||
|
|
||||||
|
const vk::ResultValue<vk::SwapchainKHR> swapchain = p_device.GetHandle().createSwapchainKHR(swapchainCreateInfo);
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||||
|
swapchain.result == vk::Result::eSuccess,
|
||||||
|
"({}) Failed to create Vulkan swapchain",
|
||||||
|
swapchain.result);
|
||||||
|
m_swapchain = swapchain.value;
|
||||||
|
|
||||||
|
const vk::ResultValue<std::vector<vk::Image>> images = p_device.GetHandle().getSwapchainImagesKHR(m_swapchain);
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||||
|
images.result == vk::Result::eSuccess,
|
||||||
|
"({}) Failed to get Vulkan swapchain images",
|
||||||
|
images.result);
|
||||||
|
const PixelFormat imageFormat = FromVulkanFormat(surfaceFormat.format);
|
||||||
|
m_images.reserve(images.value.size());
|
||||||
|
for (const vk::Image image: images.value)
|
||||||
|
{
|
||||||
|
m_images.emplace_back(image, imageFormat, extent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
VulkanSwapchain::~VulkanSwapchain()
|
||||||
|
{
|
||||||
|
m_device.GetHandle().destroySwapchainKHR(m_swapchain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
std::uint32_t VulkanSwapchain::GetImageCount() const
|
||||||
|
{
|
||||||
|
return static_cast<std::uint32_t>(m_images.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
const GraphicsImage& VulkanSwapchain::GetImage(const std::uint32_t p_index) const
|
||||||
|
{
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||||
|
p_index < m_images.size(),
|
||||||
|
"Swapchain image index {} out of range (swapchain has {} images)",
|
||||||
|
p_index,
|
||||||
|
m_images.size());
|
||||||
|
return m_images[p_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
vk::SwapchainKHR VulkanSwapchain::GetHandle() const
|
||||||
|
{
|
||||||
|
return m_swapchain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::span<const VulkanImage> VulkanSwapchain::GetImages() const
|
||||||
|
{
|
||||||
|
return {m_images.data(), m_images.size()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::unique_ptr<GraphicsSwapchain> CreateVulkanSwapchain(const SwapchainCreateInfo& p_createInfo)
|
||||||
|
{
|
||||||
|
return eastl::make_unique<VulkanSwapchain>(static_cast<const VulkanDevice&>(*p_createInfo.m_device),
|
||||||
|
static_cast<const VulkanSurface&>(*p_createInfo.m_surface),
|
||||||
|
p_createInfo.m_extent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool RegisterVulkanSwapchainFactory()
|
||||||
|
{
|
||||||
|
const bool inserted = g_graphicsSwapchainFactory->Register(GraphicsAPI::Vulkan, &CreateVulkanSwapchain);
|
||||||
|
CRITICAL_ASSERT(GraphicsVulkanAssertHandler, inserted, "Failed to register the Vulkan graphics swapchain factory");
|
||||||
|
return inserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
const bool g_vulkanSwapchainFactoryRegistered = RegisterVulkanSwapchainFactory();
|
||||||
|
} // namespace Bigfoot::Vulkan
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file LazyGlobal.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_UTILS_LAZYGLOBAL_HPP
|
||||||
|
#define BIGFOOT_UTILS_LAZYGLOBAL_HPP
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
template<class TYPE, class TAG = TYPE>
|
||||||
|
requires std::is_default_constructible_v<TYPE>
|
||||||
|
class LazyGlobal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
TYPE* operator->() const
|
||||||
|
{
|
||||||
|
return &Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
operator TYPE*() const
|
||||||
|
{
|
||||||
|
return &Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]]
|
||||||
|
static TYPE& Get()
|
||||||
|
{
|
||||||
|
static TYPE instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file String.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_UTILS_STRING_HPP
|
||||||
|
#define BIGFOOT_UTILS_STRING_HPP
|
||||||
|
#include <EASTL/string_view.h>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check if p_a and p_b are equal, ignoring case
|
||||||
|
*
|
||||||
|
* \param p_a The first string
|
||||||
|
* \param p_b The second string
|
||||||
|
* \return True if p_a and p_b are equal, false otherwise
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool EqualNoCase(eastl::string_view p_a, eastl::string_view p_b);
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -44,4 +44,20 @@
|
|||||||
#define BIGFOOT_GAME_ONLY(...) __VA_ARGS__
|
#define BIGFOOT_GAME_ONLY(...) __VA_ARGS__
|
||||||
#define BIGFOOT_GAME_OR_TOOLMODE(p_game, p_toolmode) p_game
|
#define BIGFOOT_GAME_OR_TOOLMODE(p_game, p_toolmode) p_game
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__has_feature)
|
||||||
|
#if __has_feature(address_sanitizer)
|
||||||
|
#include <sanitizer/lsan_interface.h>
|
||||||
|
#define BIGFOOT_LSAN 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifndef BIGFOOT_LSAN
|
||||||
|
#define BIGFOOT_LSAN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BIGFOOT_LSAN
|
||||||
|
#define BIGFOOT_LSAN_ONLY(...) __VA_ARGS__
|
||||||
|
#else
|
||||||
|
#define BIGFOOT_LSAN_ONLY(...)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file String.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Utils/String.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/algorithm.h>
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
bool EqualNoCase(const eastl::string_view p_a, const eastl::string_view p_b)
|
||||||
|
{
|
||||||
|
if (p_a.size() != p_b.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto toLower = [](const char p_character)
|
||||||
|
{
|
||||||
|
return static_cast<char>(std::tolower(static_cast<unsigned char>(p_character)));
|
||||||
|
};
|
||||||
|
|
||||||
|
return eastl::equal(p_a.begin(),
|
||||||
|
p_a.end(),
|
||||||
|
p_b.begin(),
|
||||||
|
[&toLower](const char p_x, const char p_y)
|
||||||
|
{
|
||||||
|
return toLower(p_x) == toLower(p_y);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -41,7 +41,7 @@ class AssetFixture: public ::testing::Test
|
|||||||
|
|
||||||
void TearDown() override
|
void TearDown() override
|
||||||
{
|
{
|
||||||
SetActiveAssetLibrary(&g_assetLibrary);
|
SetActiveAssetLibrary(g_assetLibrary);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetLibrary m_library;
|
AssetLibrary m_library;
|
||||||
|
|||||||
@@ -244,18 +244,18 @@ TEST_F(AssetLibraryFixture, SetActiveAssetLibrary_ShouldSetTheActiveAssetLibrary
|
|||||||
{
|
{
|
||||||
SetActiveAssetLibrary(&m_library);
|
SetActiveAssetLibrary(&m_library);
|
||||||
EXPECT_EQ(g_activeAssetLibrary, &m_library);
|
EXPECT_EQ(g_activeAssetLibrary, &m_library);
|
||||||
SetActiveAssetLibrary(&g_assetLibrary);
|
SetActiveAssetLibrary(g_assetLibrary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(AssetLibraryFixture, ScopedActiveAssetLibrary_ShouldChangeTheActiveAssetLibraryInAScopedWay)
|
TEST_F(AssetLibraryFixture, ScopedActiveAssetLibrary_ShouldChangeTheActiveAssetLibraryInAScopedWay)
|
||||||
{
|
{
|
||||||
EXPECT_EQ(g_activeAssetLibrary, &g_assetLibrary);
|
EXPECT_EQ(g_activeAssetLibrary, g_assetLibrary);
|
||||||
{
|
{
|
||||||
ScopedActiveAssetLibrary activeAssetLibraryScoped {&m_library};
|
ScopedActiveAssetLibrary activeAssetLibraryScoped {&m_library};
|
||||||
EXPECT_EQ(g_activeAssetLibrary, &m_library);
|
EXPECT_EQ(g_activeAssetLibrary, &m_library);
|
||||||
}
|
}
|
||||||
EXPECT_EQ(g_activeAssetLibrary, &g_assetLibrary);
|
EXPECT_EQ(g_activeAssetLibrary, g_assetLibrary);
|
||||||
}
|
}
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class ReferenceFixture: public ::testing::Test
|
|||||||
|
|
||||||
void TearDown() override
|
void TearDown() override
|
||||||
{
|
{
|
||||||
SetActiveAssetLibrary(&g_assetLibrary);
|
SetActiveAssetLibrary(g_assetLibrary);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class SerializationManagerFixture: public ::testing::Test
|
|||||||
void TearDown() override
|
void TearDown() override
|
||||||
{
|
{
|
||||||
SetDataAccessor(m_previousDataAccessor);
|
SetDataAccessor(m_previousDataAccessor);
|
||||||
SetActiveAssetLibrary(&g_assetLibrary);
|
SetActiveAssetLibrary(g_assetLibrary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
project(${PackageName}Tests)
|
project(${PackageName}Tests)
|
||||||
|
|
||||||
set(Dependencies)
|
set(Dependencies
|
||||||
|
SDL3::SDL3)
|
||||||
set(BigfootDependencies)
|
set(BigfootDependencies)
|
||||||
|
|
||||||
bigfoot_create_package_tests(
|
bigfoot_create_package_tests(
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file GraphicsContext.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <GraphicsCore/GraphicsContext.hpp>
|
||||||
|
|
||||||
|
#include <Utils/TargetMacros.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
class GraphicsContextFixture: public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void SetUp() override
|
||||||
|
{
|
||||||
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
|
{
|
||||||
|
BIGFOOT_LSAN_ONLY(const __lsan::ScopedDisabler lsanDisabler;)
|
||||||
|
m_window = SDL_CreateWindow("GraphicsContextTests", 64, 64, SDL_WINDOW_HIDDEN | SDL_WINDOW_VULKAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SDL_PropertiesID windowProperties = SDL_GetWindowProperties(m_window);
|
||||||
|
|
||||||
|
m_createInfo.m_applicationName = "GraphicsContextTests";
|
||||||
|
m_createInfo.m_applicationVersion = Version {1, 0, 0};
|
||||||
|
m_createInfo.m_extent = {64, 64};
|
||||||
|
#ifdef BIGFOOT_WINDOWS
|
||||||
|
m_createInfo.m_surfaceCreateInfo.m_windowHandle = static_cast<HWND>(
|
||||||
|
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr));
|
||||||
|
m_createInfo.m_surfaceCreateInfo.m_windowInstance = GetModuleHandle(nullptr);
|
||||||
|
#elif defined BIGFOOT_LINUX
|
||||||
|
m_createInfo.m_surfaceCreateInfo.m_display = static_cast<wl_display*>(
|
||||||
|
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, nullptr));
|
||||||
|
m_createInfo.m_surfaceCreateInfo.m_surface = static_cast<wl_surface*>(
|
||||||
|
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override
|
||||||
|
{
|
||||||
|
SDL_DestroyWindow(m_window);
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Window* m_window = nullptr;
|
||||||
|
GraphicsContextCreateInfo m_createInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(GraphicsContextFixture, Constructor_ShouldCreateAValidContext)
|
||||||
|
{
|
||||||
|
const GraphicsContext context {m_createInfo};
|
||||||
|
|
||||||
|
EXPECT_NE(context.GetDevice().GetQueue(GraphicsQueueType::Graphics), nullptr);
|
||||||
|
EXPECT_NE(context.GetDevice().GetQueue(GraphicsQueueType::Compute), nullptr);
|
||||||
|
EXPECT_NE(context.GetDevice().GetQueue(GraphicsQueueType::Transfer), nullptr);
|
||||||
|
EXPECT_NE(context.GetDevice().GetQueue(GraphicsQueueType::Present), nullptr);
|
||||||
|
EXPECT_GT(context.GetSwapchain().GetImageCount(), 0u);
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file VulkanDevice.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <GraphicsVulkan/VulkanDevice.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsVulkan/VulkanInstance.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanSurface.hpp>
|
||||||
|
|
||||||
|
#include <Utils/TargetMacros.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace Bigfoot::Vulkan
|
||||||
|
{
|
||||||
|
class VulkanDeviceFixture: public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void SetUp() override
|
||||||
|
{
|
||||||
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
|
m_window = SDL_CreateWindow("VulkanDeviceTests", 64, 64, SDL_WINDOW_HIDDEN | SDL_WINDOW_VULKAN);
|
||||||
|
|
||||||
|
const SDL_PropertiesID windowProperties = SDL_GetWindowProperties(m_window);
|
||||||
|
|
||||||
|
#ifdef BIGFOOT_WINDOWS
|
||||||
|
m_surfaceCreateInfo.m_windowHandle = static_cast<HWND>(
|
||||||
|
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr));
|
||||||
|
m_surfaceCreateInfo.m_windowInstance = GetModuleHandle(nullptr);
|
||||||
|
#elif defined BIGFOOT_LINUX
|
||||||
|
m_surfaceCreateInfo.m_display = static_cast<wl_display*>(
|
||||||
|
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, nullptr));
|
||||||
|
m_surfaceCreateInfo.m_surface = static_cast<wl_surface*>(
|
||||||
|
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override
|
||||||
|
{
|
||||||
|
SDL_DestroyWindow(m_window);
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanInstance m_instance {"VulkanDeviceTests", Version {1, 0, 0}};
|
||||||
|
SDL_Window* m_window = nullptr;
|
||||||
|
SurfaceCreateInfo m_surfaceCreateInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(VulkanDeviceFixture, WithoutSurface_ShouldCreateAValidDeviceWithoutAPresentQueue)
|
||||||
|
{
|
||||||
|
const VulkanDevice device {m_instance, nullptr, {}};
|
||||||
|
|
||||||
|
EXPECT_TRUE(device.GetPhysicalDeviceHandle());
|
||||||
|
EXPECT_TRUE(device.GetHandle());
|
||||||
|
EXPECT_NE(device.GetQueue(GraphicsQueueType::Graphics), nullptr);
|
||||||
|
EXPECT_NE(device.GetQueue(GraphicsQueueType::Compute), nullptr);
|
||||||
|
EXPECT_NE(device.GetQueue(GraphicsQueueType::Transfer), nullptr);
|
||||||
|
EXPECT_EQ(device.GetQueue(GraphicsQueueType::Present), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(VulkanDeviceFixture, WithSurface_ShouldCreateAValidDeviceWithAPresentQueue)
|
||||||
|
{
|
||||||
|
const VulkanSurface surface {m_instance, m_surfaceCreateInfo};
|
||||||
|
|
||||||
|
const VulkanDevice device {m_instance, &surface, {}};
|
||||||
|
|
||||||
|
EXPECT_TRUE(device.GetPhysicalDeviceHandle());
|
||||||
|
EXPECT_TRUE(device.GetHandle());
|
||||||
|
EXPECT_NE(device.GetQueue(GraphicsQueueType::Graphics), nullptr);
|
||||||
|
EXPECT_NE(device.GetQueue(GraphicsQueueType::Compute), nullptr);
|
||||||
|
EXPECT_NE(device.GetQueue(GraphicsQueueType::Transfer), nullptr);
|
||||||
|
EXPECT_NE(device.GetQueue(GraphicsQueueType::Present), nullptr);
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot::Vulkan
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file VulkanPixelFormat.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <GraphicsVulkan/VulkanPixelFormat.hpp>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace Bigfoot::Vulkan
|
||||||
|
{
|
||||||
|
class VulkanPixelFormatFixture: public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(VulkanPixelFormatFixture, ToVulkanFormat_MapsUndefinedToAnUndefinedVkFormat)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(ToVulkanFormat(PixelFormat::Undefined), vk::Format::eUndefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(VulkanPixelFormatFixture, ToVulkanFormat_MapsEveryOtherPixelFormatToANonUndefinedVkFormat)
|
||||||
|
{
|
||||||
|
for (const PixelFormat format: EnumValuesPixelFormat())
|
||||||
|
{
|
||||||
|
if (format == PixelFormat::Undefined)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_NE(ToVulkanFormat(format), vk::Format::eUndefined) << EnumNamePixelFormat(format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(VulkanPixelFormatFixture, ToVulkanFormat_RoundTripsThroughFromVulkanFormatForEveryPixelFormat)
|
||||||
|
{
|
||||||
|
for (const PixelFormat format: EnumValuesPixelFormat())
|
||||||
|
{
|
||||||
|
if (format == PixelFormat::Undefined)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(FromVulkanFormat(ToVulkanFormat(format)), format) << EnumNamePixelFormat(format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(VulkanPixelFormatFixture, FromVulkanFormat_ReturnsUndefinedForAnUnmappedVkFormat)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(FromVulkanFormat(vk::Format::eR32G32B32A32Sfloat), PixelFormat::Undefined);
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot::Vulkan
|
||||||
@@ -27,8 +27,8 @@ class VulkanSurfaceFixture: public ::testing::Test
|
|||||||
const SDL_PropertiesID windowProperties = SDL_GetWindowProperties(m_window);
|
const SDL_PropertiesID windowProperties = SDL_GetWindowProperties(m_window);
|
||||||
|
|
||||||
#ifdef BIGFOOT_WINDOWS
|
#ifdef BIGFOOT_WINDOWS
|
||||||
m_surfaceCreateInfo.m_windowHandle =
|
m_surfaceCreateInfo.m_windowHandle = static_cast<HWND>(
|
||||||
static_cast<HWND>(SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr));
|
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr));
|
||||||
m_surfaceCreateInfo.m_windowInstance = GetModuleHandle(nullptr);
|
m_surfaceCreateInfo.m_windowInstance = GetModuleHandle(nullptr);
|
||||||
#elif defined BIGFOOT_LINUX
|
#elif defined BIGFOOT_LINUX
|
||||||
m_surfaceCreateInfo.m_display = static_cast<wl_display*>(
|
m_surfaceCreateInfo.m_display = static_cast<wl_display*>(
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file VulkanSwapchain.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <GraphicsVulkan/VulkanSwapchain.hpp>
|
||||||
|
|
||||||
|
#include <GraphicsVulkan/VulkanDevice.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanImage.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanInstance.hpp>
|
||||||
|
#include <GraphicsVulkan/VulkanSurface.hpp>
|
||||||
|
|
||||||
|
#include <Utils/TargetMacros.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace Bigfoot::Vulkan
|
||||||
|
{
|
||||||
|
class VulkanSwapchainFixture: public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void SetUp() override
|
||||||
|
{
|
||||||
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
|
{
|
||||||
|
BIGFOOT_LSAN_ONLY(const __lsan::ScopedDisabler lsanDisabler;)
|
||||||
|
m_window = SDL_CreateWindow("VulkanSwapchainTests", 64, 64, SDL_WINDOW_HIDDEN | SDL_WINDOW_VULKAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SDL_PropertiesID windowProperties = SDL_GetWindowProperties(m_window);
|
||||||
|
|
||||||
|
#ifdef BIGFOOT_WINDOWS
|
||||||
|
m_surfaceCreateInfo.m_windowHandle = static_cast<HWND>(
|
||||||
|
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr));
|
||||||
|
m_surfaceCreateInfo.m_windowInstance = GetModuleHandle(nullptr);
|
||||||
|
#elif defined BIGFOOT_LINUX
|
||||||
|
m_surfaceCreateInfo.m_display = static_cast<wl_display*>(
|
||||||
|
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, nullptr));
|
||||||
|
m_surfaceCreateInfo.m_surface = static_cast<wl_surface*>(
|
||||||
|
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override
|
||||||
|
{
|
||||||
|
SDL_DestroyWindow(m_window);
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanInstance m_instance {"VulkanSwapchainTests", Version {1, 0, 0}};
|
||||||
|
SDL_Window* m_window = nullptr;
|
||||||
|
SurfaceCreateInfo m_surfaceCreateInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(VulkanSwapchainFixture, Constructor_ShouldCreateAValidSwapchainWithAtLeastOneImage)
|
||||||
|
{
|
||||||
|
const VulkanSurface surface {m_instance, m_surfaceCreateInfo};
|
||||||
|
const VulkanDevice device {m_instance, &surface, {}};
|
||||||
|
|
||||||
|
const VulkanSwapchain swapchain {device, surface, glm::uvec2 {64, 64}};
|
||||||
|
|
||||||
|
EXPECT_TRUE(swapchain.GetHandle());
|
||||||
|
ASSERT_FALSE(swapchain.GetImages().empty());
|
||||||
|
|
||||||
|
const VulkanImage& image = swapchain.GetImages().front();
|
||||||
|
EXPECT_TRUE(image.GetHandle());
|
||||||
|
EXPECT_NE(image.GetFormat(), PixelFormat::Undefined);
|
||||||
|
EXPECT_GT(image.GetExtent().x, 0u);
|
||||||
|
EXPECT_GT(image.GetExtent().y, 0u);
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot::Vulkan
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file LazyGlobal.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Utils/LazyGlobal.hpp>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
class DummyValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
std::uint32_t GetValue() const
|
||||||
|
{
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetValue(const std::uint32_t p_value)
|
||||||
|
{
|
||||||
|
m_value = p_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::uint32_t m_value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
class LazyGlobalFixture: public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
LazyGlobal<DummyValue> g_dummyValueA;
|
||||||
|
LazyGlobal<DummyValue, class DummyValueA> g_dummyValueB;
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(LazyGlobalFixture, ArrowOperator)
|
||||||
|
{
|
||||||
|
g_dummyValueA->SetValue(42);
|
||||||
|
|
||||||
|
EXPECT_EQ(g_dummyValueA->GetValue(), 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(LazyGlobalFixture, PointerConversion)
|
||||||
|
{
|
||||||
|
DummyValue* const pointer = g_dummyValueA;
|
||||||
|
pointer->SetValue(7);
|
||||||
|
|
||||||
|
EXPECT_EQ(g_dummyValueA->GetValue(), 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(LazyGlobalFixture, DifferentTags_ShouldYieldIndependentInstancesOfTheSameType)
|
||||||
|
{
|
||||||
|
g_dummyValueA->SetValue(1);
|
||||||
|
g_dummyValueB->SetValue(2);
|
||||||
|
|
||||||
|
EXPECT_EQ(g_dummyValueA->GetValue(), 1);
|
||||||
|
EXPECT_EQ(g_dummyValueB->GetValue(), 2);
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file String.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Utils/String.hpp>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
class StringFixture: public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(StringFixture, EqualNoCase_ShouldReturnTrueForTheSameStringWithDifferentCasing)
|
||||||
|
{
|
||||||
|
EXPECT_TRUE(EqualNoCase("NVIDIA GeForce RTX 5080", "nvidia geforce rtx 5080"));
|
||||||
|
EXPECT_TRUE(EqualNoCase("NVIDIA GeForce RTX 5080", "NVIDIA GeForce RTX 5080"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(StringFixture, EqualNoCase_ShouldReturnFalseForDifferentStrings)
|
||||||
|
{
|
||||||
|
EXPECT_FALSE(EqualNoCase("NVIDIA GeForce RTX 5080", "AMD Radeon RX 7900"));
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -32,4 +32,13 @@ TEST_F(TargetMacrosFixture, GameOrToolmode)
|
|||||||
BIGFOOT_TOOLMODE_ONLY(EXPECT_EQ(value, 2);)
|
BIGFOOT_TOOLMODE_ONLY(EXPECT_EQ(value, 2);)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(TargetMacrosFixture, Lsan)
|
||||||
|
{
|
||||||
|
bool called = false;
|
||||||
|
BIGFOOT_LSAN_ONLY(called = true;)
|
||||||
|
EXPECT_EQ(called, static_cast<bool>(BIGFOOT_LSAN));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[settings]
|
||||||
|
os=Linux
|
||||||
|
arch=x86_64
|
||||||
|
compiler=clang
|
||||||
|
compiler.version=20
|
||||||
|
compiler.libcxx=libstdc++11
|
||||||
|
compiler.cppstd=20
|
||||||
|
compiler.cstd=17
|
||||||
|
compiler.runtime=static
|
||||||
|
|
||||||
|
[conf]
|
||||||
|
tools.system.package_manager:mode=install
|
||||||
|
tools.system.package_manager:sudo=True
|
||||||
|
|
||||||
|
tools.build:compiler_executables={"c": "clang", "cpp": "clang++"}
|
||||||
|
|
||||||
|
tools.info.package_id:confs=["tools.build:cflags$", "tools.build:cxxflags$", "tools.build:defines$", "tools.build:sharedlinkflags$", "tools.build:exelinkflags$", "tools.build:compiler_executables$", "tools.cmake.cmaketoolchain:user_toolchain$", "tools.meson.mesontoolchain:extra_machine_files$"]
|
||||||
|
|
||||||
|
[tool_requires]
|
||||||
|
!cmake/*: cmake/4.3.2
|
||||||
+119
-16
@@ -2,15 +2,113 @@
|
|||||||
setlocal enabledelayedexpansion
|
setlocal enabledelayedexpansion
|
||||||
|
|
||||||
REM --- Validate argument ---------------------------------------------------
|
REM --- Validate argument ---------------------------------------------------
|
||||||
if "%~1"=="force" set "build_option=--build=*" & goto :start
|
if "%~1"=="force" (set "build_option=--build=*" & goto :parseargs)
|
||||||
if "%~1"=="missing" set "build_option=--build=missing" & goto :start
|
if "%~1"=="missing" (set "build_option=--build=missing" & goto :parseargs)
|
||||||
|
|
||||||
echo Usage: %~n0 [force^|missing]
|
call :usage
|
||||||
echo force - Rebuild all packages from source
|
|
||||||
echo missing - Only build packages not already cached
|
|
||||||
exit /b 1
|
exit /b 1
|
||||||
|
|
||||||
:start
|
:usage
|
||||||
|
echo Usage: %~n0 [force^|missing] [Release^|RelWithDebInfo^|Debug] [--profile ^<name^>] [--build-profile ^<name^>] [--variant toolmode^|game] [--unity ON^|OFF] [--tracy True^|False]
|
||||||
|
echo force - Rebuild all packages from source
|
||||||
|
echo missing - Only build packages not already cached
|
||||||
|
echo build_type (optional) - One of: Release, RelWithDebInfo, Debug
|
||||||
|
echo If omitted, all build types are processed
|
||||||
|
echo --profile ^<name^> (optional) - Conan host profile name under ConanProfiles\host (default: msvc)
|
||||||
|
echo --build-profile ^<name^> (optional) - Conan build profile name under ConanProfiles\build (default: msvc)
|
||||||
|
echo --variant ^<name^> (optional) - One of: toolmode, game. If omitted, both are processed
|
||||||
|
echo --unity ^<ON^|OFF^> (optional) - Sets CMAKE_UNITY_BUILD. If omitted, CMake's own default applies
|
||||||
|
echo --tracy ^<True^|False^> (optional) - Sets the bigfoot/*:tracy option (default: True)
|
||||||
|
REM NOTE: flags take their value as a separate argument (space-separated, not --flag=value):
|
||||||
|
REM cmd.exe splits an unquoted --flag=value into two argv entries on the "=", so a single
|
||||||
|
REM %1-style token would only ever see "--flag".
|
||||||
|
exit /b 0
|
||||||
|
|
||||||
|
:parseargs
|
||||||
|
set "profile_name=msvc"
|
||||||
|
set "build_profile_name=msvc"
|
||||||
|
set "variant_arg="
|
||||||
|
set "unity_val="
|
||||||
|
set "tracy_val=True"
|
||||||
|
set "build_type_arg="
|
||||||
|
|
||||||
|
shift
|
||||||
|
:argloop
|
||||||
|
if "%~1"=="" goto :argsdone
|
||||||
|
set "arg=%~1"
|
||||||
|
|
||||||
|
if /i "%arg%"=="--profile" (
|
||||||
|
set "profile_name=%~2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
goto :argloop
|
||||||
|
)
|
||||||
|
if /i "%arg%"=="--build-profile" (
|
||||||
|
set "build_profile_name=%~2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
goto :argloop
|
||||||
|
)
|
||||||
|
if /i "%arg%"=="--variant" (
|
||||||
|
set "variant_arg=%~2"
|
||||||
|
if /i not "!variant_arg!"=="toolmode" if /i not "!variant_arg!"=="game" goto :bad_variant
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
goto :argloop
|
||||||
|
)
|
||||||
|
if /i "%arg%"=="--unity" (
|
||||||
|
set "unity_val=%~2"
|
||||||
|
if /i not "!unity_val!"=="ON" if /i not "!unity_val!"=="OFF" goto :bad_unity
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
goto :argloop
|
||||||
|
)
|
||||||
|
if /i "%arg%"=="--tracy" (
|
||||||
|
set "tracy_val=%~2"
|
||||||
|
if /i not "!tracy_val!"=="True" if /i not "!tracy_val!"=="False" goto :bad_tracy
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
goto :argloop
|
||||||
|
)
|
||||||
|
|
||||||
|
if /i "%arg%"=="Release" (set "build_type_arg=Release" & shift & goto :argloop)
|
||||||
|
if /i "%arg%"=="RelWithDebInfo" (set "build_type_arg=RelWithDebInfo" & shift & goto :argloop)
|
||||||
|
if /i "%arg%"=="Debug" (set "build_type_arg=Debug" & shift & goto :argloop)
|
||||||
|
|
||||||
|
echo ERROR: Unrecognized argument '%arg%'
|
||||||
|
call :usage
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
REM goto targets below are unindented on purpose: exit /b from deep inside nested
|
||||||
|
REM if-blocks does not reliably propagate its code out to the caller of this script,
|
||||||
|
REM so validation failures jump out to a plain top-level "exit /b" instead.
|
||||||
|
:bad_variant
|
||||||
|
echo ERROR: Invalid variant '%variant_arg%'. Must be one of: toolmode, game
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:bad_unity
|
||||||
|
echo ERROR: Invalid value for --unity '%unity_val%'. Must be ON or OFF
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:bad_tracy
|
||||||
|
echo ERROR: Invalid value for --tracy '%tracy_val%'. Must be True or False
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:argsdone
|
||||||
|
if defined build_type_arg (
|
||||||
|
set "build_types=!build_type_arg!"
|
||||||
|
) else (
|
||||||
|
set "build_types=Release RelWithDebInfo Debug"
|
||||||
|
)
|
||||||
|
if defined variant_arg (
|
||||||
|
set "variants=!variant_arg!"
|
||||||
|
) else (
|
||||||
|
set "variants=toolmode game"
|
||||||
|
)
|
||||||
|
|
||||||
|
set "profile_stripped=!profile_name:asan=!"
|
||||||
|
if not "!profile_stripped!"=="!profile_name!" (set "is_asan=1") else (set "is_asan=0")
|
||||||
|
|
||||||
REM --- Register remote (skip if already registered) ------------------------
|
REM --- Register remote (skip if already registered) ------------------------
|
||||||
conan remote list | findstr /i "bigfootpackages" >nul 2>&1
|
conan remote list | findstr /i "bigfootpackages" >nul 2>&1
|
||||||
if errorlevel 1 (
|
if errorlevel 1 (
|
||||||
@@ -25,19 +123,21 @@ if errorlevel 1 (
|
|||||||
)
|
)
|
||||||
|
|
||||||
REM --- Shared flags -----------------------------------------------------------
|
REM --- Shared flags -----------------------------------------------------------
|
||||||
set "conan_common_base=--remote=bigfootpackages -pr:h=./ConanProfiles/host/msvc -pr:b=./ConanProfiles/build/msvc -o bigfoot/*:build_tests=True -o bigfoot/*:build_benchmarks=True -o bigfoot/*:tracy=True -o bigfoot/*:vulkan=True"
|
set "conan_common_base=--remote=bigfootpackages -pr:h=./ConanProfiles/host/!profile_name! -pr:b=./ConanProfiles/build/!build_profile_name! -o bigfoot/*:build_tests=True -o bigfoot/*:build_benchmarks=True -o bigfoot/*:tracy=!tracy_val! -o bigfoot/*:vulkan=True"
|
||||||
|
|
||||||
REM --- Install dependencies for each build type/variant -----------------------
|
REM --- Install dependencies for each build type/variant -----------------------
|
||||||
for %%C in (Release RelWithDebInfo Debug) do (
|
for %%C in (%build_types%) do (
|
||||||
echo.
|
echo.
|
||||||
echo [%%C] Installing dependencies...
|
echo [%%C] Installing dependencies...
|
||||||
if "%%C"=="Release" set "config_profile=release"
|
if /i "%%C"=="Release" set "config_profile=./ConanProfiles/Configurations/release"
|
||||||
if "%%C"=="RelWithDebInfo" set "config_profile=relwithdebinfo"
|
if /i "%%C"=="RelWithDebInfo" set "config_profile=./ConanProfiles/Configurations/relwithdebinfo"
|
||||||
if "%%C"=="Debug" set "config_profile=debug"
|
if /i "%%C"=="Debug" set "config_profile=./ConanProfiles/Configurations/debug"
|
||||||
for %%V in (toolmode game) do (
|
if "!is_asan!"=="1" if /i "%%C"=="Release" set "config_profile=./ConanProfiles/Configurations/release_noipo"
|
||||||
|
|
||||||
|
for %%V in (%variants%) do (
|
||||||
set "toolmode_val=False"
|
set "toolmode_val=False"
|
||||||
if "%%V"=="toolmode" set "toolmode_val=True"
|
if /i "%%V"=="toolmode" set "toolmode_val=True"
|
||||||
conan install . !conan_common_base! -of build-windows-%%V -o bigfoot/*:toolmode=!toolmode_val! %build_option% -pr:h=./ConanProfiles/Configurations/!config_profile! -pr:b=./ConanProfiles/Configurations/!config_profile!
|
conan install . !conan_common_base! -of build-windows-%%V -o bigfoot/*:toolmode=!toolmode_val! %build_option% -pr:h=!config_profile! -pr:b=!config_profile!
|
||||||
if errorlevel 1 (
|
if errorlevel 1 (
|
||||||
echo ERROR: conan install failed for build type %%C ^(%%V^)
|
echo ERROR: conan install failed for build type %%C ^(%%V^)
|
||||||
exit /b 1
|
exit /b 1
|
||||||
@@ -53,10 +153,13 @@ REM --- Activate build environment and run CMake -------------------------------
|
|||||||
echo.
|
echo.
|
||||||
echo Activating build environment and configuring CMake...
|
echo Activating build environment and configuring CMake...
|
||||||
|
|
||||||
for %%V in (toolmode game) do (
|
set "unity_args="
|
||||||
|
if defined unity_val set "unity_args=-DCMAKE_UNITY_BUILD=!unity_val!"
|
||||||
|
|
||||||
|
for %%V in (%variants%) do (
|
||||||
mkdir graphviz-windows-%%V 2>nul
|
mkdir graphviz-windows-%%V 2>nul
|
||||||
|
|
||||||
powershell -ExecutionPolicy Bypass -Command "& 'build-windows-%%V/build/generators/conanbuild.ps1'; cmake -S . -B build-windows-%%V --toolchain build-windows-%%V/build/generators/conan_toolchain.cmake --graphviz=graphviz-windows-%%V/graph.dot; if ($LASTEXITCODE -ne 0) { Write-Host 'ERROR: CMake configuration failed'; exit 1 }"
|
powershell -ExecutionPolicy Bypass -Command "& 'build-windows-%%V/build/generators/conanbuild.ps1'; cmake -S . -B build-windows-%%V --toolchain build-windows-%%V/build/generators/conan_toolchain.cmake !unity_args! --graphviz=graphviz-windows-%%V/graph.dot; if ($LASTEXITCODE -ne 0) { Write-Host 'ERROR: CMake configuration failed'; exit 1 }"
|
||||||
if errorlevel 1 (
|
if errorlevel 1 (
|
||||||
echo ERROR: Build environment or CMake step failed for %%V.
|
echo ERROR: Build environment or CMake step failed for %%V.
|
||||||
exit /b 1
|
exit /b 1
|
||||||
|
|||||||
+121
-44
@@ -1,44 +1,110 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# ─── Validate arguments ───────────────────────────────────────────────────────
|
usage() {
|
||||||
if [[ $# -lt 1 ]]; then
|
echo "Usage: $(basename "$0") [force|missing] [Release|RelWithDebInfo|Debug] [--profile=<name>] [--build-profile=<name>] [--variant=toolmode|game] [--unity=ON|OFF] [--tracy=True|False]"
|
||||||
echo "Usage: $(basename "$0") [force|missing] [Release|RelWithDebInfo|Debug]"
|
echo " force - Rebuild all packages from source"
|
||||||
echo " force - Rebuild all packages from source"
|
echo " missing - Only build packages not already cached"
|
||||||
echo " missing - Only build packages not already cached"
|
|
||||||
echo " build_type (optional) - One of: Release, RelWithDebInfo, Debug"
|
echo " build_type (optional) - One of: Release, RelWithDebInfo, Debug"
|
||||||
echo " If omitted, all build types are processed"
|
echo " If omitted, all build types are processed"
|
||||||
|
echo " --profile=<name> (optional) - Conan host profile under ./ConanProfiles/host (default: clang)"
|
||||||
|
echo " --build-profile=<name> (optional) - Conan build profile under ./ConanProfiles/build"
|
||||||
|
echo " If omitted, it is derived from --profile: ./ConanProfiles/build/clang,"
|
||||||
|
echo " or .../clang_asan when <name> contains 'asan'"
|
||||||
|
echo " --variant=<name> (optional) - One of: toolmode, game. If omitted, both are processed"
|
||||||
|
echo " --unity=<ON|OFF> (optional) - Sets CMAKE_UNITY_BUILD. If omitted, CMake's own default applies"
|
||||||
|
echo " --tracy=<True|False> (optional) - Sets the bigfoot/*:tracy option (default: True)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Validate arguments ───────────────────────────────────────────────────────
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case "${1:-}" in
|
case "$1" in
|
||||||
force) build_option="--build=*" ;;
|
force) build_option="--build=*" ;;
|
||||||
missing) build_option="--build=missing" ;;
|
missing) build_option="--build=missing" ;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $(basename "$0") [force|missing] [Release|RelWithDebInfo|Debug]"
|
usage
|
||||||
echo " force - Rebuild all packages from source"
|
|
||||||
echo " missing - Only build packages not already cached"
|
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
shift
|
||||||
|
|
||||||
# ─── Validate optional build_type argument ────────────────────────────────────
|
profile_name="clang"
|
||||||
all_build_types=(Release RelWithDebInfo Debug)
|
build_profile_arg=""
|
||||||
|
variant_arg=""
|
||||||
|
unity_val=""
|
||||||
|
tracy_val="True"
|
||||||
|
build_type_arg=""
|
||||||
|
|
||||||
if [[ -n "${2:-}" ]]; then
|
for arg in "$@"; do
|
||||||
case "${2}" in
|
case "$arg" in
|
||||||
|
--profile=*)
|
||||||
|
profile_name="${arg#--profile=}"
|
||||||
|
;;
|
||||||
|
--build-profile=*)
|
||||||
|
build_profile_arg="${arg#--build-profile=}"
|
||||||
|
;;
|
||||||
|
--variant=*)
|
||||||
|
variant_arg="${arg#--variant=}"
|
||||||
|
case "$variant_arg" in
|
||||||
|
toolmode|game) ;;
|
||||||
|
*)
|
||||||
|
echo "ERROR: Invalid variant '${variant_arg}'. Must be one of: toolmode, game"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
--unity=*)
|
||||||
|
unity_val="${arg#--unity=}"
|
||||||
|
case "$unity_val" in
|
||||||
|
ON|OFF) ;;
|
||||||
|
*)
|
||||||
|
echo "ERROR: Invalid value for --unity '${unity_val}'. Must be ON or OFF"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
--tracy=*)
|
||||||
|
tracy_val="${arg#--tracy=}"
|
||||||
|
case "$tracy_val" in
|
||||||
|
True|False) ;;
|
||||||
|
*)
|
||||||
|
echo "ERROR: Invalid value for --tracy '${tracy_val}'. Must be True or False"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
Release|RelWithDebInfo|Debug)
|
Release|RelWithDebInfo|Debug)
|
||||||
build_types=("${2}")
|
if [[ -n "$build_type_arg" ]]; then
|
||||||
|
echo "ERROR: build type specified more than once"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
build_type_arg="$arg"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "ERROR: Invalid build type '${2}'. Must be one of: Release, RelWithDebInfo, Debug"
|
echo "ERROR: Unrecognized argument '${arg}'"
|
||||||
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
all_build_types=(Release RelWithDebInfo Debug)
|
||||||
|
if [[ -n "$build_type_arg" ]]; then
|
||||||
|
build_types=("$build_type_arg")
|
||||||
else
|
else
|
||||||
build_types=("${all_build_types[@]}")
|
build_types=("${all_build_types[@]}")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$variant_arg" ]]; then
|
||||||
|
variants=("$variant_arg")
|
||||||
|
else
|
||||||
|
variants=(toolmode game)
|
||||||
|
fi
|
||||||
|
|
||||||
# ─── Register remote (skip if already registered) ─────────────────────────────
|
# ─── Register remote (skip if already registered) ─────────────────────────────
|
||||||
if conan remote list 2>/dev/null | grep -qi "bigfootpackages"; then
|
if conan remote list 2>/dev/null | grep -qi "bigfootpackages"; then
|
||||||
echo "Conan remote 'bigfootpackages' already registered, skipping."
|
echo "Conan remote 'bigfootpackages' already registered, skipping."
|
||||||
@@ -51,43 +117,48 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ─── Shared flags ─────────────────────────────────────────────────────────────
|
# ─── Shared flags ─────────────────────────────────────────────────────────────
|
||||||
conan_common_toolmode=(
|
host_profile="./ConanProfiles/host/${profile_name}"
|
||||||
|
if [[ -n "$build_profile_arg" ]]; then
|
||||||
|
build_profile="./ConanProfiles/build/${build_profile_arg}"
|
||||||
|
else
|
||||||
|
build_profile="./ConanProfiles/build/clang"
|
||||||
|
if [[ "$profile_name" == *asan* ]]; then
|
||||||
|
build_profile="./ConanProfiles/build/clang_asan"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
conan_common_base=(
|
||||||
--remote=bigfootpackages
|
--remote=bigfootpackages
|
||||||
-pr:h=./ConanProfiles/host/clang
|
-pr:h="${host_profile}"
|
||||||
-pr:b=./ConanProfiles/build/clang
|
-pr:b="${build_profile}"
|
||||||
-of build-linux-toolmode
|
|
||||||
-o "bigfoot/*:build_tests=True"
|
-o "bigfoot/*:build_tests=True"
|
||||||
-o "bigfoot/*:build_benchmarks=True"
|
-o "bigfoot/*:build_benchmarks=True"
|
||||||
-o "bigfoot/*:tracy=True"
|
-o "bigfoot/*:tracy=${tracy_val}"
|
||||||
-o "bigfoot/*:vulkan=True"
|
-o "bigfoot/*:vulkan=True"
|
||||||
-o "bigfoot/*:toolmode=True"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
conan_common_game=(
|
# ─── Install dependencies for each build type/variant ─────────────────────────
|
||||||
--remote=bigfootpackages
|
|
||||||
-pr:h=./ConanProfiles/host/clang
|
|
||||||
-pr:b=./ConanProfiles/build/clang
|
|
||||||
-of build-linux-game
|
|
||||||
-o "bigfoot/*:build_tests=True"
|
|
||||||
-o "bigfoot/*:build_benchmarks=True"
|
|
||||||
-o "bigfoot/*:tracy=True"
|
|
||||||
-o "bigfoot/*:vulkan=True"
|
|
||||||
-o "bigfoot/*:toolmode=False"
|
|
||||||
)
|
|
||||||
|
|
||||||
# ─── Install dependencies for each build type ─────────────────────────────────
|
|
||||||
for build_type in "${build_types[@]}"; do
|
for build_type in "${build_types[@]}"; do
|
||||||
echo
|
echo
|
||||||
echo "[${build_type}] Installing dependencies..."
|
echo "[${build_type}] Installing dependencies..."
|
||||||
build_type_profile="./ConanProfiles/Configurations/${build_type,,}"
|
|
||||||
if ! conan install . "${conan_common_toolmode[@]}" ${build_option} -pr:h="${build_type_profile}" -pr:b="${build_type_profile}"; then
|
config_profile="./ConanProfiles/Configurations/${build_type,,}"
|
||||||
echo "ERROR: conan install failed for build type ${build_type}"
|
if [[ "$profile_name" == *asan* && "$build_type" == "Release" ]]; then
|
||||||
exit 1
|
config_profile="./ConanProfiles/Configurations/release_noipo"
|
||||||
fi
|
|
||||||
if ! conan install . "${conan_common_game[@]}" ${build_option} -pr:h="${build_type_profile}" -pr:b="${build_type_profile}"; then
|
|
||||||
echo "ERROR: conan install failed for build type ${build_type}"
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
for variant in "${variants[@]}"; do
|
||||||
|
toolmode_val="False"
|
||||||
|
[[ "$variant" == "toolmode" ]] && toolmode_val="True"
|
||||||
|
|
||||||
|
if ! conan install . "${conan_common_base[@]}" ${build_option} \
|
||||||
|
-pr:h="${config_profile}" -pr:b="${config_profile}" \
|
||||||
|
-o "bigfoot/*:toolmode=${toolmode_val}" \
|
||||||
|
-of "build-linux-${variant}"; then
|
||||||
|
echo "ERROR: conan install failed for build type ${build_type} (${variant})"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
echo "[${build_type}] Done."
|
echo "[${build_type}] Done."
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -98,11 +169,16 @@ echo "All build types installed successfully."
|
|||||||
echo
|
echo
|
||||||
echo "Configuring CMake for each build type..."
|
echo "Configuring CMake for each build type..."
|
||||||
|
|
||||||
|
unity_args=()
|
||||||
|
if [[ -n "$unity_val" ]]; then
|
||||||
|
unity_args=(-DCMAKE_UNITY_BUILD="${unity_val}")
|
||||||
|
fi
|
||||||
|
|
||||||
for build_type in "${build_types[@]}"; do
|
for build_type in "${build_types[@]}"; do
|
||||||
echo
|
echo
|
||||||
echo "[${build_type}] Activating build environment..."
|
echo "[${build_type}] Activating build environment..."
|
||||||
|
|
||||||
for variant in toolmode game; do
|
for variant in "${variants[@]}"; do
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
source "build-linux-${variant}/build/${build_type}/generators/conanbuild.sh"
|
source "build-linux-${variant}/build/${build_type}/generators/conanbuild.sh"
|
||||||
|
|
||||||
@@ -112,6 +188,7 @@ for build_type in "${build_types[@]}"; do
|
|||||||
if ! cmake -S . -B "build-linux-${variant}/${build_type}" \
|
if ! cmake -S . -B "build-linux-${variant}/${build_type}" \
|
||||||
--toolchain "build-linux-${variant}/build/${build_type}/generators/conan_toolchain.cmake" \
|
--toolchain "build-linux-${variant}/build/${build_type}/generators/conan_toolchain.cmake" \
|
||||||
-DCMAKE_BUILD_TYPE="${build_type}" \
|
-DCMAKE_BUILD_TYPE="${build_type}" \
|
||||||
|
"${unity_args[@]}" \
|
||||||
-G "Ninja" \
|
-G "Ninja" \
|
||||||
--graphviz="graphviz-linux-${variant}/${build_type}/graph.dot"; then
|
--graphviz="graphviz-linux-${variant}/${build_type}/graph.dot"; then
|
||||||
echo "ERROR: CMake configuration failed for build type ${build_type} (${variant})."
|
echo "ERROR: CMake configuration failed for build type ${build_type} (${variant})."
|
||||||
@@ -122,4 +199,4 @@ for build_type in "${build_types[@]}"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "CMake configuration successful."
|
echo "CMake configuration successful."
|
||||||
|
|||||||
Reference in New Issue
Block a user