Compare commits
52
Commits
Vulkan
..
e51afcbdf5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e51afcbdf5 | ||
|
|
9ae55ac60f | ||
|
|
841ba38be8 | ||
|
|
6ccf56eb38 | ||
|
|
fc5794b5c7 | ||
|
|
3e3e3798ae | ||
|
|
ed5061dc52 | ||
|
|
f518bf7c8a | ||
|
|
eb2af20abd | ||
|
|
8f047767ae | ||
|
|
02e587bf86 | ||
|
|
fff7733cdb | ||
|
|
c6e801abb6 | ||
|
|
77e26cfa83 | ||
|
|
be85c650b9 | ||
|
|
d32d1d7229 | ||
|
|
65da7522ef | ||
|
|
2572922af9 | ||
|
|
03e501f1b2 | ||
|
|
e78d5378a4 | ||
|
|
1b9e17d6bc | ||
|
|
4b07aa7fa2 | ||
|
|
081e23360f | ||
|
|
eb22baacf9 | ||
|
|
0bee2c22ca | ||
|
|
1307273150 | ||
|
|
8b2ad9de35 | ||
|
|
1c2f9344b0 | ||
|
|
09014277a1 | ||
|
|
8e28f50e1d | ||
|
|
407401bea2 | ||
|
|
cbf4de6003 | ||
|
|
0ba9e062d4 | ||
|
|
33331ea529 | ||
|
|
8a36af6bcb | ||
|
|
c6ccdf8214 | ||
|
|
d9f4a0e896 | ||
|
|
1d572b9d09 | ||
|
|
870bfe57e6 | ||
|
|
9978ff358b | ||
|
|
8be97bacb5 | ||
|
|
cea3b8a904 | ||
|
|
1d2dafff48 | ||
|
|
17ab916b11 | ||
|
|
3c306dd2c7 | ||
|
|
a1e4119311 | ||
|
|
1bae20b79c | ||
|
|
39d2ddbe49 | ||
|
|
6bc25a776e | ||
|
|
96c4353a8a | ||
|
|
9733860ecd | ||
|
|
2062b8169f |
+12
-63
@@ -121,79 +121,28 @@ SpaceInEmptyBlock: true
|
|||||||
PenaltyBreakAssignment: 200
|
PenaltyBreakAssignment: 200
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
IncludeCategories:
|
IncludeCategories:
|
||||||
- Regex: '^<GraphicsCore/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 16
|
|
||||||
- Regex: '^<GraphicsVulkan/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 17
|
|
||||||
- Regex: '^<GraphicsInterface/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 18
|
|
||||||
- Regex: '^<Engine/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 19
|
|
||||||
- Regex: '^<System/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 20
|
|
||||||
- Regex: '^<Utils/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 21
|
|
||||||
- Regex: '^<SasquatchBaker/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 22
|
|
||||||
- Regex: '^<EngineTests/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 23
|
|
||||||
- Regex: '^<SystemTests/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 24
|
|
||||||
- Regex: '^<UtilsTests/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 25
|
|
||||||
- Regex: '^<AssetsForTesting/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 26
|
|
||||||
- Regex: '^<SasquatchBakerTests/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 27
|
|
||||||
- Regex: '^<EngineBenchmarks/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 28
|
|
||||||
- Regex: '^<AssetsForBenchmarking/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 29
|
|
||||||
- Regex: '^<SasquatchBakerBenchmarks/.*_generated\.h(pp)?>$'
|
|
||||||
Priority: 30
|
|
||||||
- Regex: '^<GraphicsCore/'
|
|
||||||
Priority: 1
|
|
||||||
- Regex: '^<GraphicsVulkan/'
|
|
||||||
Priority: 2
|
|
||||||
- Regex: '^<GraphicsInterface/'
|
|
||||||
Priority: 3
|
|
||||||
- Regex: '^<Engine/'
|
- Regex: '^<Engine/'
|
||||||
Priority: 4
|
Priority: 1
|
||||||
- Regex: '^<System/'
|
- Regex: '^<System/'
|
||||||
Priority: 5
|
Priority: 2
|
||||||
- Regex: '^<Utils/'
|
- Regex: '^<Utils/'
|
||||||
Priority: 6
|
Priority: 3
|
||||||
- Regex: '^<SasquatchBaker/'
|
|
||||||
Priority: 7
|
|
||||||
- Regex: '^<EngineTests/'
|
- Regex: '^<EngineTests/'
|
||||||
Priority: 8
|
Priority: 4
|
||||||
- Regex: '^<SystemTests/'
|
- Regex: '^<SystemTests/'
|
||||||
Priority: 9
|
Priority: 5
|
||||||
- Regex: '^<UtilsTests/'
|
- Regex: '^<UtilsTests/'
|
||||||
Priority: 10
|
Priority: 6
|
||||||
- Regex: '^<AssetsForTesting/'
|
- Regex: '^<AssetsForTesting/'
|
||||||
Priority: 11
|
Priority: 7
|
||||||
- Regex: '^<SasquatchBakerTests/'
|
|
||||||
Priority: 12
|
|
||||||
- Regex: '^<EngineBenchmarks/'
|
- Regex: '^<EngineBenchmarks/'
|
||||||
Priority: 13
|
Priority: 8
|
||||||
- Regex: '^<AssetsForBenchmarking/'
|
- Regex: '^<AssetsForBenchmarking/'
|
||||||
Priority: 14
|
Priority: 9
|
||||||
- Regex: '^<SasquatchBakerBenchmarks/'
|
|
||||||
Priority: 15
|
|
||||||
- Regex: '^<[a-zA-Z0-9_/]+\.h>'
|
- Regex: '^<[a-zA-Z0-9_/]+\.h>'
|
||||||
Priority: 31
|
Priority: 10
|
||||||
- Regex: '^<[a-zA-Z0-9_/]+\.hpp>'
|
- Regex: '^<[a-zA-Z0-9_/]+\.hpp>'
|
||||||
Priority: 31
|
Priority: 10
|
||||||
- Regex: '^<[a-zA-Z0-9_/]+>'
|
- Regex: '^<[a-zA-Z0-9_/]+>'
|
||||||
Priority: 32
|
Priority: 11
|
||||||
MainIncludeChar: AngleBracket
|
MainIncludeChar: AngleBracket
|
||||||
Macros:
|
|
||||||
- 'BIGFOOT_OPTIMIZED_ONLY(x)=x'
|
|
||||||
- 'BIGFOOT_OPTIMIZED_ONLY(x,y)=x,y'
|
|
||||||
- 'BIGFOOT_NOT_OPTIMIZED_ONLY(x)=x'
|
|
||||||
- 'BIGFOOT_NOT_OPTIMIZED_ONLY(x,y)=x,y'
|
|
||||||
- 'BIGFOOT_TOOLMODE_ONLY(x)=x'
|
|
||||||
- 'BIGFOOT_TOOLMODE_ONLY(x,y)=x,y'
|
|
||||||
- 'BIGFOOT_GAME_ONLY(x)=x'
|
|
||||||
- 'BIGFOOT_GAME_ONLY(x,y)=x,y'
|
|
||||||
|
|||||||
+1
-5
@@ -11,13 +11,9 @@ Checks: >
|
|||||||
portability-*,
|
portability-*,
|
||||||
|
|
||||||
-modernize-use-trailing-return-type,
|
-modernize-use-trailing-return-type,
|
||||||
-modernize-use-auto,
|
|
||||||
-readability-avoid-const-params-in-decls,
|
-readability-avoid-const-params-in-decls,
|
||||||
-cppcoreguidelines-macro-usage,
|
-cppcoreguidelines-macro-usage,
|
||||||
-cppcoreguidelines-avoid-do-while,
|
-cppcoreguidelines-avoid-do-while
|
||||||
-cppcoreguidelines-pro-bounds-avoid-unchecked-container-access,
|
|
||||||
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
|
||||||
-cppcoreguidelines-pro-type-reinterpret-cast
|
|
||||||
|
|
||||||
ExcludeHeaderFilterRegex: '_generated.*'
|
ExcludeHeaderFilterRegex: '_generated.*'
|
||||||
|
|
||||||
|
|||||||
+13
-15
@@ -15,16 +15,13 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
build_type:
|
build_type: ["Debug", "RelWithDebInfo", "Release"]
|
||||||
- { value: "Debug", profile: "debug" }
|
|
||||||
- { value: "RelWithDebInfo", profile: "relwithdebinfo" }
|
|
||||||
- { value: "Release", profile: "release" }
|
|
||||||
unity_build: ["ON", "OFF"]
|
unity_build: ["ON", "OFF"]
|
||||||
conan_profile: ["clang", "clang_asan"]
|
conan_profile: ["./ConanProfiles/host/clang", "./ConanProfiles/host/clang_asan"]
|
||||||
variant:
|
toolmode:
|
||||||
- { value: "True", name: "toolmode" }
|
- { value: "True", name: "toolmode" }
|
||||||
- { value: "False", name: "game" }
|
- { value: "False", name: "game" }
|
||||||
name: "Build & Test ${{ matrix.build_type.value }} with ${{ matrix.conan_profile }} (Unity Build: ${{ matrix.unity_build }}, Variant: ${{ matrix.variant.name }})"
|
name: "Build & Test ${{ matrix.build_type }} with ${{ matrix.conan_profile }} (Unity Build: ${{ matrix.unity_build }}, Variant: ${{ matrix.toolmode.name }})"
|
||||||
steps:
|
steps:
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
run: apt-get update && apt-get install -y nodejs
|
run: apt-get update && apt-get install -y nodejs
|
||||||
@@ -36,17 +33,18 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
bash ./generate_bigfoot.sh missing ${{ matrix.build_type.value }} --profile=${{ matrix.conan_profile }} --variant=${{ matrix.variant.name }} --unity=${{ matrix.unity_build }} --tracy=False
|
conan install . --remote=bigfootpackages -pr:h=${{ matrix.conan_profile }} -pr:b=./ConanProfiles/build/clang --build=missing -s build_type=${{ matrix.build_type }} -o bigfoot/*:build_tests=True -o bigfoot/*:build_benchmarks=True -o bigfoot/*:tracy=False -o bigfoot/*:vulkan=True -o bigfoot/*:toolmode=${{ matrix.toolmode.value }} -of build-${{ matrix.toolmode.name }}
|
||||||
. ./build-linux-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/conanbuild.sh
|
. ./build-${{ matrix.toolmode.name }}/build/${{ matrix.build_type }}/generators/conanbuild.sh
|
||||||
cmake --build build-linux-${{ matrix.variant.name }}/${{ matrix.build_type.value }} --parallel $(nproc)
|
cmake -S . -B ./build-${{ matrix.toolmode.name }}/${{ matrix.build_type }} --toolchain ./build-${{ matrix.toolmode.name }}/build/${{ matrix.build_type }}/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_UNITY_BUILD=${{ matrix.unity_build }} -G "Ninja"
|
||||||
. ./build-linux-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/deactivate_conanbuild.sh
|
cmake --build build-${{ matrix.toolmode.name }}/${{ matrix.build_type }} --parallel $(nproc)
|
||||||
|
. ./build-${{ matrix.toolmode.name }}/build/${{ matrix.build_type }}/generators/deactivate_conanbuild.sh
|
||||||
|
|
||||||
- name: Unit Tests
|
- name: Unit Tests
|
||||||
run: |
|
run: |
|
||||||
cd ./build-linux-${{ matrix.variant.name }}/${{ matrix.build_type.value }}
|
cd ./build-${{ matrix.toolmode.name }}/${{ matrix.build_type }}
|
||||||
. ../../build-linux-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/conanbuild.sh
|
. ../../build-${{ matrix.toolmode.name }}/build/${{ matrix.build_type }}/generators/conanbuild.sh
|
||||||
weston-run ctest . --output-on-failure
|
xvfb-run ctest . --output-on-failure
|
||||||
. ../../build-linux-${{ matrix.variant.name }}/build/${{ matrix.build_type.value }}/generators/deactivate_conanbuild.sh
|
. ../../build-${{ matrix.toolmode.name }}/build/${{ matrix.build_type }}/generators/deactivate_conanbuild.sh
|
||||||
|
|
||||||
clang-format:
|
clang-format:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -5,10 +5,6 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- Development
|
- Development
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- Development
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-test:
|
build-and-test:
|
||||||
@@ -17,14 +13,7 @@ jobs:
|
|||||||
container:
|
container:
|
||||||
image: git.romainboullard.com/bigfootdev/linuxcppbuilder:development
|
image: git.romainboullard.com/bigfootdev/linuxcppbuilder:development
|
||||||
|
|
||||||
strategy:
|
name: "Sonarqube"
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
variant:
|
|
||||||
- { value: "True", name: "toolmode", projectKey: "Bigfoot-Tool", projectName: "Bigfoot Tool" }
|
|
||||||
- { value: "False", name: "game", projectKey: "Bigfoot-Game", projectName: "Bigfoot Game" }
|
|
||||||
|
|
||||||
name: "Sonarqube (${{ matrix.variant.name }})"
|
|
||||||
steps:
|
steps:
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
run: apt-get update && apt-get install -y nodejs
|
run: apt-get update && apt-get install -y nodejs
|
||||||
@@ -34,63 +23,28 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
||||||
|
|
||||||
- name: Read version
|
|
||||||
id: version
|
|
||||||
run: echo "version=$(cat VERSION)" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
bash ./generate_bigfoot.sh missing Debug --profile=clang_coverage --variant=${{ matrix.variant.name }} --tracy=False
|
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/*:build_tools=True -o bigfoot/*:vulkan=True
|
||||||
. ./build-linux-${{ matrix.variant.name }}/build/Debug/generators/conanbuild.sh
|
. ./build/Debug/generators/conanbuild.sh
|
||||||
cmake --build build-linux-${{ matrix.variant.name }}/Debug --parallel $(nproc)
|
cmake -S . -B ./build/Debug --toolchain ./build/Debug/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -G "Ninja"
|
||||||
. ./build-linux-${{ matrix.variant.name }}/build/Debug/generators/deactivate_conanbuild.sh
|
cmake --build build/Debug --parallel $(nproc)
|
||||||
|
. ./build/Debug/generators/deactivate_conanbuild.sh
|
||||||
- name: Run tests
|
|
||||||
run: |
|
|
||||||
cd ./build-linux-${{ matrix.variant.name }}/Debug
|
|
||||||
. ../../build-linux-${{ matrix.variant.name }}/build/Debug/generators/conanbuild.sh
|
|
||||||
LLVM_PROFILE_FILE="%p.profraw%c" weston-run ctest --output-on-failure
|
|
||||||
. ../../build-linux-${{ matrix.variant.name }}/build/Debug/generators/deactivate_conanbuild.sh
|
|
||||||
|
|
||||||
- name: Clang-Tidy
|
- name: Clang-Tidy
|
||||||
run: run-clang-tidy -p ./build-linux-${{ matrix.variant.name }}/Debug/ > tidy_result.txt
|
run: run-clang-tidy -p ./build/Debug/ >> tidy_result.txt
|
||||||
|
|
||||||
- name: Infer
|
- name: Infer
|
||||||
run: infer run --compilation-database build-linux-${{ matrix.variant.name }}/Debug/compile_commands.json
|
run: infer run --compilation-database build/Debug/compile_commands.json
|
||||||
|
|
||||||
- name: Generate coverage report
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
# gcovr's own LLVM-JSON reader only understands coverage-mapping format
|
|
||||||
# 2.x; this image's clang 22 llvm-cov emits format 3.x, which gcovr
|
|
||||||
# rejects outright ("Wrong major version"). Bypassing gcovr's JSON
|
|
||||||
# path entirely: llvm-cov's lcov exporter is a separate, unaffected
|
|
||||||
# code path, so merge -> export lcov -> convert lcov to Cobertura.
|
|
||||||
llvm-profdata merge -sparse $(find build-linux-${{ matrix.variant.name }}/Debug -name "*.profraw") -o merged.profdata
|
|
||||||
BINARIES=($(find build-linux-${{ matrix.variant.name }}/Debug -maxdepth 8 -type f -executable -iname "*Tests"))
|
|
||||||
OBJECT_ARGS=$(printf -- '-object %s ' "${BINARIES[@]:1}")
|
|
||||||
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
|
|
||||||
# gcovr's existing pipx venv and expose its CLI on PATH.
|
|
||||||
pipx inject gcovr lcov_cobertura --include-apps
|
|
||||||
lcov_cobertura coverage.lcov -b . -o coverage.xml
|
|
||||||
|
|
||||||
- name: SonarQube Scan
|
- name: SonarQube Scan
|
||||||
|
if: github.head_ref == 'main' || github.ref_name == 'main'
|
||||||
uses: SonarSource/sonarqube-scan-action@v7.0.0
|
uses: SonarSource/sonarqube-scan-action@v7.0.0
|
||||||
with:
|
with:
|
||||||
args: >
|
args: >
|
||||||
-Dsonar.projectKey=${{ matrix.variant.projectKey }}
|
-Dsonar.cxx.jsonCompilationDatabase=./build/Debug/compile_commands.json
|
||||||
"-Dsonar.projectName=${{ matrix.variant.projectName }}"
|
-Dsonar.verbose=true
|
||||||
-Dsonar.projectVersion=${{ steps.version.outputs.version }}
|
|
||||||
-Dsonar.cxx.jsonCompilationDatabase=./build-linux-${{ matrix.variant.name }}/Debug/compile_commands.json
|
|
||||||
-Dsonar.cxx.xunit.reportPaths=build-linux-${{ matrix.variant.name }}/Debug/TestResults/*.xml
|
|
||||||
-Dsonar.qualitygate.wait=true
|
|
||||||
${{ github.event_name == 'pull_request' &&
|
|
||||||
format('-Dsonar.pullrequest.key={0} -Dsonar.pullrequest.branch={1} -Dsonar.pullrequest.base={2} -Dsonar.analysis.sqbot={3}',
|
|
||||||
github.event.pull_request.number, github.head_ref, github.base_ref, github.event.pull_request.head.sha)
|
|
||||||
|| format('-Dsonar.branch.name={0}', github.ref_name) }}
|
|
||||||
env:
|
env:
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
SONAR_HOST_URL: ${{ secrets.SONAR_HOST }}
|
SONAR_HOST_URL: ${{ secrets.SONAR_HOST }}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
InheritParentConfig: true
|
|
||||||
Checks: >
|
|
||||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
|
||||||
-cppcoreguidelines-avoid-magic-numbers,
|
|
||||||
-readability-magic-numbers
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file BenchmarkAssetReferred.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred.hpp>
|
|
||||||
|
|
||||||
#include <Engine/Asset/AssetHelper.hpp>
|
|
||||||
|
|
||||||
BIGFOOT_ASSET(BenchmarkAssetReferred, ::Bigfoot::BenchmarkAssetReferred)
|
|
||||||
@@ -12,4 +12,6 @@ bigfoot_create_package_lib(
|
|||||||
"${PrivateDependencies}"
|
"${PrivateDependencies}"
|
||||||
"${BigfootPublicDependencies}"
|
"${BigfootPublicDependencies}"
|
||||||
"${BigfootPrivateDependencies}"
|
"${BigfootPrivateDependencies}"
|
||||||
"Bigfoot/Benchmarks")
|
"")
|
||||||
|
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Benchmarks/Bigfoot)
|
||||||
|
|||||||
-3
@@ -1,11 +1,8 @@
|
|||||||
include "Engine/Asset/Reference.fbs";
|
|
||||||
|
|
||||||
namespace Flat.Bigfoot;
|
namespace Flat.Bigfoot;
|
||||||
|
|
||||||
table BenchmarkAsset
|
table BenchmarkAsset
|
||||||
{
|
{
|
||||||
payload: [ubyte];
|
payload: [ubyte];
|
||||||
refs: [HardReference] (native_inline, bigfoot_ref: "::Bigfoot::BenchmarkAssetReferred");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
root_type BenchmarkAsset;
|
root_type BenchmarkAsset;
|
||||||
|
|||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
namespace Flat.Bigfoot;
|
|
||||||
|
|
||||||
table BenchmarkAssetReferred
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
root_type BenchmarkAssetReferred;
|
|
||||||
-25
@@ -1,25 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file BenchmarkAssetReferred.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_ASSETSFORBENCHMARKING_ASSET_BENCHMARKASSETREFERRED_HPP
|
|
||||||
#define BIGFOOT_ASSETSFORBENCHMARKING_ASSET_BENCHMARKASSETREFERRED_HPP
|
|
||||||
#include <Engine/Asset/Asset.hpp>
|
|
||||||
|
|
||||||
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred_generated.hpp>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
struct BenchmarkAssetReferredTraits
|
|
||||||
{
|
|
||||||
using FLAT = ::Flat::Bigfoot::BenchmarkAssetReferred;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BenchmarkAssetReferred: public Asset<BenchmarkAssetReferredTraits>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
} // namespace Bigfoot
|
|
||||||
|
|
||||||
#endif
|
|
||||||
-172
@@ -1,172 +0,0 @@
|
|||||||
// automatically generated by the FlatBuffers compiler, do not modify
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef FLATBUFFERS_GENERATED_BENCHMARKASSETREFERRED_FLAT_BIGFOOT_H_
|
|
||||||
#define FLATBUFFERS_GENERATED_BENCHMARKASSETREFERRED_FLAT_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 Flat {
|
|
||||||
namespace Bigfoot {
|
|
||||||
|
|
||||||
struct BenchmarkAssetReferred;
|
|
||||||
struct BenchmarkAssetReferredBuilder;
|
|
||||||
struct BenchmarkAssetReferredT;
|
|
||||||
|
|
||||||
inline const ::flatbuffers::TypeTable *BenchmarkAssetReferredTypeTable();
|
|
||||||
|
|
||||||
struct BenchmarkAssetReferredT : public ::flatbuffers::NativeTable {
|
|
||||||
typedef BenchmarkAssetReferred TableType;
|
|
||||||
static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() {
|
|
||||||
return "Flat.Bigfoot.BenchmarkAssetReferredT";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BenchmarkAssetReferred FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
|
||||||
typedef BenchmarkAssetReferredT NativeTableType;
|
|
||||||
typedef BenchmarkAssetReferredBuilder Builder;
|
|
||||||
struct Traits;
|
|
||||||
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
|
|
||||||
return BenchmarkAssetReferredTypeTable();
|
|
||||||
}
|
|
||||||
static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() {
|
|
||||||
return "Flat.Bigfoot.BenchmarkAssetReferred";
|
|
||||||
}
|
|
||||||
template <bool B = false>
|
|
||||||
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
|
|
||||||
return VerifyTableStart(verifier) &&
|
|
||||||
verifier.EndTable();
|
|
||||||
}
|
|
||||||
BenchmarkAssetReferredT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
|
||||||
void UnPackTo(BenchmarkAssetReferredT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
|
||||||
static ::flatbuffers::Offset<BenchmarkAssetReferred> Pack(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetReferredT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BenchmarkAssetReferredBuilder {
|
|
||||||
typedef BenchmarkAssetReferred Table;
|
|
||||||
::flatbuffers::FlatBufferBuilder &fbb_;
|
|
||||||
::flatbuffers::uoffset_t start_;
|
|
||||||
explicit BenchmarkAssetReferredBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
|
|
||||||
: fbb_(_fbb) {
|
|
||||||
start_ = fbb_.StartTable();
|
|
||||||
}
|
|
||||||
::flatbuffers::Offset<BenchmarkAssetReferred> Finish() {
|
|
||||||
const auto end = fbb_.EndTable(start_);
|
|
||||||
auto o = ::flatbuffers::Offset<BenchmarkAssetReferred>(end);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline ::flatbuffers::Offset<BenchmarkAssetReferred> CreateBenchmarkAssetReferred(
|
|
||||||
::flatbuffers::FlatBufferBuilder &_fbb) {
|
|
||||||
BenchmarkAssetReferredBuilder builder_(_fbb);
|
|
||||||
return builder_.Finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BenchmarkAssetReferred::Traits {
|
|
||||||
using type = BenchmarkAssetReferred;
|
|
||||||
static auto constexpr Create = CreateBenchmarkAssetReferred;
|
|
||||||
};
|
|
||||||
|
|
||||||
::flatbuffers::Offset<BenchmarkAssetReferred> CreateBenchmarkAssetReferred(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetReferredT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
|
|
||||||
|
|
||||||
inline BenchmarkAssetReferredT *BenchmarkAssetReferred::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const {
|
|
||||||
auto _o = std::make_unique<BenchmarkAssetReferredT>();
|
|
||||||
UnPackTo(_o.get(), _resolver);
|
|
||||||
return _o.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void BenchmarkAssetReferred::UnPackTo(BenchmarkAssetReferredT *_o, const ::flatbuffers::resolver_function_t *_resolver) const {
|
|
||||||
(void)_o;
|
|
||||||
(void)_resolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ::flatbuffers::Offset<BenchmarkAssetReferred> CreateBenchmarkAssetReferred(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetReferredT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
|
|
||||||
return BenchmarkAssetReferred::Pack(_fbb, _o, _rehasher);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ::flatbuffers::Offset<BenchmarkAssetReferred> BenchmarkAssetReferred::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetReferredT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) {
|
|
||||||
(void)_rehasher;
|
|
||||||
(void)_o;
|
|
||||||
struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const BenchmarkAssetReferredT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
|
|
||||||
return Flat::Bigfoot::CreateBenchmarkAssetReferred(
|
|
||||||
_fbb);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const ::flatbuffers::TypeTable *BenchmarkAssetReferredTypeTable() {
|
|
||||||
static const ::flatbuffers::TypeTable tt = {
|
|
||||||
::flatbuffers::ST_TABLE, 0, nullptr, nullptr, nullptr, nullptr, nullptr
|
|
||||||
};
|
|
||||||
return &tt;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const Flat::Bigfoot::BenchmarkAssetReferred *GetBenchmarkAssetReferred(const void *buf) {
|
|
||||||
return ::flatbuffers::GetRoot<Flat::Bigfoot::BenchmarkAssetReferred>(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const Flat::Bigfoot::BenchmarkAssetReferred *GetSizePrefixedBenchmarkAssetReferred(const void *buf) {
|
|
||||||
return ::flatbuffers::GetSizePrefixedRoot<Flat::Bigfoot::BenchmarkAssetReferred>(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool B = false>
|
|
||||||
inline bool VerifyBenchmarkAssetReferredBuffer(
|
|
||||||
::flatbuffers::VerifierTemplate<B> &verifier) {
|
|
||||||
return verifier.template VerifyBuffer<Flat::Bigfoot::BenchmarkAssetReferred>(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool B = false>
|
|
||||||
inline bool VerifySizePrefixedBenchmarkAssetReferredBuffer(
|
|
||||||
::flatbuffers::VerifierTemplate<B> &verifier) {
|
|
||||||
return verifier.template VerifySizePrefixedBuffer<Flat::Bigfoot::BenchmarkAssetReferred>(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char *BenchmarkAssetReferredExtension() {
|
|
||||||
return "bfbs";
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FinishBenchmarkAssetReferredBuffer(
|
|
||||||
::flatbuffers::FlatBufferBuilder &fbb,
|
|
||||||
::flatbuffers::Offset<Flat::Bigfoot::BenchmarkAssetReferred> root) {
|
|
||||||
fbb.Finish(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void FinishSizePrefixedBenchmarkAssetReferredBuffer(
|
|
||||||
::flatbuffers::FlatBufferBuilder &fbb,
|
|
||||||
::flatbuffers::Offset<Flat::Bigfoot::BenchmarkAssetReferred> root) {
|
|
||||||
fbb.FinishSizePrefixed(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline eastl::unique_ptr<Flat::Bigfoot::BenchmarkAssetReferredT> UnPackBenchmarkAssetReferred(
|
|
||||||
const void *buf,
|
|
||||||
const ::flatbuffers::resolver_function_t *res = nullptr) {
|
|
||||||
return eastl::unique_ptr<Flat::Bigfoot::BenchmarkAssetReferredT>(GetBenchmarkAssetReferred(buf)->UnPack(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline eastl::unique_ptr<Flat::Bigfoot::BenchmarkAssetReferredT> UnPackSizePrefixedBenchmarkAssetReferred(
|
|
||||||
const void *buf,
|
|
||||||
const ::flatbuffers::resolver_function_t *res = nullptr) {
|
|
||||||
return eastl::unique_ptr<Flat::Bigfoot::BenchmarkAssetReferredT>(GetSizePrefixedBenchmarkAssetReferred(buf)->UnPack(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Bigfoot
|
|
||||||
} // namespace Flat
|
|
||||||
|
|
||||||
#endif // FLATBUFFERS_GENERATED_BENCHMARKASSETREFERRED_FLAT_BIGFOOT_H_
|
|
||||||
+5
-51
@@ -20,10 +20,6 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
|||||||
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
|
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
|
||||||
"Non-compatible Bigfoot flatbuffers fork version included");
|
"Non-compatible Bigfoot flatbuffers fork version included");
|
||||||
|
|
||||||
#include "System/UUID/UUID.hpp"
|
|
||||||
#include "Engine/Asset/Reference.hpp"
|
|
||||||
#include "Engine/Asset/Reference_generated.hpp"
|
|
||||||
|
|
||||||
#include "EASTL/unique_ptr.h"
|
#include "EASTL/unique_ptr.h"
|
||||||
#include "EASTL/string.h"
|
#include "EASTL/string.h"
|
||||||
#include "EASTL/vector.h"
|
#include "EASTL/vector.h"
|
||||||
@@ -35,21 +31,6 @@ struct BenchmarkAsset;
|
|||||||
struct BenchmarkAssetBuilder;
|
struct BenchmarkAssetBuilder;
|
||||||
struct BenchmarkAssetT;
|
struct BenchmarkAssetT;
|
||||||
|
|
||||||
} // namespace Bigfoot
|
|
||||||
} // namespace Flat
|
|
||||||
|
|
||||||
namespace Bigfoot {
|
|
||||||
class BenchmarkAssetReferred;
|
|
||||||
} // namespace Bigfoot
|
|
||||||
|
|
||||||
namespace flatbuffers {
|
|
||||||
Flat::Bigfoot::HardReference PackHardReferenceBenchmarkAssetReferred(const ::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred>& p_asset);
|
|
||||||
::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred> UnPackHardReferenceBenchmarkAssetReferred(const Flat::Bigfoot::HardReference& p_asset);
|
|
||||||
} // namespace flatbuffers
|
|
||||||
|
|
||||||
namespace Flat {
|
|
||||||
namespace Bigfoot {
|
|
||||||
|
|
||||||
inline const ::flatbuffers::TypeTable *BenchmarkAssetTypeTable();
|
inline const ::flatbuffers::TypeTable *BenchmarkAssetTypeTable();
|
||||||
|
|
||||||
struct BenchmarkAssetT : public ::flatbuffers::NativeTable {
|
struct BenchmarkAssetT : public ::flatbuffers::NativeTable {
|
||||||
@@ -58,7 +39,6 @@ struct BenchmarkAssetT : public ::flatbuffers::NativeTable {
|
|||||||
return "Flat.Bigfoot.BenchmarkAssetT";
|
return "Flat.Bigfoot.BenchmarkAssetT";
|
||||||
}
|
}
|
||||||
eastl::vector<uint8_t> payload{};
|
eastl::vector<uint8_t> payload{};
|
||||||
eastl::vector<::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred>> refs{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BenchmarkAsset FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
struct BenchmarkAsset FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||||
@@ -72,22 +52,16 @@ struct BenchmarkAsset FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
|||||||
return "Flat.Bigfoot.BenchmarkAsset";
|
return "Flat.Bigfoot.BenchmarkAsset";
|
||||||
}
|
}
|
||||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||||
VT_PAYLOAD = 4,
|
VT_PAYLOAD = 4
|
||||||
VT_REFS = 6
|
|
||||||
};
|
};
|
||||||
const ::flatbuffers::Vector<uint8_t> *payload() const {
|
const ::flatbuffers::Vector<uint8_t> *payload() const {
|
||||||
return GetPointer<const ::flatbuffers::Vector<uint8_t> *>(VT_PAYLOAD);
|
return GetPointer<const ::flatbuffers::Vector<uint8_t> *>(VT_PAYLOAD);
|
||||||
}
|
}
|
||||||
const ::flatbuffers::Vector<const Flat::Bigfoot::HardReference *> *refs() const {
|
|
||||||
return GetPointer<const ::flatbuffers::Vector<const Flat::Bigfoot::HardReference *> *>(VT_REFS);
|
|
||||||
}
|
|
||||||
template <bool B = false>
|
template <bool B = false>
|
||||||
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
|
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
|
||||||
return VerifyTableStart(verifier) &&
|
return VerifyTableStart(verifier) &&
|
||||||
VerifyOffset(verifier, VT_PAYLOAD) &&
|
VerifyOffset(verifier, VT_PAYLOAD) &&
|
||||||
verifier.VerifyVector(payload()) &&
|
verifier.VerifyVector(payload()) &&
|
||||||
VerifyOffset(verifier, VT_REFS) &&
|
|
||||||
verifier.VerifyVector(refs()) &&
|
|
||||||
verifier.EndTable();
|
verifier.EndTable();
|
||||||
}
|
}
|
||||||
BenchmarkAssetT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
BenchmarkAssetT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
||||||
@@ -102,9 +76,6 @@ struct BenchmarkAssetBuilder {
|
|||||||
void add_payload(::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload) {
|
void add_payload(::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload) {
|
||||||
fbb_.AddOffset(BenchmarkAsset::VT_PAYLOAD, payload);
|
fbb_.AddOffset(BenchmarkAsset::VT_PAYLOAD, payload);
|
||||||
}
|
}
|
||||||
void add_refs(::flatbuffers::Offset<::flatbuffers::Vector<const Flat::Bigfoot::HardReference *>> refs) {
|
|
||||||
fbb_.AddOffset(BenchmarkAsset::VT_REFS, refs);
|
|
||||||
}
|
|
||||||
explicit BenchmarkAssetBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
|
explicit BenchmarkAssetBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
|
||||||
: fbb_(_fbb) {
|
: fbb_(_fbb) {
|
||||||
start_ = fbb_.StartTable();
|
start_ = fbb_.StartTable();
|
||||||
@@ -118,10 +89,8 @@ struct BenchmarkAssetBuilder {
|
|||||||
|
|
||||||
inline ::flatbuffers::Offset<BenchmarkAsset> CreateBenchmarkAsset(
|
inline ::flatbuffers::Offset<BenchmarkAsset> CreateBenchmarkAsset(
|
||||||
::flatbuffers::FlatBufferBuilder &_fbb,
|
::flatbuffers::FlatBufferBuilder &_fbb,
|
||||||
::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload = 0,
|
::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload = 0) {
|
||||||
::flatbuffers::Offset<::flatbuffers::Vector<const Flat::Bigfoot::HardReference *>> refs = 0) {
|
|
||||||
BenchmarkAssetBuilder builder_(_fbb);
|
BenchmarkAssetBuilder builder_(_fbb);
|
||||||
builder_.add_refs(refs);
|
|
||||||
builder_.add_payload(payload);
|
builder_.add_payload(payload);
|
||||||
return builder_.Finish();
|
return builder_.Finish();
|
||||||
}
|
}
|
||||||
@@ -143,7 +112,6 @@ inline void BenchmarkAsset::UnPackTo(BenchmarkAssetT *_o, const ::flatbuffers::r
|
|||||||
(void)_o;
|
(void)_o;
|
||||||
(void)_resolver;
|
(void)_resolver;
|
||||||
{ auto _e = payload(); if (_e) { _o->payload.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->payload.begin()); } }
|
{ auto _e = payload(); if (_e) { _o->payload.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->payload.begin()); } }
|
||||||
{ auto _e = refs(); if (_e) { _o->refs.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->refs[_i] = ::flatbuffers::UnPackHardReferenceBenchmarkAssetReferred(*_e->Get(_i)); } } else { _o->refs.resize(0); } }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ::flatbuffers::Offset<BenchmarkAsset> CreateBenchmarkAsset(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
|
inline ::flatbuffers::Offset<BenchmarkAsset> CreateBenchmarkAsset(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
|
||||||
@@ -155,23 +123,17 @@ inline ::flatbuffers::Offset<BenchmarkAsset> BenchmarkAsset::Pack(::flatbuffers:
|
|||||||
(void)_o;
|
(void)_o;
|
||||||
struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const BenchmarkAssetT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
|
struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const BenchmarkAssetT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
|
||||||
auto _payload = _fbb.CreateVector(_o->payload.data(), _o->payload.size());
|
auto _payload = _fbb.CreateVector(_o->payload.data(), _o->payload.size());
|
||||||
auto _refs = _fbb.CreateVectorOfNativeStructs<Flat::Bigfoot::HardReference, ::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred>>(_o->refs.data(), _o->refs.size(), ::flatbuffers::PackHardReferenceBenchmarkAssetReferred);
|
|
||||||
return Flat::Bigfoot::CreateBenchmarkAsset(
|
return Flat::Bigfoot::CreateBenchmarkAsset(
|
||||||
_fbb,
|
_fbb,
|
||||||
_payload,
|
_payload);
|
||||||
_refs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const ::flatbuffers::TypeTable *BenchmarkAssetTypeTable() {
|
inline const ::flatbuffers::TypeTable *BenchmarkAssetTypeTable() {
|
||||||
static const ::flatbuffers::TypeCode type_codes[] = {
|
static const ::flatbuffers::TypeCode type_codes[] = {
|
||||||
{ ::flatbuffers::ET_UCHAR, 1, -1 },
|
{ ::flatbuffers::ET_UCHAR, 1, -1 }
|
||||||
{ ::flatbuffers::ET_SEQUENCE, 1, 0 }
|
|
||||||
};
|
|
||||||
static const ::flatbuffers::TypeFunction type_refs[] = {
|
|
||||||
Flat::Bigfoot::HardReferenceTypeTable
|
|
||||||
};
|
};
|
||||||
static const ::flatbuffers::TypeTable tt = {
|
static const ::flatbuffers::TypeTable tt = {
|
||||||
::flatbuffers::ST_TABLE, 2, type_codes, type_refs, nullptr, nullptr, nullptr
|
::flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, nullptr, nullptr
|
||||||
};
|
};
|
||||||
return &tt;
|
return &tt;
|
||||||
}
|
}
|
||||||
@@ -227,12 +189,4 @@ inline eastl::unique_ptr<Flat::Bigfoot::BenchmarkAssetT> UnPackSizePrefixedBench
|
|||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
} // namespace Flat
|
} // namespace Flat
|
||||||
|
|
||||||
namespace flatbuffers {
|
|
||||||
#ifndef FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEBENCHMARKASSETREFERRED
|
|
||||||
#define FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEBENCHMARKASSETREFERRED
|
|
||||||
inline Flat::Bigfoot::HardReference PackHardReferenceBenchmarkAssetReferred(const ::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred>& p_asset) { return {Pack(p_asset.GetUUID())}; }
|
|
||||||
inline ::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred> UnPackHardReferenceBenchmarkAssetReferred(const Flat::Bigfoot::HardReference& p_asset) { return {UnPack(p_asset.uuid())}; }
|
|
||||||
#endif // FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEBENCHMARKASSETREFERRED
|
|
||||||
} // namespace flatbuffers
|
|
||||||
|
|
||||||
#endif // FLATBUFFERS_GENERATED_BENCHMARKASSET_FLAT_BIGFOOT_H_
|
#endif // FLATBUFFERS_GENERATED_BENCHMARKASSET_FLAT_BIGFOOT_H_
|
||||||
|
|||||||
@@ -2,4 +2,3 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/AssetsForBenchmarking)
|
|||||||
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Graphics)
|
|
||||||
|
|||||||
@@ -20,30 +20,9 @@ namespace
|
|||||||
using Random = effolkronium::random_static;
|
using Random = effolkronium::random_static;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class AssetContainerFixture: public benchmark::Fixture
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
[[nodiscard]]
|
|
||||||
static eastl::vector<UUID> InsertRandomAssets(AssetContainer<BenchmarkAsset>& p_container,
|
|
||||||
const std::uint32_t p_count)
|
|
||||||
{
|
|
||||||
eastl::vector<UUID> uuids;
|
|
||||||
uuids.reserve(p_count);
|
|
||||||
for (std::uint32_t i = 0; i < p_count; ++i)
|
|
||||||
{
|
|
||||||
uuids.push_back(p_container.Insert()->GetAsset()->GetHeader().uuid);
|
|
||||||
}
|
|
||||||
Random::shuffle(uuids);
|
|
||||||
|
|
||||||
return uuids;
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetContainer<BenchmarkAsset> m_container;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(AssetContainerFixture, Insert)(benchmark::State& state)
|
void Insert(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto count = static_cast<std::uint32_t>(state.range(0));
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
@@ -62,29 +41,29 @@ BENCHMARK_DEFINE_F(AssetContainerFixture, Insert)(benchmark::State& state)
|
|||||||
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations() * count * sizeof(BenchmarkAsset)));
|
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations() * count * sizeof(BenchmarkAsset)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(AssetContainerFixture, Insert)->Name("AssetContainer/Insert")->Arg(512)->Arg(8192)->Arg(131'072);
|
BENCHMARK(Insert)->Name("AssetContainer/Insert")->Arg(512)->Arg(8192)->Arg(131'072);
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(AssetContainerFixture, Get)(benchmark::State& state)
|
void Get(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto count = static_cast<std::uint32_t>(state.range(0));
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
const eastl::vector<UUID> uuids = InsertRandomAssets(m_container, count);
|
AssetContainer<BenchmarkAsset> container;
|
||||||
|
eastl::vector<SlotMapKey<>> keys;
|
||||||
eastl::vector<ContainerHandle*> handles;
|
keys.reserve(count);
|
||||||
handles.reserve(count);
|
for (std::uint32_t i = 0; i < count; ++i)
|
||||||
for (const UUID& uuid: uuids)
|
|
||||||
{
|
{
|
||||||
handles.push_back(m_container.AcquireContainerHandle(uuid));
|
keys.push_back(container.Insert());
|
||||||
}
|
}
|
||||||
|
Random::shuffle(keys);
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
std::uint64_t sum = 0;
|
std::uint64_t sum = 0;
|
||||||
for (ContainerHandle* const handle: handles)
|
for (const SlotMapKey<> key: keys)
|
||||||
{
|
{
|
||||||
if (const auto* const asset = static_cast<const BenchmarkAsset*>(handle->GetAsset()))
|
if (const BenchmarkAsset* const asset = container.Get(key))
|
||||||
{
|
{
|
||||||
sum += asset->GetHeader().type_id;
|
sum += asset->GetHeader().type_id;
|
||||||
}
|
}
|
||||||
@@ -95,22 +74,30 @@ BENCHMARK_DEFINE_F(AssetContainerFixture, Get)(benchmark::State& state)
|
|||||||
state.SetItemsProcessed(state.iterations() * count);
|
state.SetItemsProcessed(state.iterations() * count);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(AssetContainerFixture, Get)->Name("AssetContainer/Get")->Arg(512)->Arg(8192)->Arg(131'072);
|
BENCHMARK(Get)->Name("AssetContainer/Get")->Arg(512)->Arg(8192)->Arg(131'072);
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(AssetContainerFixture, Has)(benchmark::State& state)
|
void Has(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto count = static_cast<std::uint32_t>(state.range(0));
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
const eastl::vector<UUID> uuids = InsertRandomAssets(m_container, count);
|
AssetContainer<BenchmarkAsset> container;
|
||||||
|
eastl::vector<UUID> uuids;
|
||||||
|
uuids.reserve(count);
|
||||||
|
for (std::uint32_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
const SlotMapKey<> key = container.Insert();
|
||||||
|
uuids.push_back(container.Get(key)->GetHeader().uuid);
|
||||||
|
}
|
||||||
|
Random::shuffle(uuids);
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
for (const UUID& uuid: uuids)
|
for (const UUID& uuid: uuids)
|
||||||
{
|
{
|
||||||
result = result && m_container.Has(uuid);
|
result = result && container.Has(uuid);
|
||||||
}
|
}
|
||||||
benchmark::DoNotOptimize(result);
|
benchmark::DoNotOptimize(result);
|
||||||
}
|
}
|
||||||
@@ -118,22 +105,30 @@ BENCHMARK_DEFINE_F(AssetContainerFixture, Has)(benchmark::State& state)
|
|||||||
state.SetItemsProcessed(state.iterations() * count);
|
state.SetItemsProcessed(state.iterations() * count);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(AssetContainerFixture, Has)->Name("AssetContainer/Has")->Arg(512)->Arg(8192)->Arg(131'072);
|
BENCHMARK(Has)->Name("AssetContainer/Has")->Arg(512)->Arg(8192)->Arg(131'072);
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(AssetContainerFixture, AcquireContainerHandle)(benchmark::State& state)
|
void AcquireContainerHandle(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto count = static_cast<std::uint32_t>(state.range(0));
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
const eastl::vector<UUID> uuids = InsertRandomAssets(m_container, count);
|
AssetContainer<BenchmarkAsset> container;
|
||||||
|
eastl::vector<UUID> uuids;
|
||||||
|
uuids.reserve(count);
|
||||||
|
for (std::uint32_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
const SlotMapKey<> key = container.Insert();
|
||||||
|
uuids.push_back(container.Get(key)->GetHeader().uuid);
|
||||||
|
}
|
||||||
|
Random::shuffle(uuids);
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
std::uint64_t sum = 0;
|
std::uint64_t sum = 0;
|
||||||
for (const UUID& uuid: uuids)
|
for (const UUID& uuid: uuids)
|
||||||
{
|
{
|
||||||
sum += m_container.AcquireContainerHandle(uuid)->GetHardRefCount();
|
sum += container.AcquireContainerHandle(uuid)->GetHardRefCount();
|
||||||
}
|
}
|
||||||
benchmark::DoNotOptimize(sum);
|
benchmark::DoNotOptimize(sum);
|
||||||
}
|
}
|
||||||
@@ -141,29 +136,33 @@ BENCHMARK_DEFINE_F(AssetContainerFixture, AcquireContainerHandle)(benchmark::Sta
|
|||||||
state.SetItemsProcessed(state.iterations() * count);
|
state.SetItemsProcessed(state.iterations() * count);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(AssetContainerFixture, AcquireContainerHandle)
|
BENCHMARK(AcquireContainerHandle)->Name("AssetContainer/AcquireContainerHandle")->Arg(512)->Arg(8192)->Arg(131'072);
|
||||||
->Name("AssetContainer/AcquireContainerHandle")
|
|
||||||
->Arg(512)
|
|
||||||
->Arg(8192)
|
|
||||||
->Arg(131'072);
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(AssetContainerFixture, Remove)(benchmark::State& state)
|
void Remove(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto count = static_cast<std::uint32_t>(state.range(0));
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
|
AssetContainer<BenchmarkAsset> container;
|
||||||
eastl::vector<UUID> uuids;
|
eastl::vector<UUID> uuids;
|
||||||
|
uuids.reserve(count);
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
state.PauseTiming();
|
state.PauseTiming();
|
||||||
uuids = InsertRandomAssets(m_container, count);
|
uuids.clear();
|
||||||
|
for (std::uint32_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
const SlotMapKey<> key = container.Insert();
|
||||||
|
uuids.push_back(container.Get(key)->GetHeader().uuid);
|
||||||
|
}
|
||||||
|
Random::shuffle(uuids);
|
||||||
state.ResumeTiming();
|
state.ResumeTiming();
|
||||||
|
|
||||||
for (const UUID& uuid: uuids)
|
for (const UUID& uuid: uuids)
|
||||||
{
|
{
|
||||||
m_container.Remove(uuid);
|
container.Remove(uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,5 +170,5 @@ BENCHMARK_DEFINE_F(AssetContainerFixture, Remove)(benchmark::State& state)
|
|||||||
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations() * count * sizeof(BenchmarkAsset)));
|
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations() * count * sizeof(BenchmarkAsset)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(AssetContainerFixture, Remove)->Name("AssetContainer/Remove")->Arg(512)->Arg(8192)->Arg(131'072);
|
BENCHMARK(Remove)->Name("AssetContainer/Remove")->Arg(512)->Arg(8192)->Arg(131'072);
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
||||||
|
|
||||||
#include <EASTL/optional.h>
|
|
||||||
#include <EASTL/vector.h>
|
#include <EASTL/vector.h>
|
||||||
#include <benchmark/benchmark.h>
|
#include <benchmark/benchmark.h>
|
||||||
|
|
||||||
@@ -20,119 +19,96 @@
|
|||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
template<template<class> class REFERENCE>
|
template<template<class> class REFERENCE>
|
||||||
class ReferenceFixture: public benchmark::Fixture
|
void Construct(benchmark::State& state)
|
||||||
{
|
{
|
||||||
protected:
|
AssetLibrary library;
|
||||||
using ReferenceType = REFERENCE<BenchmarkAsset>;
|
AssetContainer<BenchmarkAsset> container;
|
||||||
|
std::ignore = library.Insert(&container);
|
||||||
|
ScopedActiveAssetLibrary scopedLibrary {&library};
|
||||||
|
|
||||||
void SetUp(benchmark::State&) override
|
const SlotMapKey<> key = container.Insert();
|
||||||
{
|
const UUID uuid = container.Get(key)->GetHeader().uuid;
|
||||||
SetActiveAssetLibrary(&m_library);
|
|
||||||
std::ignore = m_library.Insert(&m_container);
|
|
||||||
|
|
||||||
m_uuid = CreateAsset<BenchmarkAsset>()->GetHeader().uuid;
|
|
||||||
m_reference.emplace(m_uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown(benchmark::State&) override
|
|
||||||
{
|
|
||||||
SetActiveAssetLibrary(g_assetLibrary);
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetLibrary m_library;
|
|
||||||
AssetContainer<BenchmarkAsset> m_container;
|
|
||||||
UUID m_uuid;
|
|
||||||
eastl::optional<ReferenceType> m_reference;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, HardReferenceConstruct, HardReference)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
ReferenceType reference {m_uuid};
|
REFERENCE<BenchmarkAsset> reference {uuid};
|
||||||
benchmark::DoNotOptimize(reference);
|
benchmark::DoNotOptimize(reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(ReferenceFixture, HardReferenceConstruct)->Name("Reference/HardReference/Construct");
|
BENCHMARK_TEMPLATE(Construct, HardReference)->Name("Reference/HardReference/Construct");
|
||||||
|
BENCHMARK_TEMPLATE(Construct, SoftReference)->Name("Reference/SoftReference/Construct");
|
||||||
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, SoftReferenceConstruct, SoftReference)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
ReferenceType reference {m_uuid};
|
|
||||||
benchmark::DoNotOptimize(reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(ReferenceFixture, SoftReferenceConstruct)->Name("Reference/SoftReference/Construct");
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, HardReferenceGet, HardReference)(benchmark::State& state)
|
template<template<class> class REFERENCE>
|
||||||
|
void Get(benchmark::State& state)
|
||||||
{
|
{
|
||||||
|
AssetLibrary library;
|
||||||
|
AssetContainer<BenchmarkAsset> container;
|
||||||
|
std::ignore = library.Insert(&container);
|
||||||
|
ScopedActiveAssetLibrary scopedLibrary {&library};
|
||||||
|
|
||||||
|
const SlotMapKey<> key = container.Insert();
|
||||||
|
const UUID uuid = container.Get(key)->GetHeader().uuid;
|
||||||
|
|
||||||
|
REFERENCE<BenchmarkAsset> reference {uuid};
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
benchmark::DoNotOptimize(m_reference->Get());
|
benchmark::DoNotOptimize(reference.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(ReferenceFixture, HardReferenceGet)->Name("Reference/HardReference/Get");
|
BENCHMARK_TEMPLATE(Get, HardReference)->Name("Reference/HardReference/Get");
|
||||||
|
BENCHMARK_TEMPLATE(Get, SoftReference)->Name("Reference/SoftReference/Get");
|
||||||
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, SoftReferenceGet, SoftReference)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
benchmark::DoNotOptimize(m_reference->Get());
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(ReferenceFixture, SoftReferenceGet)->Name("Reference/SoftReference/Get");
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, HardReferenceCopy, HardReference)(benchmark::State& state)
|
template<template<class> class REFERENCE>
|
||||||
|
void Copy(benchmark::State& state)
|
||||||
{
|
{
|
||||||
|
AssetLibrary library;
|
||||||
|
AssetContainer<BenchmarkAsset> container;
|
||||||
|
std::ignore = library.Insert(&container);
|
||||||
|
ScopedActiveAssetLibrary scopedLibrary {&library};
|
||||||
|
|
||||||
|
const SlotMapKey<> key = container.Insert();
|
||||||
|
const UUID uuid = container.Get(key)->GetHeader().uuid;
|
||||||
|
|
||||||
|
REFERENCE<BenchmarkAsset> reference {uuid};
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
ReferenceType copy {*m_reference};
|
REFERENCE<BenchmarkAsset> copy {reference};
|
||||||
benchmark::DoNotOptimize(copy);
|
benchmark::DoNotOptimize(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(ReferenceFixture, HardReferenceCopy)->Name("Reference/HardReference/Copy");
|
BENCHMARK_TEMPLATE(Copy, HardReference)->Name("Reference/HardReference/Copy");
|
||||||
|
BENCHMARK_TEMPLATE(Copy, SoftReference)->Name("Reference/SoftReference/Copy");
|
||||||
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, SoftReferenceCopy, SoftReference)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
ReferenceType copy {*m_reference};
|
|
||||||
benchmark::DoNotOptimize(copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(ReferenceFixture, SoftReferenceCopy)->Name("Reference/SoftReference/Copy");
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, HardReferenceMove, HardReference)(benchmark::State& state)
|
template<template<class> class REFERENCE>
|
||||||
|
void Move(benchmark::State& state)
|
||||||
{
|
{
|
||||||
|
AssetLibrary library;
|
||||||
|
AssetContainer<BenchmarkAsset> container;
|
||||||
|
std::ignore = library.Insert(&container);
|
||||||
|
ScopedActiveAssetLibrary scopedLibrary {&library};
|
||||||
|
|
||||||
|
const SlotMapKey<> key = container.Insert();
|
||||||
|
const UUID uuid = container.Get(key)->GetHeader().uuid;
|
||||||
|
|
||||||
constexpr std::size_t BATCH_SIZE = 128;
|
constexpr std::size_t BATCH_SIZE = 128;
|
||||||
eastl::vector<ReferenceType> batch;
|
eastl::vector<REFERENCE<BenchmarkAsset>> batch;
|
||||||
batch.reserve(BATCH_SIZE);
|
batch.reserve(BATCH_SIZE);
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
@@ -141,13 +117,13 @@ BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, HardReferenceMove, HardReference)(
|
|||||||
batch.clear();
|
batch.clear();
|
||||||
for (std::size_t i = 0; i < BATCH_SIZE; ++i)
|
for (std::size_t i = 0; i < BATCH_SIZE; ++i)
|
||||||
{
|
{
|
||||||
batch.emplace_back(m_uuid);
|
batch.emplace_back(uuid);
|
||||||
}
|
}
|
||||||
state.ResumeTiming();
|
state.ResumeTiming();
|
||||||
|
|
||||||
for (ReferenceType& reference: batch)
|
for (REFERENCE<BenchmarkAsset>& reference: batch)
|
||||||
{
|
{
|
||||||
ReferenceType moved {std::move(reference)};
|
REFERENCE<BenchmarkAsset> moved {std::move(reference)};
|
||||||
benchmark::DoNotOptimize(moved);
|
benchmark::DoNotOptimize(moved);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,33 +131,6 @@ BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, HardReferenceMove, HardReference)(
|
|||||||
state.SetItemsProcessed(state.iterations() * BATCH_SIZE);
|
state.SetItemsProcessed(state.iterations() * BATCH_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(ReferenceFixture, HardReferenceMove)->Name("Reference/HardReference/Move");
|
BENCHMARK_TEMPLATE(Move, HardReference)->Name("Reference/HardReference/Move");
|
||||||
|
BENCHMARK_TEMPLATE(Move, SoftReference)->Name("Reference/SoftReference/Move");
|
||||||
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, SoftReferenceMove, SoftReference)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
constexpr std::size_t BATCH_SIZE = 128;
|
|
||||||
eastl::vector<ReferenceType> batch;
|
|
||||||
batch.reserve(BATCH_SIZE);
|
|
||||||
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
state.PauseTiming();
|
|
||||||
batch.clear();
|
|
||||||
for (std::size_t i = 0; i < BATCH_SIZE; ++i)
|
|
||||||
{
|
|
||||||
batch.emplace_back(m_uuid);
|
|
||||||
}
|
|
||||||
state.ResumeTiming();
|
|
||||||
|
|
||||||
for (ReferenceType& reference: batch)
|
|
||||||
{
|
|
||||||
ReferenceType moved {std::move(reference)};
|
|
||||||
benchmark::DoNotOptimize(moved);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations() * BATCH_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(ReferenceFixture, SoftReferenceMove)->Name("Reference/SoftReference/Move");
|
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -9,13 +9,10 @@
|
|||||||
#include <System/File/File.hpp>
|
#include <System/File/File.hpp>
|
||||||
#include <System/UUID/UUID.hpp>
|
#include <System/UUID/UUID.hpp>
|
||||||
|
|
||||||
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
|
||||||
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred.hpp>
|
|
||||||
|
|
||||||
#include <EngineBenchmarks/BigFileInfo_generated.hpp>
|
#include <EngineBenchmarks/BigFileInfo_generated.hpp>
|
||||||
|
|
||||||
#include <EASTL/optional.h>
|
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
||||||
#include <EASTL/span.h>
|
|
||||||
#include <EASTL/vector.h>
|
#include <EASTL/vector.h>
|
||||||
#include <benchmark/benchmark.h>
|
#include <benchmark/benchmark.h>
|
||||||
#include <effolkronium/random.hpp>
|
#include <effolkronium/random.hpp>
|
||||||
@@ -26,30 +23,47 @@
|
|||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
#ifdef BIGFOOT_TOOLMODE
|
#ifdef BIGFOOT_TOOLMODE
|
||||||
|
namespace
|
||||||
|
{
|
||||||
using Random = effolkronium::random_static;
|
using Random = effolkronium::random_static;
|
||||||
|
|
||||||
class BigFileFixture: public benchmark::Fixture
|
constexpr std::uint32_t ASSET_COUNT = 20'000;
|
||||||
|
constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
|
||||||
|
|
||||||
|
class Fixture: public benchmark::Fixture
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
void SetUp(benchmark::State&) override
|
||||||
|
{
|
||||||
|
BigFile::Request {m_bigFile, "DELETE FROM Asset;"}.Execute();
|
||||||
|
BigFile::Request {m_bigFile, "DELETE FROM AssetMetadata;"}.Execute();
|
||||||
|
|
||||||
|
m_uuids.clear();
|
||||||
|
m_uuids.reserve(ASSET_COUNT);
|
||||||
|
|
||||||
|
eastl::vector<AssetMetadata> metadatas;
|
||||||
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||||
|
metadatas.reserve(ASSET_COUNT);
|
||||||
|
flatbuffers.reserve(ASSET_COUNT);
|
||||||
|
|
||||||
|
for (std::uint32_t i = 0; i < ASSET_COUNT; ++i)
|
||||||
|
{
|
||||||
|
BenchmarkAsset asset;
|
||||||
|
asset.SetName(asset.GetHeader().uuid.ToString().c_str());
|
||||||
|
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||||
|
|
||||||
|
metadatas.push_back(AssetMetadata {.m_uuid = asset.GetHeader().uuid,
|
||||||
|
.m_name = asset.GetHeader().name,
|
||||||
|
.m_typeID = asset.GetHeader().type_id,
|
||||||
|
.m_typeName = asset.GetHeader().type_name});
|
||||||
|
flatbuffers.push_back(asset.Pack());
|
||||||
|
m_uuids.push_back(asset.GetHeader().uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bigFile.SaveAssetFlatbuffers(metadatas, flatbuffers);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static constexpr std::uint32_t ASSET_COUNT = 20'000;
|
|
||||||
static constexpr std::uint32_t REFS_PER_ASSET = 4;
|
|
||||||
static constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
|
|
||||||
|
|
||||||
void SetUp([[maybe_unused]] benchmark::State& p_state) override
|
|
||||||
{
|
|
||||||
// The DB is populated exactly once for the entire benchmark process.
|
|
||||||
// SetUp is called before every calibration round (Google Benchmark doubles
|
|
||||||
// iteration counts until it reaches a stable measurement), so rebuilding
|
|
||||||
// the DB each time would dominate the total benchmark time.
|
|
||||||
m_uuids = BuildData();
|
|
||||||
m_bigFile.emplace(File {BIGFILE_ENGINEBENCHMARKS_LOCATION});
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown([[maybe_unused]] benchmark::State& p_state) override
|
|
||||||
{
|
|
||||||
m_bigFile.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
eastl::vector<UUID> RandomBatch(const std::size_t p_batchSize) const
|
eastl::vector<UUID> RandomBatch(const std::size_t p_batchSize) const
|
||||||
{
|
{
|
||||||
@@ -77,75 +91,38 @@ class BigFileFixture: public benchmark::Fixture
|
|||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
eastl::optional<BigFile> m_bigFile;
|
BigFile m_bigFile {File {BIGFILE_ENGINEBENCHMARKS_LOCATION}};
|
||||||
eastl::span<const UUID> m_uuids;
|
eastl::vector<UUID> m_uuids;
|
||||||
|
|
||||||
private:
|
|
||||||
static const eastl::vector<UUID>& BuildData()
|
|
||||||
{
|
|
||||||
static const eastl::vector<UUID> s_uuids = []()
|
|
||||||
{
|
|
||||||
eastl::vector<UUID> uuids;
|
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
|
||||||
eastl::vector<eastl::vector<UUID>> hardReferences;
|
|
||||||
uuids.reserve(ASSET_COUNT);
|
|
||||||
flatbuffers.reserve(ASSET_COUNT);
|
|
||||||
hardReferences.reserve(ASSET_COUNT);
|
|
||||||
|
|
||||||
for (std::uint32_t i = 0; i < ASSET_COUNT; ++i)
|
|
||||||
{
|
|
||||||
BenchmarkAsset asset;
|
|
||||||
asset.SetName(asset.GetHeader().uuid.ToString());
|
|
||||||
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
|
||||||
for (std::uint32_t j = 0; j < REFS_PER_ASSET; ++j)
|
|
||||||
{
|
|
||||||
BenchmarkAssetReferred assetReferred;
|
|
||||||
assetReferred.SetName(assetReferred.GetHeader().uuid.ToString());
|
|
||||||
|
|
||||||
asset.GetAsset().refs.emplace_back(assetReferred.GetHeader().uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
eastl::vector<std::byte> flatbuffer = asset.Pack();
|
|
||||||
hardReferences.push_back(asset.GetHardReferences(flatbuffer));
|
|
||||||
flatbuffers.push_back(std::move(flatbuffer));
|
|
||||||
uuids.push_back(asset.GetHeader().uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
BigFile bigFile {File {BIGFILE_ENGINEBENCHMARKS_LOCATION}};
|
|
||||||
bigFile.Clear();
|
|
||||||
bigFile.SaveAssetFlatbuffers(uuids, flatbuffers, hardReferences);
|
|
||||||
|
|
||||||
return uuids;
|
|
||||||
}();
|
|
||||||
|
|
||||||
return s_uuids;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetFlatbuffer)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(Fixture, GetAssetFlatbuffer)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
std::int64_t bytesProcessed = 0;
|
std::int64_t bytesProcessed = 0;
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
eastl::vector<std::byte> flatbuffer = m_bigFile->GetAssetFlatbuffer(
|
eastl::optional<eastl::vector<std::byte>> flatbuffer = m_bigFile.GetAssetFlatbuffer(
|
||||||
m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
||||||
benchmark::DoNotOptimize(flatbuffer);
|
benchmark::DoNotOptimize(flatbuffer);
|
||||||
|
|
||||||
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
if (flatbuffer.has_value())
|
||||||
|
{
|
||||||
|
bytesProcessed += static_cast<std::int64_t>(flatbuffer->size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetFlatbuffer)->Name("BigFile/GetAssetFlatbuffer")->UseRealTime();
|
BENCHMARK_REGISTER_F(Fixture, GetAssetFlatbuffer)->Name("BigFile/GetAssetFlatbuffer");
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetFlatbuffers)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(Fixture, GetAssetFlatbuffers)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
||||||
|
|
||||||
@@ -157,7 +134,7 @@ BENCHMARK_DEFINE_F(BigFileFixture, GetAssetFlatbuffers)(benchmark::State& state)
|
|||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers = m_bigFile->GetAssetFlatbuffers(batchPool[batchIndex]);
|
eastl::vector<eastl::vector<std::byte>> flatbuffers = m_bigFile.GetAssetFlatbuffers(batchPool[batchIndex]);
|
||||||
benchmark::DoNotOptimize(flatbuffers);
|
benchmark::DoNotOptimize(flatbuffers);
|
||||||
|
|
||||||
for (const eastl::vector<std::byte>& flatbuffer: flatbuffers)
|
for (const eastl::vector<std::byte>& flatbuffer: flatbuffers)
|
||||||
@@ -172,34 +149,31 @@ BENCHMARK_DEFINE_F(BigFileFixture, GetAssetFlatbuffers)(benchmark::State& state)
|
|||||||
state.SetBytesProcessed(bytesProcessed);
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetFlatbuffers)
|
BENCHMARK_REGISTER_F(Fixture, GetAssetFlatbuffers)
|
||||||
->Name("BigFile/GetAssetFlatbuffers")
|
->Name("BigFile/GetAssetFlatbuffers")
|
||||||
->Arg(1)
|
->Arg(1)
|
||||||
->Arg(8)
|
->Arg(8)
|
||||||
->Arg(64)
|
->Arg(64)
|
||||||
->Arg(512)
|
->Arg(512)
|
||||||
->Arg(4096)
|
->Arg(4096);
|
||||||
->UseRealTime();
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetHardReferences)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(Fixture, GetAssetMetadata)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
benchmark::DoNotOptimize(
|
benchmark::DoNotOptimize(m_bigFile.GetAssetMetadata(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]));
|
||||||
m_bigFile->GetAssetHardReferences(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations()) * REFS_PER_ASSET * UUID::UUID_BYTE_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetHardReferences)->Name("BigFile/GetAssetHardReferences")->UseRealTime();
|
BENCHMARK_REGISTER_F(Fixture, GetAssetMetadata)->Name("BigFile/GetAssetMetadata");
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetsHardReferences)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(Fixture, GetAssetMetadatas)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
||||||
|
|
||||||
@@ -209,27 +183,24 @@ BENCHMARK_DEFINE_F(BigFileFixture, GetAssetsHardReferences)(benchmark::State& st
|
|||||||
std::size_t batchIndex = 0;
|
std::size_t batchIndex = 0;
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
benchmark::DoNotOptimize(m_bigFile->GetAssetsHardReferences(batchPool[batchIndex]));
|
benchmark::DoNotOptimize(m_bigFile.GetAssetMetadatas(batchPool[batchIndex]));
|
||||||
batchIndex = (batchIndex + 1) % BATCH_POOL_SIZE;
|
batchIndex = (batchIndex + 1) % BATCH_POOL_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations() * batchSize);
|
state.SetItemsProcessed(state.iterations() * batchSize);
|
||||||
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations()) * batchSize * REFS_PER_ASSET *
|
|
||||||
UUID::UUID_BYTE_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetsHardReferences)
|
BENCHMARK_REGISTER_F(Fixture, GetAssetMetadatas)
|
||||||
->Name("BigFile/GetAssetsHardReferences")
|
->Name("BigFile/GetAssetMetadatas")
|
||||||
->Arg(1)
|
->Arg(1)
|
||||||
->Arg(8)
|
->Arg(8)
|
||||||
->Arg(64)
|
->Arg(64)
|
||||||
->Arg(512)
|
->Arg(512)
|
||||||
->Arg(4096)
|
->Arg(4096);
|
||||||
->UseRealTime();
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(BigFileFixture, SaveAssetFlatbuffer)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(Fixture, SaveAssetFlatbuffer)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
std::int64_t bytesProcessed = 0;
|
std::int64_t bytesProcessed = 0;
|
||||||
|
|
||||||
@@ -237,30 +208,29 @@ BENCHMARK_DEFINE_F(BigFileFixture, SaveAssetFlatbuffer)(benchmark::State& state)
|
|||||||
{
|
{
|
||||||
state.PauseTiming();
|
state.PauseTiming();
|
||||||
BenchmarkAsset asset;
|
BenchmarkAsset asset;
|
||||||
asset.SetName(asset.GetHeader().uuid.ToString());
|
asset.SetName(asset.GetHeader().uuid.ToString().c_str());
|
||||||
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||||
for (std::uint32_t j = 0; j < REFS_PER_ASSET; ++j)
|
|
||||||
{
|
|
||||||
asset.GetAsset().refs.emplace_back(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const AssetMetadata metadata {.m_uuid = asset.GetHeader().uuid,
|
||||||
|
.m_name = asset.GetHeader().name,
|
||||||
|
.m_typeID = asset.GetHeader().type_id,
|
||||||
|
.m_typeName = asset.GetHeader().type_name};
|
||||||
const eastl::vector<std::byte> flatbuffer = asset.Pack();
|
const eastl::vector<std::byte> flatbuffer = asset.Pack();
|
||||||
const eastl::vector<UUID> hardReferences = asset.GetHardReferences(flatbuffer);
|
|
||||||
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
||||||
state.ResumeTiming();
|
state.ResumeTiming();
|
||||||
|
|
||||||
m_bigFile->SaveAssetFlatbuffer(asset.GetHeader().uuid, flatbuffer, hardReferences);
|
m_bigFile.SaveAssetFlatbuffer(metadata, flatbuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(BigFileFixture, SaveAssetFlatbuffer)->Name("BigFile/SaveAssetFlatbuffer")->UseRealTime();
|
BENCHMARK_REGISTER_F(Fixture, SaveAssetFlatbuffer)->Name("BigFile/SaveAssetFlatbuffer");
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(BigFileFixture, SaveAssetFlatbuffers)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(Fixture, SaveAssetFlatbuffers)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
||||||
std::int64_t bytesProcessed = 0;
|
std::int64_t bytesProcessed = 0;
|
||||||
@@ -268,45 +238,39 @@ BENCHMARK_DEFINE_F(BigFileFixture, SaveAssetFlatbuffers)(benchmark::State& state
|
|||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
state.PauseTiming();
|
state.PauseTiming();
|
||||||
eastl::vector<UUID> uuids;
|
eastl::vector<AssetMetadata> metadatas;
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||||
eastl::vector<eastl::vector<UUID>> hardReferences;
|
metadatas.reserve(batchSize);
|
||||||
uuids.reserve(batchSize);
|
|
||||||
flatbuffers.reserve(batchSize);
|
flatbuffers.reserve(batchSize);
|
||||||
hardReferences.reserve(batchSize);
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < batchSize; ++i)
|
for (std::size_t i = 0; i < batchSize; ++i)
|
||||||
{
|
{
|
||||||
BenchmarkAsset asset;
|
BenchmarkAsset asset;
|
||||||
asset.SetName(asset.GetHeader().uuid.ToString());
|
asset.SetName(asset.GetHeader().uuid.ToString().c_str());
|
||||||
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||||
for (std::uint32_t j = 0; j < REFS_PER_ASSET; ++j)
|
|
||||||
{
|
|
||||||
asset.GetAsset().refs.emplace_back(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
eastl::vector<std::byte> flatbuffer = asset.Pack();
|
metadatas.push_back(AssetMetadata {.m_uuid = asset.GetHeader().uuid,
|
||||||
uuids.push_back(asset.GetHeader().uuid);
|
.m_name = asset.GetHeader().name,
|
||||||
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
.m_typeID = asset.GetHeader().type_id,
|
||||||
hardReferences.push_back(asset.GetHardReferences(flatbuffer));
|
.m_typeName = asset.GetHeader().type_name});
|
||||||
flatbuffers.push_back(std::move(flatbuffer));
|
flatbuffers.push_back(asset.Pack());
|
||||||
|
bytesProcessed += static_cast<std::int64_t>(flatbuffers.back().size());
|
||||||
}
|
}
|
||||||
state.ResumeTiming();
|
state.ResumeTiming();
|
||||||
|
|
||||||
m_bigFile->SaveAssetFlatbuffers(uuids, flatbuffers, hardReferences);
|
m_bigFile.SaveAssetFlatbuffers(metadatas, flatbuffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations() * batchSize);
|
state.SetItemsProcessed(state.iterations() * batchSize);
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(BigFileFixture, SaveAssetFlatbuffers)
|
BENCHMARK_REGISTER_F(Fixture, SaveAssetFlatbuffers)
|
||||||
->Name("BigFile/SaveAssetFlatbuffers")
|
->Name("BigFile/SaveAssetFlatbuffers")
|
||||||
->Arg(1)
|
->Arg(1)
|
||||||
->Arg(8)
|
->Arg(8)
|
||||||
->Arg(64)
|
->Arg(64)
|
||||||
->Arg(512)
|
->Arg(512)
|
||||||
->Arg(4096)
|
->Arg(4096);
|
||||||
->UseRealTime();
|
|
||||||
#endif
|
#endif
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -2,13 +2,11 @@ get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|||||||
project(${PackageName}Benchmarks)
|
project(${PackageName}Benchmarks)
|
||||||
|
|
||||||
bigfoot_create_package_benchmarks(
|
bigfoot_create_package_benchmarks(
|
||||||
"Bigfoot/Benchmarks")
|
"")
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME}
|
target_link_libraries(${PROJECT_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
effolkronium_random
|
effolkronium_random
|
||||||
$<LINK_LIBRARY:WHOLE_ARCHIVE,AssetsForBenchmarking>)
|
$<LINK_LIBRARY:WHOLE_ARCHIVE,AssetsForBenchmarking>)
|
||||||
|
|
||||||
bigfoot_create_bigfile("Bigfoot/Benchmarks")
|
bigfoot_create_bigfile("Benchmarks/Bigfoot")
|
||||||
|
|
||||||
bigfoot_create_sasquatch_info()
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Bigfoot
|
|||||||
/*
|
/*
|
||||||
* BigFile location
|
* BigFile location
|
||||||
*/
|
*/
|
||||||
constexpr eastl::string_view BIGFILE_ENGINEBENCHMARKS_LOCATION {"./EngineBenchmarks.db"};
|
constexpr eastl::string_view BIGFILE_ENGINEBENCHMARKS_LOCATION {"./EngineBenchmarks-bigfile.db"};
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
// AUTO-GENERATED DO NOT TOUCH
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
* \file SasquatchInfo.generated.hpp
|
|
||||||
*
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_ENGINEBENCHMARKS_SASQUATCHINFO_GENERATED_HPP
|
|
||||||
#define BIGFOOT_ENGINEBENCHMARKS_SASQUATCHINFO_GENERATED_HPP
|
|
||||||
|
|
||||||
#include <EASTL/string_view.h>
|
|
||||||
|
|
||||||
#if defined BIGFOOT_GAME
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Sasquatch location
|
|
||||||
*/
|
|
||||||
constexpr eastl::string_view SASQUATCH_ENGINEBENCHMARKS_LOCATION {"./EngineBenchmarks.sasquatch"};
|
|
||||||
} // namespace Bigfoot
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@@ -1,245 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file Sasquatch.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Engine/Sasquatch/Sasquatch.hpp>
|
|
||||||
|
|
||||||
#include <System/File/File.hpp>
|
|
||||||
#include <System/UUID/UUID.hpp>
|
|
||||||
|
|
||||||
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
|
||||||
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred.hpp>
|
|
||||||
|
|
||||||
#include <EngineBenchmarks/SasquatchInfo_generated.hpp>
|
|
||||||
|
|
||||||
#include <EASTL/optional.h>
|
|
||||||
#include <EASTL/span.h>
|
|
||||||
#include <EASTL/vector.h>
|
|
||||||
#include <benchmark/benchmark.h>
|
|
||||||
#include <effolkronium/random.hpp>
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
#ifdef BIGFOOT_GAME
|
|
||||||
using Random = effolkronium::random_static;
|
|
||||||
|
|
||||||
class SasquatchFixture: public benchmark::Fixture
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
static constexpr std::uint32_t ASSET_COUNT = 20'000;
|
|
||||||
static constexpr std::uint32_t REFS_PER_ASSET = 4;
|
|
||||||
static constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
|
|
||||||
|
|
||||||
void SetUp([[maybe_unused]] benchmark::State& p_state) override
|
|
||||||
{
|
|
||||||
// The Sasquatch file is built exactly once for the entire benchmark process.
|
|
||||||
// SetUp is called before every calibration round (Google Benchmark doubles
|
|
||||||
// iteration counts until it reaches a stable measurement), so rebuilding
|
|
||||||
// the file each time would dominate the total benchmark time.
|
|
||||||
m_uuids = BuildData();
|
|
||||||
m_sasquatch.emplace(File {SASQUATCH_ENGINEBENCHMARKS_LOCATION});
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown([[maybe_unused]] benchmark::State& p_state) override
|
|
||||||
{
|
|
||||||
m_sasquatch.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
eastl::vector<UUID> RandomBatch(const std::size_t p_batchSize) const
|
|
||||||
{
|
|
||||||
eastl::vector<UUID> batch;
|
|
||||||
batch.reserve(p_batchSize);
|
|
||||||
for (std::size_t i = 0; i < p_batchSize; ++i)
|
|
||||||
{
|
|
||||||
batch.push_back(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return batch;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
eastl::vector<eastl::vector<UUID>> RandomBatchPool(const std::size_t p_batchSize,
|
|
||||||
const std::size_t p_poolSize) const
|
|
||||||
{
|
|
||||||
eastl::vector<eastl::vector<UUID>> pool;
|
|
||||||
pool.reserve(p_poolSize);
|
|
||||||
for (std::size_t i = 0; i < p_poolSize; ++i)
|
|
||||||
{
|
|
||||||
pool.push_back(RandomBatch(p_batchSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
eastl::optional<Sasquatch> m_sasquatch;
|
|
||||||
eastl::span<const UUID> m_uuids;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const eastl::vector<UUID>& BuildData()
|
|
||||||
{
|
|
||||||
static const eastl::vector<UUID> s_uuids = []()
|
|
||||||
{
|
|
||||||
File {SASQUATCH_ENGINEBENCHMARKS_LOCATION}.Delete();
|
|
||||||
|
|
||||||
eastl::vector<UUID> uuids;
|
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
|
||||||
eastl::vector<eastl::vector<UUID>> hardReferences;
|
|
||||||
uuids.reserve(ASSET_COUNT);
|
|
||||||
flatbuffers.reserve(ASSET_COUNT);
|
|
||||||
hardReferences.reserve(ASSET_COUNT);
|
|
||||||
|
|
||||||
for (std::uint32_t i = 0; i < ASSET_COUNT; ++i)
|
|
||||||
{
|
|
||||||
BenchmarkAsset asset;
|
|
||||||
asset.SetName(asset.GetHeader().uuid.ToString());
|
|
||||||
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
|
||||||
for (std::uint32_t j = 0; j < REFS_PER_ASSET; ++j)
|
|
||||||
{
|
|
||||||
BenchmarkAssetReferred assetReferred;
|
|
||||||
assetReferred.SetName(assetReferred.GetHeader().uuid.ToString());
|
|
||||||
|
|
||||||
asset.GetAsset().refs.emplace_back(assetReferred.GetHeader().uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
eastl::vector<std::byte> flatbuffer = asset.Pack();
|
|
||||||
hardReferences.push_back(asset.GetHardReferences(flatbuffer));
|
|
||||||
flatbuffers.push_back(std::move(flatbuffer));
|
|
||||||
uuids.push_back(asset.GetHeader().uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t totalFlatbufferBytes = 0;
|
|
||||||
std::size_t totalHardReferencesBytes = 0;
|
|
||||||
for (std::size_t i = 0; i < uuids.size(); ++i)
|
|
||||||
{
|
|
||||||
totalFlatbufferBytes += flatbuffers[i].size();
|
|
||||||
totalHardReferencesBytes += hardReferences[i].size() * UUID::UUID_BYTE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
SasquatchWriter writer {File {SASQUATCH_ENGINEBENCHMARKS_LOCATION},
|
|
||||||
uuids.size(),
|
|
||||||
totalFlatbufferBytes,
|
|
||||||
totalHardReferencesBytes};
|
|
||||||
for (std::size_t i = 0; i < uuids.size(); ++i)
|
|
||||||
{
|
|
||||||
writer.WriteAsset(uuids[i], flatbuffers[i], hardReferences[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return uuids;
|
|
||||||
}();
|
|
||||||
|
|
||||||
return s_uuids;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetHardReferences)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
benchmark::DoNotOptimize(
|
|
||||||
m_sasquatch->GetAssetHardReferences(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]));
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
|
||||||
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations()) * REFS_PER_ASSET * UUID::UUID_BYTE_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetHardReferences)->Name("Sasquatch/GetAssetHardReferences")->UseRealTime();
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetsHardReferences)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
|
||||||
|
|
||||||
constexpr std::size_t BATCH_POOL_SIZE = 64;
|
|
||||||
const eastl::vector<eastl::vector<UUID>> batchPool = RandomBatchPool(batchSize, BATCH_POOL_SIZE);
|
|
||||||
|
|
||||||
std::size_t batchIndex = 0;
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
benchmark::DoNotOptimize(m_sasquatch->GetAssetsHardReferences(batchPool[batchIndex]));
|
|
||||||
batchIndex = (batchIndex + 1) % BATCH_POOL_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations() * batchSize);
|
|
||||||
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations()) * batchSize * REFS_PER_ASSET *
|
|
||||||
UUID::UUID_BYTE_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetsHardReferences)
|
|
||||||
->Name("Sasquatch/GetAssetsHardReferences")
|
|
||||||
->Arg(1)
|
|
||||||
->Arg(8)
|
|
||||||
->Arg(64)
|
|
||||||
->Arg(512)
|
|
||||||
->Arg(4096)
|
|
||||||
->UseRealTime();
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetFlatbuffer)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
std::int64_t bytesProcessed = 0;
|
|
||||||
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
eastl::vector<std::byte> flatbuffer = m_sasquatch->GetAssetFlatbuffer(
|
|
||||||
m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
|
||||||
benchmark::DoNotOptimize(flatbuffer);
|
|
||||||
|
|
||||||
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetFlatbuffer)->Name("Sasquatch/GetAssetFlatbuffer")->UseRealTime();
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetFlatbuffers)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
|
||||||
|
|
||||||
constexpr std::size_t BATCH_POOL_SIZE = 64;
|
|
||||||
const eastl::vector<eastl::vector<UUID>> batchPool = RandomBatchPool(batchSize, BATCH_POOL_SIZE);
|
|
||||||
|
|
||||||
std::int64_t bytesProcessed = 0;
|
|
||||||
std::size_t batchIndex = 0;
|
|
||||||
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers = m_sasquatch->GetAssetFlatbuffers(batchPool[batchIndex]);
|
|
||||||
benchmark::DoNotOptimize(flatbuffers);
|
|
||||||
|
|
||||||
for (const eastl::vector<std::byte>& flatbuffer: flatbuffers)
|
|
||||||
{
|
|
||||||
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
batchIndex = (batchIndex + 1) % BATCH_POOL_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations() * batchSize);
|
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetFlatbuffers)
|
|
||||||
->Name("Sasquatch/GetAssetFlatbuffers")
|
|
||||||
->Arg(1)
|
|
||||||
->Arg(8)
|
|
||||||
->Arg(64)
|
|
||||||
->Arg(512)
|
|
||||||
->Arg(4096)
|
|
||||||
->UseRealTime();
|
|
||||||
#endif
|
|
||||||
} // namespace Bigfoot
|
|
||||||
@@ -1,391 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file SerializationManager.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Engine/SerializationManager/SerializationManager.hpp>
|
|
||||||
|
|
||||||
#include <Engine/Asset/AssetLibrary.hpp>
|
|
||||||
#include <Engine/DataAccessor/DataAccessor.hpp>
|
|
||||||
|
|
||||||
#if defined BIGFOOT_TOOLMODE
|
|
||||||
#include <Engine/BigFile/BigFile.hpp>
|
|
||||||
|
|
||||||
#include <EngineBenchmarks/BigFileInfo_generated.hpp>
|
|
||||||
#elif defined BIGFOOT_GAME
|
|
||||||
#include <Engine/Sasquatch/Sasquatch.hpp>
|
|
||||||
|
|
||||||
#include <EngineBenchmarks/SasquatchInfo_generated.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <System/File/File.hpp>
|
|
||||||
#include <System/UUID/UUID.hpp>
|
|
||||||
|
|
||||||
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
|
||||||
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred.hpp>
|
|
||||||
|
|
||||||
#include <EASTL/optional.h>
|
|
||||||
#include <EASTL/span.h>
|
|
||||||
#include <EASTL/vector.h>
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
#include <benchmark/benchmark.h>
|
|
||||||
#include <effolkronium/random.hpp>
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
using Random = effolkronium::random_static;
|
|
||||||
|
|
||||||
class SerializationManagerFixture: public benchmark::Fixture
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
static constexpr std::uint32_t ROOT_ASSET_COUNT = 20'000;
|
|
||||||
static constexpr std::uint32_t REFS_PER_ROOT = 4;
|
|
||||||
static constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
|
|
||||||
|
|
||||||
void SetUp([[maybe_unused]] benchmark::State& p_state) override
|
|
||||||
{
|
|
||||||
m_previousDataAccessor = g_dataAccessor;
|
|
||||||
m_previousAssetLibrary = g_activeAssetLibrary;
|
|
||||||
|
|
||||||
// The data store is populated exactly once for the entire benchmark process.
|
|
||||||
// SetUp is called before every calibration round (Google Benchmark doubles
|
|
||||||
// iteration counts until it reaches a stable measurement), so rebuilding
|
|
||||||
// the data store each time would dominate the total benchmark time.
|
|
||||||
static const SharedData& s_data = BuildData();
|
|
||||||
m_rootUuids = s_data.rootUuids;
|
|
||||||
m_leafUuids = s_data.leafUuids;
|
|
||||||
m_rootTotalBytes = &s_data.rootTotalBytes;
|
|
||||||
|
|
||||||
#if defined BIGFOOT_TOOLMODE
|
|
||||||
m_bigFile.emplace(File {BIGFILE_ENGINEBENCHMARKS_LOCATION});
|
|
||||||
SetDataAccessor(&*m_bigFile);
|
|
||||||
#elif defined BIGFOOT_GAME
|
|
||||||
m_sasquatch.emplace(File {SASQUATCH_ENGINEBENCHMARKS_LOCATION});
|
|
||||||
SetDataAccessor(&*m_sasquatch);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown([[maybe_unused]] benchmark::State& p_state) override
|
|
||||||
{
|
|
||||||
#if defined BIGFOOT_TOOLMODE
|
|
||||||
m_bigFile.reset();
|
|
||||||
#elif defined BIGFOOT_GAME
|
|
||||||
m_sasquatch.reset();
|
|
||||||
#endif
|
|
||||||
SetDataAccessor(m_previousDataAccessor);
|
|
||||||
SetActiveAssetLibrary(m_previousAssetLibrary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Registers a fresh, empty AssetLibrary as the active one, so that every root and leaf asset appears unloaded
|
|
||||||
*
|
|
||||||
* \param p_library The library to register
|
|
||||||
* \param p_leafContainer The container to register leaves into
|
|
||||||
* \param p_rootContainer The container to register roots into
|
|
||||||
*/
|
|
||||||
static void ResetActiveLibrary(AssetLibrary& p_library,
|
|
||||||
AssetContainer<BenchmarkAssetReferred>& p_leafContainer,
|
|
||||||
AssetContainer<BenchmarkAsset>& p_rootContainer)
|
|
||||||
{
|
|
||||||
std::ignore = p_library.Insert(&p_leafContainer);
|
|
||||||
std::ignore = p_library.Insert(&p_rootContainer);
|
|
||||||
SetActiveAssetLibrary(&p_library);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
eastl::vector<UUID> RandomRootBatch(const std::size_t p_batchSize) const
|
|
||||||
{
|
|
||||||
eastl::vector<UUID> batch;
|
|
||||||
batch.reserve(p_batchSize);
|
|
||||||
for (std::size_t i = 0; i < p_batchSize; ++i)
|
|
||||||
{
|
|
||||||
batch.push_back(m_rootUuids[Random::get<std::size_t>(0, m_rootUuids.size() - 1)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return batch;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Total flatbuffer bytes (root + its leaves) that loading p_roots will actually read, deduplicated the same way
|
|
||||||
* SerializationManager::LoadAssets deduplicates its own transitive discovery
|
|
||||||
*
|
|
||||||
* \param p_roots The root assets that would be loaded
|
|
||||||
* \return The total flatbuffer bytes across the unique roots
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
std::int64_t TotalBytes(const eastl::vector<UUID>& p_roots) const
|
|
||||||
{
|
|
||||||
ankerl::unordered_dense::set<UUID> unique;
|
|
||||||
unique.reserve(p_roots.size());
|
|
||||||
for (const UUID& uuid: p_roots)
|
|
||||||
{
|
|
||||||
unique.insert(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::int64_t bytes = 0;
|
|
||||||
for (const UUID& uuid: unique)
|
|
||||||
{
|
|
||||||
bytes += static_cast<std::int64_t>(m_rootTotalBytes->at(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataAccessor* m_previousDataAccessor = nullptr;
|
|
||||||
AssetLibrary* m_previousAssetLibrary = nullptr;
|
|
||||||
|
|
||||||
eastl::span<const UUID> m_rootUuids;
|
|
||||||
eastl::span<const UUID> m_leafUuids;
|
|
||||||
const ankerl::unordered_dense::map<UUID, std::size_t>* m_rootTotalBytes = nullptr;
|
|
||||||
|
|
||||||
#if defined BIGFOOT_TOOLMODE
|
|
||||||
eastl::optional<BigFile> m_bigFile;
|
|
||||||
#elif defined BIGFOOT_GAME
|
|
||||||
eastl::optional<Sasquatch> m_sasquatch;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct SharedData
|
|
||||||
{
|
|
||||||
eastl::vector<UUID> rootUuids;
|
|
||||||
eastl::vector<UUID> leafUuids;
|
|
||||||
ankerl::unordered_dense::map<UUID, std::size_t> rootTotalBytes;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const SharedData& BuildData()
|
|
||||||
{
|
|
||||||
static const SharedData s_data = []()
|
|
||||||
{
|
|
||||||
SharedData data;
|
|
||||||
data.rootUuids.reserve(ROOT_ASSET_COUNT);
|
|
||||||
data.leafUuids.reserve(ROOT_ASSET_COUNT * REFS_PER_ROOT);
|
|
||||||
data.rootTotalBytes.reserve(ROOT_ASSET_COUNT);
|
|
||||||
|
|
||||||
eastl::vector<UUID> uuids;
|
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
|
||||||
eastl::vector<eastl::vector<UUID>> hardReferences;
|
|
||||||
uuids.reserve(ROOT_ASSET_COUNT * (1 + REFS_PER_ROOT));
|
|
||||||
flatbuffers.reserve(uuids.capacity());
|
|
||||||
hardReferences.reserve(uuids.capacity());
|
|
||||||
|
|
||||||
for (std::uint32_t i = 0; i < ROOT_ASSET_COUNT; ++i)
|
|
||||||
{
|
|
||||||
BenchmarkAsset root;
|
|
||||||
root.SetName(root.GetHeader().uuid.ToString());
|
|
||||||
root.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
|
||||||
|
|
||||||
std::size_t totalBytes = 0;
|
|
||||||
for (std::uint32_t j = 0; j < REFS_PER_ROOT; ++j)
|
|
||||||
{
|
|
||||||
BenchmarkAssetReferred leaf;
|
|
||||||
leaf.SetName(leaf.GetHeader().uuid.ToString());
|
|
||||||
|
|
||||||
root.GetAsset().refs.emplace_back(leaf.GetHeader().uuid);
|
|
||||||
|
|
||||||
eastl::vector<std::byte> leafFlatbuffer = leaf.Pack();
|
|
||||||
totalBytes += leafFlatbuffer.size();
|
|
||||||
data.leafUuids.push_back(leaf.GetHeader().uuid);
|
|
||||||
uuids.push_back(leaf.GetHeader().uuid);
|
|
||||||
hardReferences.push_back(leaf.GetHardReferences(leafFlatbuffer));
|
|
||||||
flatbuffers.push_back(std::move(leafFlatbuffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
eastl::vector<std::byte> rootFlatbuffer = root.Pack();
|
|
||||||
totalBytes += rootFlatbuffer.size();
|
|
||||||
data.rootTotalBytes.emplace(root.GetHeader().uuid, totalBytes);
|
|
||||||
data.rootUuids.push_back(root.GetHeader().uuid);
|
|
||||||
uuids.push_back(root.GetHeader().uuid);
|
|
||||||
hardReferences.push_back(root.GetHardReferences(rootFlatbuffer));
|
|
||||||
flatbuffers.push_back(std::move(rootFlatbuffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined BIGFOOT_TOOLMODE
|
|
||||||
BigFile bigFile {File { BIGFILE_ENGINEBENCHMARKS_LOCATION }};
|
|
||||||
bigFile.Clear();
|
|
||||||
bigFile.SaveAssetFlatbuffers(uuids, flatbuffers, hardReferences);
|
|
||||||
#elif defined BIGFOOT_GAME
|
|
||||||
std::size_t totalFlatbufferBytes = 0;
|
|
||||||
std::size_t totalHardReferencesBytes = 0;
|
|
||||||
for (std::size_t i = 0; i < uuids.size(); ++i)
|
|
||||||
{
|
|
||||||
totalFlatbufferBytes += flatbuffers[i].size();
|
|
||||||
totalHardReferencesBytes += hardReferences[i].size() * UUID::UUID_BYTE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
File {SASQUATCH_ENGINEBENCHMARKS_LOCATION}.Delete();
|
|
||||||
SasquatchWriter writer {File {SASQUATCH_ENGINEBENCHMARKS_LOCATION},
|
|
||||||
uuids.size(),
|
|
||||||
totalFlatbufferBytes,
|
|
||||||
totalHardReferencesBytes};
|
|
||||||
for (std::size_t i = 0; i < uuids.size(); ++i)
|
|
||||||
{
|
|
||||||
writer.WriteAsset(uuids[i], flatbuffers[i], hardReferences[i]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}();
|
|
||||||
|
|
||||||
return s_data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(SerializationManagerFixture, LoadAsset)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
std::int64_t bytesProcessed = 0;
|
|
||||||
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
state.PauseTiming();
|
|
||||||
AssetLibrary library;
|
|
||||||
// leafContainer must outlive rootContainer: the loaded root's HardReferences release into leafContainer's
|
|
||||||
// handles on destruction, so declaring it second would tear it down first and use-after-free those handles.
|
|
||||||
AssetContainer<BenchmarkAssetReferred> leafContainer;
|
|
||||||
AssetContainer<BenchmarkAsset> rootContainer;
|
|
||||||
ResetActiveLibrary(library, leafContainer, rootContainer);
|
|
||||||
|
|
||||||
const UUID uuid = m_rootUuids[Random::get<std::size_t>(0, m_rootUuids.size() - 1)];
|
|
||||||
const std::size_t uuidBytes = m_rootTotalBytes->at(uuid);
|
|
||||||
state.ResumeTiming();
|
|
||||||
|
|
||||||
SerializationManager::LoadAsset(uuid);
|
|
||||||
bytesProcessed += static_cast<std::int64_t>(uuidBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations() * (1 + REFS_PER_ROOT));
|
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(SerializationManagerFixture, LoadAsset)->Name("SerializationManager/LoadAsset")->UseRealTime();
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(SerializationManagerFixture, LoadAssets)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
|
||||||
std::int64_t bytesProcessed = 0;
|
|
||||||
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
state.PauseTiming();
|
|
||||||
AssetLibrary library;
|
|
||||||
// leafContainer must outlive rootContainer, see the same comment in the LoadAsset benchmark above.
|
|
||||||
AssetContainer<BenchmarkAssetReferred> leafContainer;
|
|
||||||
AssetContainer<BenchmarkAsset> rootContainer;
|
|
||||||
ResetActiveLibrary(library, leafContainer, rootContainer);
|
|
||||||
|
|
||||||
const eastl::vector<UUID> batch = RandomRootBatch(batchSize);
|
|
||||||
const std::int64_t batchBytes = TotalBytes(batch);
|
|
||||||
state.ResumeTiming();
|
|
||||||
|
|
||||||
SerializationManager::LoadAssets(batch);
|
|
||||||
bytesProcessed += batchBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations() * batchSize * (1 + REFS_PER_ROOT));
|
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(SerializationManagerFixture, LoadAssets)
|
|
||||||
->Name("SerializationManager/LoadAssets")
|
|
||||||
->Arg(1)
|
|
||||||
->Arg(8)
|
|
||||||
->Arg(64)
|
|
||||||
->Arg(512)
|
|
||||||
->Arg(4096)
|
|
||||||
->UseRealTime();
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
#if defined BIGFOOT_TOOLMODE
|
|
||||||
BENCHMARK_DEFINE_F(SerializationManagerFixture, SaveAsset)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
AssetLibrary library;
|
|
||||||
AssetContainer<BenchmarkAsset> container;
|
|
||||||
std::ignore = library.Insert(&container);
|
|
||||||
SetActiveAssetLibrary(&library);
|
|
||||||
|
|
||||||
std::int64_t bytesProcessed = 0;
|
|
||||||
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
state.PauseTiming();
|
|
||||||
auto* asset = CreateAsset<BenchmarkAsset>();
|
|
||||||
asset->SetName(asset->GetHeader().uuid.ToString());
|
|
||||||
asset->GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
|
||||||
for (std::uint32_t j = 0; j < REFS_PER_ROOT; ++j)
|
|
||||||
{
|
|
||||||
asset->GetAsset().refs.emplace_back(m_leafUuids[Random::get<std::size_t>(0, m_leafUuids.size() - 1)]);
|
|
||||||
}
|
|
||||||
const UUID uuid = asset->GetHeader().uuid;
|
|
||||||
const std::size_t assetBytes = asset->Pack().size();
|
|
||||||
bytesProcessed += static_cast<std::int64_t>(assetBytes);
|
|
||||||
state.ResumeTiming();
|
|
||||||
|
|
||||||
benchmark::DoNotOptimize(SerializationManager::SaveAsset(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(SerializationManagerFixture, SaveAsset)->Name("SerializationManager/SaveAsset")->UseRealTime();
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(SerializationManagerFixture, SaveAssets)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
|
||||||
|
|
||||||
AssetLibrary library;
|
|
||||||
AssetContainer<BenchmarkAsset> container;
|
|
||||||
std::ignore = library.Insert(&container);
|
|
||||||
SetActiveAssetLibrary(&library);
|
|
||||||
|
|
||||||
std::int64_t bytesProcessed = 0;
|
|
||||||
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
state.PauseTiming();
|
|
||||||
eastl::vector<UUID> uuids;
|
|
||||||
uuids.reserve(batchSize);
|
|
||||||
std::size_t batchBytes = 0;
|
|
||||||
for (std::size_t i = 0; i < batchSize; ++i)
|
|
||||||
{
|
|
||||||
auto* asset = CreateAsset<BenchmarkAsset>();
|
|
||||||
asset->SetName(asset->GetHeader().uuid.ToString());
|
|
||||||
asset->GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
|
||||||
for (std::uint32_t j = 0; j < REFS_PER_ROOT; ++j)
|
|
||||||
{
|
|
||||||
asset->GetAsset().refs.emplace_back(m_leafUuids[Random::get<std::size_t>(0, m_leafUuids.size() - 1)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
batchBytes += asset->Pack().size();
|
|
||||||
uuids.push_back(asset->GetHeader().uuid);
|
|
||||||
}
|
|
||||||
state.ResumeTiming();
|
|
||||||
|
|
||||||
benchmark::DoNotOptimize(SerializationManager::SaveAssets(uuids));
|
|
||||||
bytesProcessed += static_cast<std::int64_t>(batchBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations() * batchSize);
|
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(SerializationManagerFixture, SaveAssets)
|
|
||||||
->Name("SerializationManager/SaveAssets")
|
|
||||||
->Arg(1)
|
|
||||||
->Arg(8)
|
|
||||||
->Arg(64)
|
|
||||||
->Arg(512)
|
|
||||||
->UseRealTime();
|
|
||||||
#endif
|
|
||||||
} // namespace Bigfoot
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file main.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Utils/Log/LogMacros.hpp>
|
|
||||||
#include <Utils/TargetMacros.h>
|
|
||||||
|
|
||||||
#include <benchmark/benchmark.h>
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime);
|
|
||||||
|
|
||||||
::benchmark::Initialize(&argc, argv);
|
|
||||||
if (::benchmark::ReportUnrecognizedArguments(argc, argv))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
::benchmark::RunSpecifiedBenchmarks();
|
|
||||||
::benchmark::Shutdown();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
if(${VULKAN})
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/GraphicsVulkan)
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/GraphicsCore)
|
|
||||||
endif()
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|
||||||
project(${PackageName}Benchmarks)
|
|
||||||
|
|
||||||
bigfoot_create_package_benchmarks(
|
|
||||||
"Bigfoot/Benchmarks/Graphics")
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file main.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Utils/Log/LogMacros.hpp>
|
|
||||||
#include <Utils/TargetMacros.h>
|
|
||||||
|
|
||||||
#include <benchmark/benchmark.h>
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime);
|
|
||||||
|
|
||||||
::benchmark::Initialize(&argc, argv);
|
|
||||||
if (::benchmark::ReportUnrecognizedArguments(argc, argv))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
::benchmark::RunSpecifiedBenchmarks();
|
|
||||||
::benchmark::Shutdown();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|
||||||
project(${PackageName}Benchmarks)
|
|
||||||
|
|
||||||
bigfoot_create_package_benchmarks(
|
|
||||||
"Bigfoot/Benchmarks/Graphics")
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file main.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Utils/Log/LogMacros.hpp>
|
|
||||||
#include <Utils/TargetMacros.h>
|
|
||||||
|
|
||||||
#include <benchmark/benchmark.h>
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime);
|
|
||||||
|
|
||||||
::benchmark::Initialize(&argc, argv);
|
|
||||||
if (::benchmark::ReportUnrecognizedArguments(argc, argv))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
::benchmark::RunSpecifiedBenchmarks();
|
|
||||||
::benchmark::Shutdown();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file Graph.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Utils/Algorithm/Graph.hpp>
|
|
||||||
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
#include <benchmark/benchmark.h>
|
|
||||||
#include <effolkronium/random.hpp>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
using Random = effolkronium::random_static;
|
|
||||||
|
|
||||||
class LayeredTopologicalSortFixture: public benchmark::Fixture
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
/*
|
|
||||||
* Nodes are grouped into layers, and every node in a layer depends on up to DEPENDENCY_MAX_COUNT
|
|
||||||
* distinct nodes randomly picked from the previous layer.
|
|
||||||
*/
|
|
||||||
void SetUp(benchmark::State& state) override
|
|
||||||
{
|
|
||||||
Random::seed(0x5EEDU);
|
|
||||||
|
|
||||||
const auto nodeCount = static_cast<std::uint32_t>(state.range(0));
|
|
||||||
|
|
||||||
m_graph.clear();
|
|
||||||
m_nodes.clear();
|
|
||||||
m_graph.reserve(nodeCount);
|
|
||||||
m_nodes.reserve(nodeCount);
|
|
||||||
|
|
||||||
for (std::uint32_t node = 0; node < nodeCount; ++node)
|
|
||||||
{
|
|
||||||
m_nodes.insert(node);
|
|
||||||
eastl::vector<std::uint32_t>& edges = m_graph[node];
|
|
||||||
|
|
||||||
const std::uint32_t layerStart = (node / NODE_COUNT_PER_LAYER) * NODE_COUNT_PER_LAYER;
|
|
||||||
if (layerStart == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::uint32_t previousLayerStart = layerStart - NODE_COUNT_PER_LAYER;
|
|
||||||
ankerl::unordered_dense::set<std::uint32_t> picked;
|
|
||||||
for (std::uint32_t i = 0; i < DEPENDENCY_MAX_COUNT; ++i)
|
|
||||||
{
|
|
||||||
const std::uint32_t dependency = Random::get<std::uint32_t>(previousLayerStart, layerStart - 1);
|
|
||||||
if (picked.insert(dependency).second)
|
|
||||||
{
|
|
||||||
edges.push_back(dependency);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr std::uint32_t NODE_COUNT_PER_LAYER = 64;
|
|
||||||
static constexpr std::uint32_t DEPENDENCY_MAX_COUNT = 4;
|
|
||||||
|
|
||||||
ankerl::unordered_dense::map<std::uint32_t, eastl::vector<std::uint32_t>> m_graph;
|
|
||||||
ankerl::unordered_dense::set<std::uint32_t> m_nodes;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(LayeredTopologicalSortFixture, LayeredTopologicalSortBench)(benchmark::State& state)
|
|
||||||
{
|
|
||||||
const auto nodeCount = static_cast<std::uint32_t>(state.range(0));
|
|
||||||
|
|
||||||
for (auto _: state)
|
|
||||||
{
|
|
||||||
eastl::vector<eastl::vector<std::uint32_t>> waves;
|
|
||||||
eastl::vector<std::uint32_t> cyclicNodes;
|
|
||||||
benchmark::DoNotOptimize(LayeredTopologicalSort(m_graph, m_nodes, waves, cyclicNodes));
|
|
||||||
benchmark::DoNotOptimize(waves);
|
|
||||||
benchmark::ClobberMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations() * nodeCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(LayeredTopologicalSortFixture, LayeredTopologicalSortBench)
|
|
||||||
->Name("Bigfoot::LayeredTopologicalSort")
|
|
||||||
->Arg(512)
|
|
||||||
->Arg(8192)
|
|
||||||
->Arg(262'144)
|
|
||||||
->Arg(4'194'304);
|
|
||||||
} // namespace Bigfoot
|
|
||||||
@@ -2,4 +2,4 @@ get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|||||||
project(${PackageName}Benchmarks)
|
project(${PackageName}Benchmarks)
|
||||||
|
|
||||||
bigfoot_create_package_benchmarks(
|
bigfoot_create_package_benchmarks(
|
||||||
"Bigfoot/Benchmarks")
|
"")
|
||||||
@@ -11,7 +11,10 @@
|
|||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
using Random = effolkronium::random_static;
|
using Random = effolkronium::random_static;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
struct MyComplexStruct
|
struct MyComplexStruct
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file main.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Utils/Log/LogMacros.hpp>
|
|
||||||
#include <Utils/TargetMacros.h>
|
|
||||||
|
|
||||||
#include <benchmark/benchmark.h>
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime);
|
|
||||||
|
|
||||||
::benchmark::Initialize(&argc, argv);
|
|
||||||
if (::benchmark::ReportUnrecognizedArguments(argc, argv))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
::benchmark::RunSpecifiedBenchmarks();
|
|
||||||
::benchmark::Shutdown();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System)
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Graphics)
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file AssetBase.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date April 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Engine/Asset/AssetBase.hpp>
|
|
||||||
|
|
||||||
#include <Engine/Asset/Reference_generated.hpp>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
void AssetBase::HardReferenceVisitor::Field([[maybe_unused]] size_t p_fieldIndex,
|
|
||||||
[[maybe_unused]] size_t p_setIndex,
|
|
||||||
const flatbuffers::ElementaryType p_type,
|
|
||||||
const bool p_isVector,
|
|
||||||
const flatbuffers::TypeTable* p_typeTable,
|
|
||||||
[[maybe_unused]] const char* p_name,
|
|
||||||
const std::uint8_t* p_val)
|
|
||||||
{
|
|
||||||
if (!p_isVector)
|
|
||||||
{
|
|
||||||
Visit(p_type, p_typeTable, p_val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void AssetBase::HardReferenceVisitor::Element([[maybe_unused]] size_t p_index,
|
|
||||||
const flatbuffers::ElementaryType p_type,
|
|
||||||
const flatbuffers::TypeTable* p_typeTable,
|
|
||||||
const std::uint8_t* p_val)
|
|
||||||
{
|
|
||||||
Visit(p_type, p_typeTable, p_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
eastl::vector<UUID> AssetBase::HardReferenceVisitor::GetUUIDs() const
|
|
||||||
{
|
|
||||||
eastl::vector<UUID> uuids;
|
|
||||||
uuids.reserve(m_uuids.size());
|
|
||||||
std::copy(m_uuids.begin(), m_uuids.end(), eastl::back_inserter(uuids));
|
|
||||||
return uuids;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void AssetBase::HardReferenceVisitor::Visit(const flatbuffers::ElementaryType p_type,
|
|
||||||
const flatbuffers::TypeTable* p_typeTable,
|
|
||||||
const std::uint8_t* p_val)
|
|
||||||
{
|
|
||||||
if (p_val == nullptr || p_type != flatbuffers::ET_SEQUENCE ||
|
|
||||||
p_typeTable != ::Flat::Bigfoot::HardReference::MiniReflectTypeTable())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ::Flat::Bigfoot::HardReference* hardReference = reinterpret_cast<const ::Flat::Bigfoot::HardReference*>(
|
|
||||||
p_val);
|
|
||||||
m_uuids.emplace(flatbuffers::UnPack(hardReference->uuid()));
|
|
||||||
}
|
|
||||||
} // namespace Bigfoot
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file AssetContainer.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Engine/Asset/AssetContainer.hpp>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
ContainerHandle::ContainerHandle(AssetContainerBase* p_assetContainer, const UUID p_uuid):
|
|
||||||
m_assetContainer(p_assetContainer),
|
|
||||||
m_uuid(p_uuid)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
std::uint32_t ContainerHandle::GetHardRefCount() const
|
|
||||||
{
|
|
||||||
return m_hardRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void ContainerHandle::IncrementHardRefCount()
|
|
||||||
{
|
|
||||||
if (m_hardRefCount == 0)
|
|
||||||
{
|
|
||||||
m_assetContainer->CancelRemoval(m_uuid);
|
|
||||||
}
|
|
||||||
++m_hardRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void ContainerHandle::DecrementHardRefCount()
|
|
||||||
{
|
|
||||||
--m_hardRefCount;
|
|
||||||
if (m_hardRefCount == 0)
|
|
||||||
{
|
|
||||||
m_assetContainer->QueueForRemoval(m_uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
std::uint32_t ContainerHandle::GetSoftRefCount() const
|
|
||||||
{
|
|
||||||
return m_softRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void ContainerHandle::IncrementSoftRefCount()
|
|
||||||
{
|
|
||||||
++m_softRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void ContainerHandle::DecrementSoftRefCount()
|
|
||||||
{
|
|
||||||
--m_softRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
AssetBase* ContainerHandle::GetAsset()
|
|
||||||
{
|
|
||||||
return m_asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
const AssetBase* ContainerHandle::GetAsset() const
|
|
||||||
{
|
|
||||||
return m_asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void ContainerHandle::SetAsset(AssetBase* p_asset)
|
|
||||||
{
|
|
||||||
m_asset = p_asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
bool AssetContainerBase::Has(const UUID& p_uuid) const
|
|
||||||
{
|
|
||||||
const Entry* entry = FindEntry(p_uuid);
|
|
||||||
return entry != nullptr && entry->m_assetSlotKey.Valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
ContainerHandle* AssetContainerBase::AcquireContainerHandle(const UUID& p_uuid)
|
|
||||||
{
|
|
||||||
return GetOrCreateEntry(p_uuid).m_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void AssetContainerBase::Remove(const UUID& p_uuid)
|
|
||||||
{
|
|
||||||
if (Entry* entry = FindEntry(p_uuid); entry != nullptr)
|
|
||||||
{
|
|
||||||
if (entry->m_assetSlotKey.Valid())
|
|
||||||
{
|
|
||||||
entry->m_handle->SetAsset(nullptr);
|
|
||||||
RemoveAsset(entry->m_assetSlotKey);
|
|
||||||
entry->m_assetSlotKey = SlotMapKey {};
|
|
||||||
}
|
|
||||||
m_handles.Remove(entry->m_handleSlotKey);
|
|
||||||
m_uuidToEntry.erase(p_uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void AssetContainerBase::QueueForRemoval(const UUID& p_uuid)
|
|
||||||
{
|
|
||||||
m_pendingRemovalUuids.push_back(p_uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void AssetContainerBase::CancelRemoval(const UUID& p_uuid)
|
|
||||||
{
|
|
||||||
auto* const pendingIt = eastl::find(m_pendingRemovalUuids.begin(), m_pendingRemovalUuids.end(), p_uuid);
|
|
||||||
if (pendingIt != m_pendingRemovalUuids.end())
|
|
||||||
{
|
|
||||||
m_pendingRemovalUuids.erase_unsorted(pendingIt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void AssetContainerBase::ProcessPendingRemovals()
|
|
||||||
{
|
|
||||||
eastl::vector<UUID> toRemove;
|
|
||||||
toRemove.swap(m_pendingRemovalUuids);
|
|
||||||
|
|
||||||
for (const UUID& uuid: toRemove)
|
|
||||||
{
|
|
||||||
Remove(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
bool AssetContainerBase::IsMarkedForRemove(const UUID& p_uuid)
|
|
||||||
{
|
|
||||||
return eastl::find(m_pendingRemovalUuids.begin(), m_pendingRemovalUuids.end(), p_uuid) !=
|
|
||||||
m_pendingRemovalUuids.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
AssetContainerBase::Entry* AssetContainerBase::FindEntry(const UUID& p_uuid)
|
|
||||||
{
|
|
||||||
const auto entryIt = m_uuidToEntry.find(p_uuid);
|
|
||||||
return entryIt != m_uuidToEntry.end() ? &entryIt->second : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
const AssetContainerBase::Entry* AssetContainerBase::FindEntry(const UUID& p_uuid) const
|
|
||||||
{
|
|
||||||
const auto entryIt = m_uuidToEntry.find(p_uuid);
|
|
||||||
return entryIt != m_uuidToEntry.end() ? &entryIt->second : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
AssetContainerBase::Entry& AssetContainerBase::GetOrCreateEntry(const UUID& p_uuid)
|
|
||||||
{
|
|
||||||
auto [entryIt, inserted] = m_uuidToEntry.try_emplace(p_uuid);
|
|
||||||
if (inserted)
|
|
||||||
{
|
|
||||||
entryIt->second.m_handleSlotKey = m_handles.Insert(this, p_uuid);
|
|
||||||
entryIt->second.m_handle = m_handles.Get(entryIt->second.m_handleSlotKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entryIt->second;
|
|
||||||
}
|
|
||||||
} // namespace Bigfoot
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file AssetLibrary.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Engine/Asset/AssetLibrary.hpp>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
AssetContainerBase* AssetLibrary::GetAssetContainer(const AssetTypeID p_typeID)
|
|
||||||
{
|
|
||||||
if (const auto container = m_assetContainers.find(p_typeID); container != m_assetContainers.end())
|
|
||||||
{
|
|
||||||
return container->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
const AssetContainerBase* AssetLibrary::GetAssetContainer(const AssetTypeID p_typeID) const
|
|
||||||
{
|
|
||||||
if (const auto container = m_assetContainers.find(p_typeID); container != m_assetContainers.end())
|
|
||||||
{
|
|
||||||
return container->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
const AssetContainerBase* AssetLibrary::GetAssetContainer(const UUID& p_uuid) const
|
|
||||||
{
|
|
||||||
for (const auto [typeId, container]: m_assetContainers)
|
|
||||||
{
|
|
||||||
if (container->Has(p_uuid))
|
|
||||||
{
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
AssetContainerBase* AssetLibrary::GetAssetContainer(const UUID& p_uuid)
|
|
||||||
{
|
|
||||||
for (const auto [typeId, container]: m_assetContainers)
|
|
||||||
{
|
|
||||||
if (container->Has(p_uuid))
|
|
||||||
{
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
bool AssetLibrary::IsLoaded(const UUID& p_uuid) const
|
|
||||||
{
|
|
||||||
return GetAssetContainer(p_uuid) != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void AssetLibrary::ProcessPendingRemovals()
|
|
||||||
{
|
|
||||||
for (const auto [typeId, container]: m_assetContainers)
|
|
||||||
{
|
|
||||||
container->ProcessPendingRemovals();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void SetActiveAssetLibrary(AssetLibrary* p_assetLibrary)
|
|
||||||
{
|
|
||||||
g_activeAssetLibrary = p_assetLibrary;
|
|
||||||
}
|
|
||||||
} // namespace Bigfoot
|
|
||||||
@@ -1,851 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file BigFile.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date October 2025
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Engine/BigFile/BigFile.hpp>
|
|
||||||
|
|
||||||
#include <Engine/EngineAssertHandler.hpp>
|
|
||||||
|
|
||||||
#include <Utils/Format.hpp>
|
|
||||||
|
|
||||||
#include <EASTL/algorithm.h>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
#ifdef BIGFOOT_TOOLMODE
|
|
||||||
BigFile::BigFile(const File& p_file)
|
|
||||||
{
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_open_v2(p_file.ToAbsolute().GetPath().data(), &m_db, SQLITE_OPEN_READWRITE, nullptr);
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler,
|
|
||||||
result == SQLITE_OK,
|
|
||||||
"Failed to open BigFile {} DB: {}",
|
|
||||||
p_file.ToAbsolute().GetPath(),
|
|
||||||
sqlite3_errmsg(m_db));
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int synchronousResult = sqlite3_exec(m_db, "PRAGMA synchronous = NORMAL;", nullptr, nullptr, nullptr);
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
synchronousResult == SQLITE_OK,
|
|
||||||
"Failed to set synchronous pragma: {}",
|
|
||||||
sqlite3_errmsg(m_db));
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int foreignKeysResult = sqlite3_exec(m_db, "PRAGMA foreign_keys = ON;", nullptr, nullptr, nullptr);
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
foreignKeysResult == SQLITE_OK,
|
|
||||||
"Failed to set foreign_keys pragma: {}",
|
|
||||||
sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::BeginTransaction()
|
|
||||||
{
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_exec(m_db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr);
|
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to begin transaction: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::CommitTransaction()
|
|
||||||
{
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_exec(m_db, "COMMIT TRANSACTION;", nullptr, nullptr, nullptr);
|
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to commit: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::RollbackTransaction()
|
|
||||||
{
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_exec(m_db, "ROLLBACK TRANSACTION;", nullptr, nullptr, nullptr);
|
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to rollback: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::Clear()
|
|
||||||
{
|
|
||||||
BeginTransaction();
|
|
||||||
|
|
||||||
BigFile::Request {*this, "DELETE FROM AssetHardReference;"}.Execute();
|
|
||||||
BigFile::Request {*this, "DELETE FROM Asset;"}.Execute();
|
|
||||||
BigFile::Request {*this, "DELETE FROM AssetMetadata;"}.Execute();
|
|
||||||
|
|
||||||
CommitTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::~BigFile()
|
|
||||||
{
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_close_v2(m_db);
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to close BigFile DB: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
eastl::vector<std::byte> BigFile::GetAssetFlatbuffer(const UUID& p_uuid) const
|
|
||||||
{
|
|
||||||
BigFile::Request assetRequest {*this, "SELECT Asset FROM Asset WHERE UUID = ?1;"};
|
|
||||||
assetRequest.Bind(1, p_uuid.ToBytes());
|
|
||||||
|
|
||||||
if (!assetRequest.Step())
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::span<const std::byte> flatbuffer = assetRequest.Get(0);
|
|
||||||
return eastl::vector<std::byte> {flatbuffer.begin(), flatbuffer.end()};
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
eastl::vector<eastl::vector<std::byte>> BigFile::GetAssetFlatbuffers(const eastl::span<const UUID> p_uuids) const
|
|
||||||
{
|
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers(p_uuids.size());
|
|
||||||
|
|
||||||
if (p_uuids.empty())
|
|
||||||
{
|
|
||||||
return flatbuffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
ankerl::unordered_dense::map<UUID, eastl::vector<std::size_t>> uuidToIndices;
|
|
||||||
uuidToIndices.reserve(p_uuids.size());
|
|
||||||
for (std::size_t i = 0; i < p_uuids.size(); ++i)
|
|
||||||
{
|
|
||||||
uuidToIndices[p_uuids[i]].push_back(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
eastl::vector<UUID> distinctUUIDs;
|
|
||||||
distinctUUIDs.reserve(uuidToIndices.size());
|
|
||||||
for (const auto& [uuid, indices]: uuidToIndices)
|
|
||||||
{
|
|
||||||
distinctUUIDs.push_back(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr std::size_t PARAMS_PER_ROW = 1;
|
|
||||||
const std::size_t maxRowsPerStatement = static_cast<std::size_t>(
|
|
||||||
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
|
||||||
PARAMS_PER_ROW;
|
|
||||||
|
|
||||||
for (std::size_t chunkStart = 0; chunkStart < distinctUUIDs.size(); chunkStart += maxRowsPerStatement)
|
|
||||||
{
|
|
||||||
const std::size_t chunkSize = eastl::min(maxRowsPerStatement, distinctUUIDs.size() - chunkStart);
|
|
||||||
|
|
||||||
eastl::string placeholders;
|
|
||||||
placeholders.reserve(chunkSize * 2);
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
placeholders += ", ";
|
|
||||||
}
|
|
||||||
placeholders += "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::string sql = Format("SELECT UUID, Asset FROM Asset WHERE UUID IN ({});", placeholders);
|
|
||||||
|
|
||||||
BigFile::Request assetRequest {*this, sql};
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
assetRequest.Bind(static_cast<std::uint32_t>(i + 1), distinctUUIDs[chunkStart + i].ToBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
while (assetRequest.Step())
|
|
||||||
{
|
|
||||||
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawUUID {
|
|
||||||
static_cast<std::span<const std::byte>>(assetRequest.Get(0))};
|
|
||||||
const UUID uuid {rawUUID};
|
|
||||||
|
|
||||||
const auto indicesIt = uuidToIndices.find(uuid);
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
indicesIt != uuidToIndices.end(),
|
|
||||||
"Returned UUID {} not found in requested UUIDs",
|
|
||||||
uuid);
|
|
||||||
|
|
||||||
const eastl::span<const std::byte> flatbuffer = assetRequest.Get(1);
|
|
||||||
|
|
||||||
for (const std::size_t index: indicesIt->second)
|
|
||||||
{
|
|
||||||
flatbuffers[index].assign(flatbuffer.begin(), flatbuffer.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return flatbuffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
eastl::vector<UUID> BigFile::GetAssetHardReferences(const UUID& p_uuid) const
|
|
||||||
{
|
|
||||||
BigFile::Request hardReferencesRequest {*this, "SELECT HardReference FROM AssetHardReference WHERE UUID = ?1;"};
|
|
||||||
hardReferencesRequest.Bind(1, p_uuid.ToBytes());
|
|
||||||
|
|
||||||
eastl::vector<UUID> hardReferences;
|
|
||||||
while (hardReferencesRequest.Step())
|
|
||||||
{
|
|
||||||
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawUUID {
|
|
||||||
static_cast<std::span<const std::byte>>(hardReferencesRequest.Get(0))};
|
|
||||||
hardReferences.emplace_back(rawUUID);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hardReferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
eastl::vector<eastl::vector<UUID>> BigFile::GetAssetsHardReferences(eastl::span<const UUID> p_uuids) const
|
|
||||||
{
|
|
||||||
eastl::vector<eastl::vector<UUID>> hardReferences(p_uuids.size());
|
|
||||||
|
|
||||||
if (p_uuids.empty())
|
|
||||||
{
|
|
||||||
return hardReferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
ankerl::unordered_dense::map<UUID, eastl::vector<std::size_t>> uuidToIndices;
|
|
||||||
uuidToIndices.reserve(p_uuids.size());
|
|
||||||
for (std::size_t i = 0; i < p_uuids.size(); ++i)
|
|
||||||
{
|
|
||||||
uuidToIndices[p_uuids[i]].push_back(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
eastl::vector<UUID> distinctUUIDs;
|
|
||||||
distinctUUIDs.reserve(uuidToIndices.size());
|
|
||||||
for (const auto& [uuid, indices]: uuidToIndices)
|
|
||||||
{
|
|
||||||
distinctUUIDs.push_back(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr std::size_t PARAMS_PER_ROW = 1;
|
|
||||||
const std::size_t maxRowsPerStatement = static_cast<std::size_t>(
|
|
||||||
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
|
||||||
PARAMS_PER_ROW;
|
|
||||||
|
|
||||||
for (std::size_t chunkStart = 0; chunkStart < distinctUUIDs.size(); chunkStart += maxRowsPerStatement)
|
|
||||||
{
|
|
||||||
const std::size_t chunkSize = eastl::min(maxRowsPerStatement, distinctUUIDs.size() - chunkStart);
|
|
||||||
|
|
||||||
eastl::string placeholders;
|
|
||||||
placeholders.reserve(chunkSize * 2);
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
placeholders += ", ";
|
|
||||||
}
|
|
||||||
placeholders += "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::string sql = Format("SELECT UUID, HardReference FROM AssetHardReference WHERE UUID IN ({});",
|
|
||||||
placeholders);
|
|
||||||
|
|
||||||
BigFile::Request hardReferencesRequest {*this, sql};
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
hardReferencesRequest.Bind(static_cast<std::uint32_t>(i + 1), distinctUUIDs[chunkStart + i].ToBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
while (hardReferencesRequest.Step())
|
|
||||||
{
|
|
||||||
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawOwnerUUID {
|
|
||||||
static_cast<std::span<const std::byte>>(hardReferencesRequest.Get(0))};
|
|
||||||
const UUID ownerUUID {rawOwnerUUID};
|
|
||||||
|
|
||||||
const auto indicesIt = uuidToIndices.find(ownerUUID);
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
indicesIt != uuidToIndices.end(),
|
|
||||||
"Returned UUID {} not found in requested UUIDs",
|
|
||||||
ownerUUID);
|
|
||||||
|
|
||||||
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawHardReference {
|
|
||||||
static_cast<std::span<const std::byte>>(hardReferencesRequest.Get(1))};
|
|
||||||
|
|
||||||
for (const std::size_t index: indicesIt->second)
|
|
||||||
{
|
|
||||||
hardReferences[index].emplace_back(rawHardReference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hardReferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
eastl::optional<BigFile::AssetTime> BigFile::GetAssetTime(const UUID& p_uuid) const
|
|
||||||
{
|
|
||||||
BigFile::Request timeRequest {*this, "SELECT CreateTime, ModificationTime FROM AssetMetadata WHERE UUID = ?1;"};
|
|
||||||
timeRequest.Bind(1, p_uuid.ToBytes());
|
|
||||||
|
|
||||||
if (!timeRequest.Step())
|
|
||||||
{
|
|
||||||
return eastl::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return AssetTime {.m_creationTime = Time {static_cast<std::uint64_t>(timeRequest.Get(0))},
|
|
||||||
.m_modificationTime = Time {static_cast<std::uint64_t>(timeRequest.Get(1))}};
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
eastl::vector<eastl::optional<BigFile::AssetTime>> BigFile::GetAssetsTime(const eastl::span<const UUID> p_uuids) const
|
|
||||||
{
|
|
||||||
eastl::vector<eastl::optional<AssetTime>> times(p_uuids.size());
|
|
||||||
|
|
||||||
if (p_uuids.empty())
|
|
||||||
{
|
|
||||||
return times;
|
|
||||||
}
|
|
||||||
|
|
||||||
ankerl::unordered_dense::map<UUID, eastl::vector<std::size_t>> uuidToIndices;
|
|
||||||
uuidToIndices.reserve(p_uuids.size());
|
|
||||||
for (std::size_t i = 0; i < p_uuids.size(); ++i)
|
|
||||||
{
|
|
||||||
uuidToIndices[p_uuids[i]].push_back(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
eastl::vector<UUID> distinctUUIDs;
|
|
||||||
distinctUUIDs.reserve(uuidToIndices.size());
|
|
||||||
for (const auto& [uuid, indices]: uuidToIndices)
|
|
||||||
{
|
|
||||||
distinctUUIDs.push_back(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr std::size_t PARAMS_PER_ROW = 1;
|
|
||||||
const std::size_t maxRowsPerStatement = static_cast<std::size_t>(
|
|
||||||
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
|
||||||
PARAMS_PER_ROW;
|
|
||||||
|
|
||||||
for (std::size_t chunkStart = 0; chunkStart < distinctUUIDs.size(); chunkStart += maxRowsPerStatement)
|
|
||||||
{
|
|
||||||
const std::size_t chunkSize = eastl::min(maxRowsPerStatement, distinctUUIDs.size() - chunkStart);
|
|
||||||
|
|
||||||
eastl::string placeholders;
|
|
||||||
placeholders.reserve(chunkSize * 2);
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
placeholders += ", ";
|
|
||||||
}
|
|
||||||
placeholders += "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::string sql = Format(
|
|
||||||
"SELECT UUID, CreateTime, ModificationTime FROM AssetMetadata WHERE UUID IN ({});",
|
|
||||||
placeholders);
|
|
||||||
|
|
||||||
BigFile::Request timeRequest {*this, sql};
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
timeRequest.Bind(static_cast<std::uint32_t>(i + 1), distinctUUIDs[chunkStart + i].ToBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
while (timeRequest.Step())
|
|
||||||
{
|
|
||||||
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawUUID {
|
|
||||||
static_cast<std::span<const std::byte>>(timeRequest.Get(0))};
|
|
||||||
const UUID uuid {rawUUID};
|
|
||||||
|
|
||||||
const auto indicesIt = uuidToIndices.find(uuid);
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
indicesIt != uuidToIndices.end(),
|
|
||||||
"Returned UUID {} not found in requested UUIDs",
|
|
||||||
uuid);
|
|
||||||
|
|
||||||
const AssetTime assetTime {.m_creationTime = Time {static_cast<std::uint64_t>(timeRequest.Get(1))},
|
|
||||||
.m_modificationTime = Time {static_cast<std::uint64_t>(timeRequest.Get(2))}};
|
|
||||||
|
|
||||||
for (const std::size_t index: indicesIt->second)
|
|
||||||
{
|
|
||||||
times[index] = assetTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return times;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::SaveAssetFlatbuffer(const UUID& p_uuid,
|
|
||||||
const eastl::span<const std::byte> p_flatbuffer,
|
|
||||||
const eastl::span<const UUID> p_hardReferences)
|
|
||||||
{
|
|
||||||
BeginTransaction();
|
|
||||||
|
|
||||||
BigFile::Request metadataRequest {*this,
|
|
||||||
"INSERT INTO AssetMetadata (UUID) VALUES (?1) "
|
|
||||||
"ON CONFLICT(UUID) DO NOTHING;"};
|
|
||||||
metadataRequest.Bind(1, p_uuid.ToBytes());
|
|
||||||
metadataRequest.Execute();
|
|
||||||
|
|
||||||
BigFile::Request assetRequest {*this,
|
|
||||||
"INSERT INTO Asset (UUID, Asset) VALUES (?1, ?2) "
|
|
||||||
"ON CONFLICT(UUID) DO UPDATE SET Asset = excluded.Asset;"};
|
|
||||||
assetRequest.Bind(1, p_uuid.ToBytes());
|
|
||||||
assetRequest.Bind(2, p_flatbuffer);
|
|
||||||
assetRequest.Execute();
|
|
||||||
|
|
||||||
BigFile::Request deleteHardReferencesRequest {*this, "DELETE FROM AssetHardReference WHERE UUID = ?1;"};
|
|
||||||
deleteHardReferencesRequest.Bind(1, p_uuid.ToBytes());
|
|
||||||
deleteHardReferencesRequest.Execute();
|
|
||||||
|
|
||||||
constexpr std::size_t HARDREF_PARAMS_PER_ROW = 2;
|
|
||||||
constexpr std::size_t HARDREF_PLACEHOLDER_RESERVE_CHARS_PER_ROW = 8;
|
|
||||||
const std::size_t maxHardRefRowsPerStatement = static_cast<std::size_t>(
|
|
||||||
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
|
||||||
HARDREF_PARAMS_PER_ROW;
|
|
||||||
|
|
||||||
for (std::size_t chunkStart = 0; chunkStart < p_hardReferences.size(); chunkStart += maxHardRefRowsPerStatement)
|
|
||||||
{
|
|
||||||
const std::size_t chunkSize = eastl::min(maxHardRefRowsPerStatement, p_hardReferences.size() - chunkStart);
|
|
||||||
|
|
||||||
eastl::string hardReferencePlaceholders;
|
|
||||||
hardReferencePlaceholders.reserve(chunkSize * HARDREF_PLACEHOLDER_RESERVE_CHARS_PER_ROW);
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
hardReferencePlaceholders += ", ";
|
|
||||||
}
|
|
||||||
hardReferencePlaceholders += "(?, ?)";
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::string hardReferenceSQL = Format("INSERT INTO AssetHardReference (UUID, HardReference) VALUES {} "
|
|
||||||
"ON CONFLICT(UUID, HardReference) DO NOTHING;",
|
|
||||||
hardReferencePlaceholders);
|
|
||||||
|
|
||||||
BigFile::Request hardReferenceRequest {*this, hardReferenceSQL};
|
|
||||||
std::uint32_t bindIndex = 1;
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
hardReferenceRequest.Bind(bindIndex++, p_uuid.ToBytes());
|
|
||||||
hardReferenceRequest.Bind(bindIndex++, p_hardReferences[chunkStart + i].ToBytes());
|
|
||||||
}
|
|
||||||
hardReferenceRequest.Execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
CommitTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::SaveAssetFlatbuffers(const eastl::span<const UUID> p_uuids,
|
|
||||||
const eastl::span<const eastl::vector<std::byte>> p_flatbuffers,
|
|
||||||
const eastl::span<const eastl::vector<UUID>> p_hardReferences)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
p_uuids.size() == p_flatbuffers.size() && p_uuids.size() == p_hardReferences.size(),
|
|
||||||
"p_metadatas and p_flatbuffers and p_hardReferences must have the same size");
|
|
||||||
|
|
||||||
if (p_uuids.empty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BeginTransaction();
|
|
||||||
|
|
||||||
constexpr std::size_t METADATA_PARAMS_PER_ROW = 4;
|
|
||||||
constexpr std::size_t METADATA_PLACEHOLDER_RESERVE_CHARS_PER_ROW = 14;
|
|
||||||
constexpr std::size_t ASSET_PLACEHOLDER_RESERVE_CHARS_PER_ROW = 8;
|
|
||||||
const std::size_t maxRowsPerStatement = static_cast<std::size_t>(
|
|
||||||
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
|
||||||
METADATA_PARAMS_PER_ROW;
|
|
||||||
|
|
||||||
for (std::size_t chunkStart = 0; chunkStart < p_uuids.size(); chunkStart += maxRowsPerStatement)
|
|
||||||
{
|
|
||||||
const std::size_t chunkSize = eastl::min(maxRowsPerStatement, p_uuids.size() - chunkStart);
|
|
||||||
|
|
||||||
eastl::string metadataPlaceholders;
|
|
||||||
metadataPlaceholders.reserve(chunkSize * METADATA_PLACEHOLDER_RESERVE_CHARS_PER_ROW);
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
metadataPlaceholders += ", ";
|
|
||||||
}
|
|
||||||
metadataPlaceholders += "(?)";
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::string metadataSQL = Format(
|
|
||||||
"INSERT INTO AssetMetadata (UUID) VALUES {} ON CONFLICT(UUID) DO NOTHING;",
|
|
||||||
metadataPlaceholders);
|
|
||||||
|
|
||||||
BigFile::Request metadataRequest {*this, metadataSQL};
|
|
||||||
std::uint32_t metadataBindIndex = 1;
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
metadataRequest.Bind(metadataBindIndex++, p_uuids[chunkStart + i].ToBytes());
|
|
||||||
}
|
|
||||||
metadataRequest.Execute();
|
|
||||||
|
|
||||||
eastl::string assetPlaceholders;
|
|
||||||
assetPlaceholders.reserve(chunkSize * ASSET_PLACEHOLDER_RESERVE_CHARS_PER_ROW);
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
assetPlaceholders += ", ";
|
|
||||||
}
|
|
||||||
assetPlaceholders += "(?, ?)";
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::string assetSQL = Format(
|
|
||||||
"INSERT INTO Asset (UUID, Asset) VALUES {} ON CONFLICT(UUID) DO UPDATE SET Asset = excluded.Asset;",
|
|
||||||
assetPlaceholders);
|
|
||||||
|
|
||||||
BigFile::Request assetRequest {*this, assetSQL};
|
|
||||||
std::uint32_t assetBindIndex = 1;
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
assetRequest.Bind(assetBindIndex++, p_uuids[chunkStart + i].ToBytes());
|
|
||||||
assetRequest.Bind(assetBindIndex++, p_flatbuffers[chunkStart + i]);
|
|
||||||
}
|
|
||||||
assetRequest.Execute();
|
|
||||||
|
|
||||||
// Replace hard references for every asset in this chunk with its current set.
|
|
||||||
eastl::string deleteInPlaceholders;
|
|
||||||
deleteInPlaceholders.reserve(chunkSize * 3);
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
deleteInPlaceholders += ", ";
|
|
||||||
}
|
|
||||||
deleteInPlaceholders += "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::string deleteHardReferencesSQL = Format("DELETE FROM AssetHardReference WHERE UUID IN ({});",
|
|
||||||
deleteInPlaceholders);
|
|
||||||
|
|
||||||
BigFile::Request deleteHardReferencesRequest {*this, deleteHardReferencesSQL};
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
deleteHardReferencesRequest.Bind(static_cast<std::uint32_t>(i + 1), p_uuids[chunkStart + i].ToBytes());
|
|
||||||
}
|
|
||||||
deleteHardReferencesRequest.Execute();
|
|
||||||
|
|
||||||
eastl::vector<eastl::pair<UUID, UUID>> hardReferencePairs;
|
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
|
||||||
{
|
|
||||||
for (const UUID& hardReference: p_hardReferences[chunkStart + i])
|
|
||||||
{
|
|
||||||
hardReferencePairs.emplace_back(p_uuids[chunkStart + i], hardReference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr std::size_t HARDREF_PARAMS_PER_ROW = 2;
|
|
||||||
constexpr std::size_t HARDREF_PLACEHOLDER_RESERVE_CHARS_PER_ROW = 8;
|
|
||||||
const std::size_t maxHardRefRowsPerStatement = static_cast<std::size_t>(
|
|
||||||
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
|
||||||
HARDREF_PARAMS_PER_ROW;
|
|
||||||
|
|
||||||
for (std::size_t hardRefChunkStart = 0; hardRefChunkStart < hardReferencePairs.size();
|
|
||||||
hardRefChunkStart += maxHardRefRowsPerStatement)
|
|
||||||
{
|
|
||||||
const std::size_t hardRefChunkSize = eastl::min(maxHardRefRowsPerStatement,
|
|
||||||
hardReferencePairs.size() - hardRefChunkStart);
|
|
||||||
|
|
||||||
eastl::string hardReferencePlaceholders;
|
|
||||||
hardReferencePlaceholders.reserve(hardRefChunkSize * HARDREF_PLACEHOLDER_RESERVE_CHARS_PER_ROW);
|
|
||||||
for (std::size_t i = 0; i < hardRefChunkSize; ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
hardReferencePlaceholders += ", ";
|
|
||||||
}
|
|
||||||
hardReferencePlaceholders += "(?, ?)";
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::string hardReferenceSQL = Format(
|
|
||||||
"INSERT INTO AssetHardReference (UUID, HardReference) VALUES {} "
|
|
||||||
"ON CONFLICT(UUID, HardReference) DO NOTHING;",
|
|
||||||
hardReferencePlaceholders);
|
|
||||||
|
|
||||||
BigFile::Request hardReferenceRequest {*this, hardReferenceSQL};
|
|
||||||
std::uint32_t bindIndex = 1;
|
|
||||||
for (std::size_t i = 0; i < hardRefChunkSize; ++i)
|
|
||||||
{
|
|
||||||
const auto& [assetUUID, hardReference] = hardReferencePairs[hardRefChunkStart + i];
|
|
||||||
hardReferenceRequest.Bind(bindIndex++, assetUUID.ToBytes());
|
|
||||||
hardReferenceRequest.Bind(bindIndex++, hardReference.ToBytes());
|
|
||||||
}
|
|
||||||
hardReferenceRequest.Execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CommitTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
bool BigFile::Has(const UUID& p_uuid) const
|
|
||||||
{
|
|
||||||
BigFile::Request request {*this, "SELECT 1 FROM AssetMetadata WHERE UUID = ?1;"};
|
|
||||||
request.Bind(1, p_uuid.ToBytes());
|
|
||||||
|
|
||||||
return request.Step();
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Request(const BigFile& p_bigFile, const eastl::string_view p_request):
|
|
||||||
m_db(p_bigFile.m_db)
|
|
||||||
{
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_prepare_v2(m_db,
|
|
||||||
p_request.data(),
|
|
||||||
static_cast<int>(p_request.size()),
|
|
||||||
&m_statement,
|
|
||||||
nullptr);
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler,
|
|
||||||
result == SQLITE_OK,
|
|
||||||
"Failed to create statement from BigFile DB: {}",
|
|
||||||
sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const std::int32_t p_value)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
|
||||||
"Invalid index for statement");
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_bind_int(m_statement, static_cast<int>(p_index), p_value);
|
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint32_t p_value)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
|
||||||
"Invalid index for statement");
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_bind_int(m_statement, static_cast<int>(p_index), static_cast<int>(p_value));
|
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const std::int64_t p_value)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
|
||||||
"Invalid index for statement");
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_bind_int64(m_statement, static_cast<int>(p_index), p_value);
|
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint64_t p_value)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
|
||||||
"Invalid index for statement");
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_bind_int64(m_statement, static_cast<int>(p_index), std::bit_cast<std::int64_t>(p_value));
|
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const float p_value)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
|
||||||
"Invalid index for statement");
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_bind_double(m_statement, static_cast<int>(p_index), p_value);
|
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const double p_value)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
|
||||||
"Invalid index for statement");
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_bind_double(m_statement, static_cast<int>(p_index), p_value);
|
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const eastl::string_view p_value, const CopyValue p_copy)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
|
||||||
"Invalid index for statement");
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_bind_text(m_statement,
|
|
||||||
static_cast<int>(p_index),
|
|
||||||
p_value.data(),
|
|
||||||
static_cast<int>(p_value.size()),
|
|
||||||
p_copy ? SQLITE_TRANSIENT : SQLITE_STATIC);
|
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void BigFile::Request::Bind(const std::uint32_t p_index,
|
|
||||||
const eastl::span<const std::byte> p_value,
|
|
||||||
const CopyValue p_copy)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
|
||||||
"Invalid index for statement");
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_bind_blob(m_statement,
|
|
||||||
static_cast<int>(p_index),
|
|
||||||
p_value.data(),
|
|
||||||
static_cast<int>(p_value.size()),
|
|
||||||
p_copy ? SQLITE_TRANSIENT : SQLITE_STATIC);
|
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
bool BigFile::Request::Step()
|
|
||||||
{
|
|
||||||
const int result = sqlite3_step(m_statement);
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
(result == SQLITE_DONE) || (result == SQLITE_ROW),
|
|
||||||
"Failed to step through the statement: {}",
|
|
||||||
sqlite3_errmsg(m_db));
|
|
||||||
|
|
||||||
return result == SQLITE_ROW;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
std::uint32_t BigFile::Request::Execute()
|
|
||||||
{
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_step(m_statement);
|
|
||||||
ASSERT(EngineAssertHandler, (result == SQLITE_DONE), "Failed to execute the statement: {}", sqlite3_errmsg(m_db));
|
|
||||||
|
|
||||||
return sqlite3_changes(m_db);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Column::Column(const Request& p_request, const std::uint32_t p_index):
|
|
||||||
m_statement(p_request.m_statement),
|
|
||||||
m_index(p_index)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Column::operator std::int32_t() const
|
|
||||||
{
|
|
||||||
return sqlite3_column_int(m_statement, static_cast<int>(m_index));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Column::operator std::uint32_t() const
|
|
||||||
{
|
|
||||||
return sqlite3_column_int(m_statement, static_cast<int>(m_index));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Column::operator std::int64_t() const
|
|
||||||
{
|
|
||||||
return sqlite3_column_int64(m_statement, static_cast<int>(m_index));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Column::operator std::uint64_t() const
|
|
||||||
{
|
|
||||||
return std::bit_cast<std::uint64_t>(sqlite3_column_int64(m_statement, static_cast<int>(m_index)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Column::operator float() const
|
|
||||||
{
|
|
||||||
return static_cast<float>(sqlite3_column_double(m_statement, static_cast<int>(m_index)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Column::operator double() const
|
|
||||||
{
|
|
||||||
return sqlite3_column_double(m_statement, static_cast<int>(m_index));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Column::operator eastl::string_view() const
|
|
||||||
{
|
|
||||||
return eastl::string_view {
|
|
||||||
reinterpret_cast<const char*>(sqlite3_column_text(m_statement, static_cast<int>(m_index))),
|
|
||||||
static_cast<std::size_t>(sqlite3_column_bytes(m_statement, static_cast<int>(m_index)))};
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Column::operator eastl::span<const std::byte>() const
|
|
||||||
{
|
|
||||||
return eastl::span<const std::byte> {
|
|
||||||
static_cast<const std::byte*>(sqlite3_column_blob(m_statement, static_cast<int>(m_index))),
|
|
||||||
static_cast<std::size_t>(sqlite3_column_bytes(m_statement, static_cast<int>(m_index)))};
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Column::operator std::span<const std::byte>() const
|
|
||||||
{
|
|
||||||
return std::span<const std::byte> {
|
|
||||||
static_cast<const std::byte*>(sqlite3_column_blob(m_statement, static_cast<int>(m_index))),
|
|
||||||
static_cast<std::size_t>(sqlite3_column_bytes(m_statement, static_cast<int>(m_index)))};
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::Column BigFile::Request::Get(const std::uint32_t p_index) const
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
p_index < static_cast<std::uint32_t>(sqlite3_column_count(m_statement)),
|
|
||||||
"Invalid index for column!");
|
|
||||||
return {*this, p_index};
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
BigFile::Request::~Request()
|
|
||||||
{
|
|
||||||
[[maybe_unused]]
|
|
||||||
const int result = sqlite3_finalize(m_statement);
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to finalize statement: {}", sqlite3_errmsg(m_db));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} // namespace Bigfoot
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file AssetBase.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date April 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_ENGINE_ASSET_ASSETBASE_HPP
|
|
||||||
#define BIGFOOT_ENGINE_ASSET_ASSETBASE_HPP
|
|
||||||
#include <System/UUID/UUID.hpp>
|
|
||||||
|
|
||||||
#include <Engine/Asset/Asset_generated.hpp>
|
|
||||||
|
|
||||||
#include <EASTL/span.h>
|
|
||||||
#include <EASTL/vector.h>
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
#include <flatbuffers/minireflect.h>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
class AssetBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~AssetBase() = default;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the header of the asset
|
|
||||||
*
|
|
||||||
* \return The header of the asset
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
virtual const ::Flat::Bigfoot::AssetHeaderT& GetHeader() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the HardReferences the flatbuffer has
|
|
||||||
*
|
|
||||||
* \param p_flatbuffer The flatbuffer
|
|
||||||
* \return The UUIDs of the HardReferences
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
virtual eastl::vector<UUID> GetHardReferences(const eastl::span<const std::byte> p_flatbuffer) const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpack a flatbuffer to the asset
|
|
||||||
*
|
|
||||||
* \param p_flatbuffer The flatbuffer to unpack
|
|
||||||
*/
|
|
||||||
virtual void Unpack(const eastl::span<const std::byte> p_flatbuffer) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pack the asset to a flatbuffer
|
|
||||||
*
|
|
||||||
* \return The packed asset
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
virtual eastl::vector<std::byte> Pack() const = 0;
|
|
||||||
|
|
||||||
AssetBase(const AssetBase& p_asset) = delete;
|
|
||||||
AssetBase& operator=(const AssetBase& p_asset) = delete;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
AssetBase() = default;
|
|
||||||
|
|
||||||
AssetBase(AssetBase&& p_asset) = default;
|
|
||||||
|
|
||||||
AssetBase& operator=(AssetBase&& p_asset) = default;
|
|
||||||
|
|
||||||
class HardReferenceVisitor: public flatbuffers::IterationVisitor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void Field(size_t p_fieldIndex,
|
|
||||||
size_t p_setIndex,
|
|
||||||
const flatbuffers::ElementaryType p_type,
|
|
||||||
const bool p_isVector,
|
|
||||||
const flatbuffers::TypeTable* p_typeTable,
|
|
||||||
const char* p_name,
|
|
||||||
const std::uint8_t* p_val) override;
|
|
||||||
|
|
||||||
void Element(size_t p_index,
|
|
||||||
const flatbuffers::ElementaryType p_type,
|
|
||||||
const flatbuffers::TypeTable* p_typeTable,
|
|
||||||
const std::uint8_t* p_val) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the visited HardReference
|
|
||||||
*
|
|
||||||
* \return The visited HardReferences
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
eastl::vector<UUID> GetUUIDs() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* Visit an element in the flatbuffer
|
|
||||||
*
|
|
||||||
* \param p_type The element type
|
|
||||||
* \param p_typeTable The element typetable
|
|
||||||
* \param p_val The element
|
|
||||||
*/
|
|
||||||
void Visit(const flatbuffers::ElementaryType p_type,
|
|
||||||
const flatbuffers::TypeTable* p_typeTable,
|
|
||||||
const std::uint8_t* p_val);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The HardReferences visited so far
|
|
||||||
*/
|
|
||||||
ankerl::unordered_dense::set<UUID> m_uuids;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} // namespace Bigfoot
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file Sasquatch.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_ENGINE_SASQUATCH_SASQUATCH_HPP
|
|
||||||
#define BIGFOOT_ENGINE_SASQUATCH_SASQUATCH_HPP
|
|
||||||
#include <Engine/DataAccessor/DataAccessor.hpp>
|
|
||||||
|
|
||||||
#include <System/File/File.hpp>
|
|
||||||
#include <System/File/MemoryMappedFile.hpp>
|
|
||||||
#include <System/UUID/UUID.hpp>
|
|
||||||
|
|
||||||
#include <Utils/TargetMacros.h>
|
|
||||||
|
|
||||||
#include <EASTL/span.h>
|
|
||||||
#include <EASTL/vector.h>
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
struct SasquatchHeader
|
|
||||||
{
|
|
||||||
static constexpr std::uint32_t MAGIC = 0x53515443; // 'SQTC'
|
|
||||||
static constexpr std::uint32_t VERSION = 1;
|
|
||||||
|
|
||||||
std::uint32_t m_magic = MAGIC;
|
|
||||||
std::uint32_t m_version = VERSION;
|
|
||||||
std::uint64_t m_assetCount = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(std::is_trivially_copyable_v<SasquatchHeader>);
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
struct SasquatchEntry
|
|
||||||
{
|
|
||||||
std::array<std::byte, UUID::UUID_BYTE_SIZE> m_uuid {};
|
|
||||||
|
|
||||||
std::size_t m_assetOffset = 0;
|
|
||||||
std::size_t m_assetSize = 0;
|
|
||||||
|
|
||||||
std::size_t m_hardReferencesOffset = 0;
|
|
||||||
std::size_t m_hardReferencesSize = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(std::is_trivially_copyable_v<SasquatchEntry>);
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
#if defined(BIGFOOT_TOOLMODE) || defined(BIGFOOT_BUILD_TESTS) || defined(BIGFOOT_BUILD_BENCHMARKS)
|
|
||||||
class SasquatchWriter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* Writes the header
|
|
||||||
*
|
|
||||||
* \param p_file The file to write
|
|
||||||
* \param p_assetCount The number of assets that will be written
|
|
||||||
* \param p_totalFlatbufferBytes The sum of the sizes of every flatbuffer that will be written
|
|
||||||
* \param p_totalHardReferencesBytes The sum of the sizes of every asset hardreferences that will be written
|
|
||||||
*/
|
|
||||||
SasquatchWriter(const File& p_file,
|
|
||||||
const std::uint64_t p_assetCount,
|
|
||||||
const std::size_t p_totalFlatbufferBytes,
|
|
||||||
const std::size_t p_totalHardReferencesBytes);
|
|
||||||
|
|
||||||
SasquatchWriter(const SasquatchWriter& p_writer) = delete;
|
|
||||||
SasquatchWriter(SasquatchWriter&& p_writer) = delete;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor
|
|
||||||
* Writes the entries
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
~SasquatchWriter();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes an asset to the file.
|
|
||||||
*
|
|
||||||
* \param p_uuid The UUID of the asset
|
|
||||||
* \param p_flatbuffer The flatbuffer of the asset
|
|
||||||
*/
|
|
||||||
void WriteAsset(const UUID& p_uuid,
|
|
||||||
eastl::span<const std::byte> p_flatbuffer,
|
|
||||||
eastl::span<const UUID> p_hardReferences);
|
|
||||||
|
|
||||||
SasquatchWriter& operator=(const SasquatchWriter& p_writer) = delete;
|
|
||||||
SasquatchWriter& operator=(SasquatchWriter&& p_writer) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr std::uint64_t PREFETCH_BYTES = 4ULL * 1024 * 1024;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of assets expected
|
|
||||||
*/
|
|
||||||
std::uint64_t m_assetCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How far into m_file has already been prefetched
|
|
||||||
*/
|
|
||||||
std::size_t m_prefetchedUpTo = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Current write position in the data region
|
|
||||||
*/
|
|
||||||
std::size_t m_currentDataOffset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Sasquatch file being written, mapped at its final size
|
|
||||||
*/
|
|
||||||
WritableMemoryMappedFile m_file;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The entries
|
|
||||||
*/
|
|
||||||
eastl::vector<SasquatchEntry> m_entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
class Sasquatch: public DataAccessor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* \param p_file The sasquatch file
|
|
||||||
*/
|
|
||||||
Sasquatch(const File& p_file);
|
|
||||||
|
|
||||||
Sasquatch(const Sasquatch& p_sasquatch) = delete;
|
|
||||||
Sasquatch(Sasquatch&& p_sasquatch) = delete;
|
|
||||||
|
|
||||||
~Sasquatch() override = default;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the header
|
|
||||||
*
|
|
||||||
* \return The header
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
const SasquatchHeader& GetHeader() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an Asset flatbuffer
|
|
||||||
*
|
|
||||||
* \param p_uuid The asset to get the flatbuffer of
|
|
||||||
* \return The flatbuffer, or an empty vector if the asset was not found
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
eastl::vector<std::byte> GetAssetFlatbuffer(const UUID& p_uuid) const override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get several Asset flatbuffers
|
|
||||||
*
|
|
||||||
* \param p_uuids The assets to get the flatbuffers of
|
|
||||||
* \return The flatbuffers that were found
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
eastl::vector<eastl::vector<std::byte>> GetAssetFlatbuffers(eastl::span<const UUID> p_uuids) const override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the HardReferences of a given asset
|
|
||||||
*
|
|
||||||
* \param p_uuid The asset to get the HardReferences of
|
|
||||||
* \return The HardReferences of the asset
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
eastl::vector<UUID> GetAssetHardReferences(const UUID& p_uuid) const override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the HardReferences of given assets
|
|
||||||
*
|
|
||||||
* \param p_uuids The assets to get the HardReferences of
|
|
||||||
* \return The HardReferences of the assets
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
eastl::vector<eastl::vector<UUID>> GetAssetsHardReferences(eastl::span<const UUID> p_uuids) const override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sasquatch is read-only: this will always fail
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void SaveAssetFlatbuffer(const UUID& p_uuid,
|
|
||||||
eastl::span<const std::byte> p_flatbuffer,
|
|
||||||
eastl::span<const UUID> p_hardReferences) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sasquatch is read-only: this will always fail
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void SaveAssetFlatbuffers(const eastl::span<const UUID> p_uuids,
|
|
||||||
eastl::span<const eastl::vector<std::byte>> p_flatbuffers,
|
|
||||||
eastl::span<const eastl::vector<UUID>> p_hardReferences) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the Asset exists
|
|
||||||
*
|
|
||||||
* \param p_uuid The asset to check
|
|
||||||
* \param True if it exists, false otherwise
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
bool Has(const UUID& p_uuid) const override;
|
|
||||||
|
|
||||||
Sasquatch& operator=(const Sasquatch& p_sasquatch) = delete;
|
|
||||||
Sasquatch& operator=(Sasquatch&& p_sasquatch) = delete;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Entry
|
|
||||||
{
|
|
||||||
std::size_t m_assetOffset = 0;
|
|
||||||
std::size_t m_assetSize = 0;
|
|
||||||
|
|
||||||
std::size_t m_hardReferencesOffset = 0;
|
|
||||||
std::size_t m_hardReferencesSize = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Sasquatch file
|
|
||||||
*/
|
|
||||||
MemoryMappedFile m_file;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The sasquatch header
|
|
||||||
*/
|
|
||||||
SasquatchHeader m_header;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UUID to entry
|
|
||||||
*/
|
|
||||||
ankerl::unordered_dense::map<UUID, Entry> m_entries;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
} // namespace Bigfoot
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
@AUTO_GENERATED_COMMENT@
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
* \file SasquatchInfo.generated.hpp
|
|
||||||
*
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_@SASQUATCH_NAME@_SASQUATCHINFO_GENERATED_HPP
|
|
||||||
#define BIGFOOT_@SASQUATCH_NAME@_SASQUATCHINFO_GENERATED_HPP
|
|
||||||
|
|
||||||
#include <EASTL/string_view.h>
|
|
||||||
|
|
||||||
#if defined BIGFOOT_GAME
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Sasquatch location
|
|
||||||
*/
|
|
||||||
constexpr eastl::string_view SASQUATCH_@SASQUATCH_NAME@_LOCATION {"@SASQUATCH_LOCATION@"};
|
|
||||||
} // namespace Bigfoot
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file SerializationManager.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_ENGINE_SERIALIZATIONMANAGER_SERIALIZATIONMANAGER_HPP
|
|
||||||
#define BIGFOOT_ENGINE_SERIALIZATIONMANAGER_SERIALIZATIONMANAGER_HPP
|
|
||||||
#include <System/UUID/UUID.hpp>
|
|
||||||
|
|
||||||
#include <EASTL/span.h>
|
|
||||||
|
|
||||||
namespace Bigfoot::SerializationManager
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Load an Asset, along with every HardReference it transitively points to
|
|
||||||
* Already loaded assets are skipped. Assets that are part of a cyclic dependency are left unloaded
|
|
||||||
*
|
|
||||||
* \param p_uuid The asset to load
|
|
||||||
*/
|
|
||||||
void LoadAsset(const UUID& p_uuid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load several Assets, along with every HardReference they transitively point to
|
|
||||||
* Already loaded assets are skipped. Assets that are part of a cyclic dependency are left unloaded
|
|
||||||
*
|
|
||||||
* \param p_uuids The assets to load
|
|
||||||
*/
|
|
||||||
void LoadAssets(const eastl::span<const UUID> p_uuids);
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_TOOLMODE
|
|
||||||
/**
|
|
||||||
* Save an Asset
|
|
||||||
* Fails without saving if a cyclic dependency is detected starting from this asset
|
|
||||||
*
|
|
||||||
* \param p_uuid The asset to save
|
|
||||||
* \return True if the asset was saved, false otherwise
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
bool SaveAsset(const UUID& p_uuid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save several Assets
|
|
||||||
* Fails without saving any of them if a cyclic dependency is detected starting from any of them
|
|
||||||
*
|
|
||||||
* \param p_uuids The assets to save
|
|
||||||
* \return True if the assets were saved, false otherwise
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
bool SaveAssets(const eastl::span<const UUID> p_uuids);
|
|
||||||
#endif
|
|
||||||
} // namespace Bigfoot::SerializationManager
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file Sasquatch.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Engine/Sasquatch/Sasquatch.hpp>
|
|
||||||
|
|
||||||
#include <Engine/EngineAssertHandler.hpp>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
#if defined(BIGFOOT_TOOLMODE) || defined(BIGFOOT_BUILD_TESTS) || defined(BIGFOOT_BUILD_BENCHMARKS)
|
|
||||||
SasquatchWriter::SasquatchWriter(const File& p_file,
|
|
||||||
const std::uint64_t p_assetCount,
|
|
||||||
const std::size_t p_totalFlatbufferBytes,
|
|
||||||
const std::size_t p_totalHardReferencesBytes):
|
|
||||||
m_assetCount(p_assetCount),
|
|
||||||
m_currentDataOffset(sizeof(SasquatchHeader) + (m_assetCount * sizeof(SasquatchEntry))),
|
|
||||||
m_file(p_file,
|
|
||||||
sizeof(SasquatchHeader) + (m_assetCount * sizeof(SasquatchEntry)) + p_totalFlatbufferBytes +
|
|
||||||
p_totalHardReferencesBytes)
|
|
||||||
{
|
|
||||||
m_entries.reserve(m_assetCount);
|
|
||||||
|
|
||||||
SasquatchHeader header;
|
|
||||||
header.m_assetCount = m_assetCount;
|
|
||||||
|
|
||||||
std::memcpy(m_file.GetData().data(), &header, sizeof(SasquatchHeader));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
SasquatchWriter::~SasquatchWriter()
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
m_entries.size() == m_assetCount,
|
|
||||||
"SasquatchWriter expected {} assets, only {} were added",
|
|
||||||
m_assetCount,
|
|
||||||
m_entries.size());
|
|
||||||
|
|
||||||
m_file.Prefetch(sizeof(SasquatchHeader), m_entries.size() * sizeof(SasquatchEntry));
|
|
||||||
|
|
||||||
if (!m_entries.empty())
|
|
||||||
{
|
|
||||||
std::memcpy(m_file.GetData().data() + sizeof(SasquatchHeader),
|
|
||||||
m_entries.data(),
|
|
||||||
m_entries.size() * sizeof(SasquatchEntry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void SasquatchWriter::WriteAsset(const UUID& p_uuid,
|
|
||||||
eastl::span<const std::byte> p_flatbuffer,
|
|
||||||
eastl::span<const UUID> p_hardReferences)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
m_entries.size() < m_assetCount,
|
|
||||||
"SasquatchWriter can only hold {} assets",
|
|
||||||
m_assetCount);
|
|
||||||
|
|
||||||
const std::size_t offset = m_currentDataOffset;
|
|
||||||
|
|
||||||
const eastl::span<std::byte> data = m_file.GetData();
|
|
||||||
ASSERT(EngineAssertHandler,
|
|
||||||
offset + p_flatbuffer.size() + (p_hardReferences.size() * UUID::UUID_BYTE_SIZE) <= data.size(),
|
|
||||||
"SasquatchWriter can only write {} bytes",
|
|
||||||
data.size());
|
|
||||||
|
|
||||||
const std::size_t writeEnd = offset + p_flatbuffer.size() + (p_hardReferences.size() * UUID::UUID_BYTE_SIZE);
|
|
||||||
if (writeEnd > m_prefetchedUpTo)
|
|
||||||
{
|
|
||||||
const std::size_t prefetchEnd = std::min(writeEnd + PREFETCH_BYTES, data.size());
|
|
||||||
m_file.Prefetch(m_prefetchedUpTo, prefetchEnd - m_prefetchedUpTo);
|
|
||||||
m_prefetchedUpTo = prefetchEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
SasquatchEntry entry;
|
|
||||||
std::memcpy(entry.m_uuid.data(), p_uuid.ToBytes().data(), UUID::UUID_BYTE_SIZE);
|
|
||||||
entry.m_assetOffset = offset;
|
|
||||||
entry.m_assetSize = p_flatbuffer.size();
|
|
||||||
entry.m_hardReferencesOffset = entry.m_assetOffset + entry.m_assetSize;
|
|
||||||
entry.m_hardReferencesSize = p_hardReferences.size() * UUID::UUID_BYTE_SIZE;
|
|
||||||
|
|
||||||
std::memcpy(data.data() + entry.m_assetOffset, p_flatbuffer.data(), entry.m_assetSize);
|
|
||||||
|
|
||||||
for (std::uint32_t i = 0; i < p_hardReferences.size(); ++i)
|
|
||||||
{
|
|
||||||
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawUUID = p_hardReferences[i].ToBytes();
|
|
||||||
std::memcpy(data.data() + entry.m_hardReferencesOffset + (static_cast<std::size_t>(i) * UUID::UUID_BYTE_SIZE),
|
|
||||||
rawUUID.data(),
|
|
||||||
UUID::UUID_BYTE_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_currentDataOffset += entry.m_assetSize + entry.m_hardReferencesSize;
|
|
||||||
m_entries.push_back(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
Sasquatch::Sasquatch(const File& p_file):
|
|
||||||
m_file(p_file)
|
|
||||||
{
|
|
||||||
const eastl::span<const std::byte> data = m_file.GetData();
|
|
||||||
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler,
|
|
||||||
data.size() >= sizeof(SasquatchHeader),
|
|
||||||
"Sasquatch file {} is smaller than its header",
|
|
||||||
p_file.GetPath());
|
|
||||||
|
|
||||||
std::memcpy(&m_header, data.data(), sizeof(SasquatchHeader));
|
|
||||||
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler,
|
|
||||||
m_header.m_magic == SasquatchHeader::MAGIC,
|
|
||||||
"Sasquatch file {} has an invalid magic number (got {} / expected {})",
|
|
||||||
p_file.GetPath(),
|
|
||||||
m_header.m_magic,
|
|
||||||
SasquatchHeader::MAGIC);
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler,
|
|
||||||
m_header.m_version == SasquatchHeader::VERSION,
|
|
||||||
"Sasquatch file {} has an unsupported version (got {} / expected {})",
|
|
||||||
p_file.GetPath(),
|
|
||||||
m_header.m_version,
|
|
||||||
SasquatchHeader::VERSION);
|
|
||||||
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler,
|
|
||||||
data.size() >= sizeof(SasquatchHeader) + (m_header.m_assetCount * sizeof(SasquatchEntry)),
|
|
||||||
"Sasquatch file {} index is truncated (got {} / expected at least {})",
|
|
||||||
p_file.GetPath(),
|
|
||||||
data.size(),
|
|
||||||
sizeof(SasquatchHeader) + (m_header.m_assetCount * sizeof(SasquatchEntry)));
|
|
||||||
|
|
||||||
eastl::vector<SasquatchEntry> entries(m_header.m_assetCount);
|
|
||||||
if (!entries.empty())
|
|
||||||
{
|
|
||||||
std::memcpy(entries.data(), data.data() + sizeof(SasquatchHeader), entries.size() * sizeof(SasquatchEntry));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_entries.reserve(m_header.m_assetCount);
|
|
||||||
for (const SasquatchEntry& entry: entries)
|
|
||||||
{
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler,
|
|
||||||
entry.m_assetOffset + entry.m_assetSize + entry.m_hardReferencesSize <= data.size(),
|
|
||||||
"Sasquatch file {} has an out-of-bounds asset entry",
|
|
||||||
p_file.GetPath());
|
|
||||||
|
|
||||||
m_entries.emplace(UUID {entry.m_uuid},
|
|
||||||
Entry {.m_assetOffset = entry.m_assetOffset,
|
|
||||||
.m_assetSize = entry.m_assetSize,
|
|
||||||
.m_hardReferencesOffset = entry.m_hardReferencesOffset,
|
|
||||||
.m_hardReferencesSize = entry.m_hardReferencesSize});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
const SasquatchHeader& Sasquatch::GetHeader() const
|
|
||||||
{
|
|
||||||
return m_header;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
eastl::vector<std::byte> Sasquatch::GetAssetFlatbuffer(const UUID& p_uuid) const
|
|
||||||
{
|
|
||||||
const auto entryIt = m_entries.find(p_uuid);
|
|
||||||
if (entryIt == m_entries.end())
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::span<const std::byte> data = m_file.GetData();
|
|
||||||
const eastl::span<const std::byte> bytes {data.data() + entryIt->second.m_assetOffset,
|
|
||||||
static_cast<std::size_t>(entryIt->second.m_assetSize)};
|
|
||||||
return eastl::vector<std::byte> {bytes.begin(), bytes.end()};
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
eastl::vector<eastl::vector<std::byte>> Sasquatch::GetAssetFlatbuffers(const eastl::span<const UUID> p_uuids) const
|
|
||||||
{
|
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
|
||||||
flatbuffers.reserve(p_uuids.size());
|
|
||||||
|
|
||||||
for (const UUID& uuid: p_uuids)
|
|
||||||
{
|
|
||||||
flatbuffers.push_back(GetAssetFlatbuffer(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
return flatbuffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
eastl::vector<UUID> Sasquatch::GetAssetHardReferences(const UUID& p_uuid) const
|
|
||||||
{
|
|
||||||
eastl::vector<UUID> hardReferences;
|
|
||||||
|
|
||||||
const auto entryIt = m_entries.find(p_uuid);
|
|
||||||
if (entryIt == m_entries.end())
|
|
||||||
{
|
|
||||||
return hardReferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::span<const std::byte> data = m_file.GetData();
|
|
||||||
const eastl::span<const std::byte> bytes {data.data() + entryIt->second.m_hardReferencesOffset,
|
|
||||||
static_cast<std::size_t>(entryIt->second.m_hardReferencesSize)};
|
|
||||||
|
|
||||||
const std::size_t hardReferenceCount = bytes.size() / UUID::UUID_BYTE_SIZE;
|
|
||||||
hardReferences.reserve(hardReferenceCount);
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < hardReferenceCount; ++i)
|
|
||||||
{
|
|
||||||
std::array<std::byte, UUID::UUID_BYTE_SIZE> rawUUID;
|
|
||||||
std::memcpy(rawUUID.data(), bytes.data() + (i * UUID::UUID_BYTE_SIZE), UUID::UUID_BYTE_SIZE);
|
|
||||||
hardReferences.emplace_back(rawUUID);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hardReferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
eastl::vector<eastl::vector<UUID>> Sasquatch::GetAssetsHardReferences(eastl::span<const UUID> p_uuids) const
|
|
||||||
{
|
|
||||||
eastl::vector<eastl::vector<UUID>> hardReferences;
|
|
||||||
hardReferences.reserve(p_uuids.size());
|
|
||||||
|
|
||||||
for (const UUID& uuid: p_uuids)
|
|
||||||
{
|
|
||||||
hardReferences.push_back(GetAssetHardReferences(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
return hardReferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void Sasquatch::SaveAssetFlatbuffer([[maybe_unused]] const UUID& p_uuid,
|
|
||||||
[[maybe_unused]] eastl::span<const std::byte> p_flatbuffer,
|
|
||||||
[[maybe_unused]] eastl::span<const UUID> p_hardReferences)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler, false, "Sasquatch is read-only, it cannot save assets");
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void Sasquatch::SaveAssetFlatbuffers([[maybe_unused]] const eastl::span<const UUID> p_uuids,
|
|
||||||
[[maybe_unused]] eastl::span<const eastl::vector<std::byte>> p_flatbuffers,
|
|
||||||
[[maybe_unused]] eastl::span<const eastl::vector<UUID>> p_hardReferences)
|
|
||||||
{
|
|
||||||
ASSERT(EngineAssertHandler, false, "Sasquatch is read-only, it cannot save assets");
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
bool Sasquatch::Has(const UUID& p_uuid) const
|
|
||||||
{
|
|
||||||
return m_entries.contains(p_uuid);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} // namespace Bigfoot
|
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file SerializationManager.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <Engine/SerializationManager/SerializationManager.hpp>
|
|
||||||
|
|
||||||
#include <Engine/Asset/AssetLibrary.hpp>
|
|
||||||
#include <Engine/DataAccessor/DataAccessor.hpp>
|
|
||||||
|
|
||||||
#include <Utils/Algorithm/Graph.hpp>
|
|
||||||
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
|
|
||||||
namespace Bigfoot::SerializationManager
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Build the transitive HardReference graph reachable from p_roots
|
|
||||||
*
|
|
||||||
* \param p_roots The assets to start the discovery from
|
|
||||||
* \param p_discovered Every discovered asset that isn't already loaded, including p_roots
|
|
||||||
* \return Every asset's HardReferences
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
ankerl::unordered_dense::map<UUID, eastl::vector<UUID>> BuildDependencyGraph(
|
|
||||||
const eastl::span<const UUID> p_roots,
|
|
||||||
ankerl::unordered_dense::set<UUID>& p_discovered)
|
|
||||||
{
|
|
||||||
ankerl::unordered_dense::map<UUID, eastl::vector<UUID>> graph;
|
|
||||||
|
|
||||||
eastl::vector<UUID> toQuery;
|
|
||||||
toQuery.reserve(p_roots.size());
|
|
||||||
for (const UUID& uuid: p_roots)
|
|
||||||
{
|
|
||||||
if (!g_activeAssetLibrary->IsLoaded(uuid) && p_discovered.insert(uuid).second)
|
|
||||||
{
|
|
||||||
toQuery.push_back(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!toQuery.empty())
|
|
||||||
{
|
|
||||||
eastl::vector<eastl::vector<UUID>> hardReferencesBatch = g_dataAccessor->GetAssetsHardReferences(toQuery);
|
|
||||||
|
|
||||||
eastl::vector<UUID> nextToQuery;
|
|
||||||
for (std::size_t i = 0; i < toQuery.size(); ++i)
|
|
||||||
{
|
|
||||||
eastl::vector<UUID>& hardReferences = graph[toQuery[i]];
|
|
||||||
hardReferences = std::move(hardReferencesBatch[i]);
|
|
||||||
|
|
||||||
for (const UUID& hardReference: hardReferences)
|
|
||||||
{
|
|
||||||
if (!g_activeAssetLibrary->IsLoaded(hardReference) && p_discovered.insert(hardReference).second)
|
|
||||||
{
|
|
||||||
nextToQuery.push_back(hardReference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toQuery = std::move(nextToQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
return graph;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void LoadAssets(const eastl::span<const UUID> p_uuids)
|
|
||||||
{
|
|
||||||
ankerl::unordered_dense::set<UUID> discovered;
|
|
||||||
const ankerl::unordered_dense::map<UUID, eastl::vector<UUID>> graph = BuildDependencyGraph(p_uuids, discovered);
|
|
||||||
|
|
||||||
// Assets that are part of a cyclic HardReference dependency are left out of waves and simply never loaded.
|
|
||||||
eastl::vector<eastl::vector<UUID>> waves;
|
|
||||||
eastl::vector<UUID> cyclicUuids;
|
|
||||||
std::ignore = LayeredTopologicalSort(graph, discovered, waves, cyclicUuids);
|
|
||||||
BIGFOOT_LOG_ERROR_IF(!cyclicUuids.empty(),
|
|
||||||
ENGINE_LOGGER,
|
|
||||||
"Cyclic HardReference dependency detected while loading assets, involved UUIDs: {}",
|
|
||||||
cyclicUuids);
|
|
||||||
|
|
||||||
// Waves are loaded one after another since a wave's assets may HardReference the previous wave's; within a
|
|
||||||
// wave, every asset is independent of the others, so this is where loading could later be parallelized.
|
|
||||||
for (const eastl::vector<UUID>& wave: waves)
|
|
||||||
{
|
|
||||||
const eastl::vector<eastl::vector<std::byte>> assetFlatbuffers = g_dataAccessor->GetAssetFlatbuffers(wave);
|
|
||||||
for (std::size_t i = 0; i < wave.size(); ++i)
|
|
||||||
{
|
|
||||||
const eastl::vector<std::byte>& flatbuffer = assetFlatbuffers[i];
|
|
||||||
if (flatbuffer.empty())
|
|
||||||
{
|
|
||||||
BIGFOOT_LOG_ERROR(ENGINE_LOGGER, "Asset {} could not be found while loading, skipping it", wave[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_NOT_OPTIMIZED
|
|
||||||
flatbuffers::Verifier verifier {reinterpret_cast<const std::uint8_t*>(flatbuffer.data()),
|
|
||||||
flatbuffer.size()};
|
|
||||||
const bool assetVerified = ::Flat::Bigfoot::VerifyAssetBuffer(verifier);
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler, assetVerified, "Given asset could not be verified!");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const ::Flat::Bigfoot::Asset* asset = flatbuffers::GetRoot<::Flat::Bigfoot::Asset>(flatbuffer.data());
|
|
||||||
|
|
||||||
AssetContainerBase* container = g_activeAssetLibrary->GetAssetContainer(
|
|
||||||
flatbuffers::UnPack(*asset->header()->type_id()));
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler,
|
|
||||||
container != nullptr,
|
|
||||||
"No AssetContainer registered for asset {}",
|
|
||||||
wave[i]);
|
|
||||||
std::ignore = container->Insert(flatbuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
void LoadAsset(const UUID& p_uuid)
|
|
||||||
{
|
|
||||||
LoadAssets(eastl::span<const UUID> {&p_uuid, 1});
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_TOOLMODE
|
|
||||||
/*
|
|
||||||
* Finds the cyclic dependencies that may exist in Assets
|
|
||||||
*
|
|
||||||
* \param p_uuids The assets we want to explore
|
|
||||||
* \param p_hardReferences The HardReferences of p_uuids, matching by index
|
|
||||||
* \return Every UUID caught in a cyclic dependency
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
eastl::vector<UUID> FindCyclicDependencies(const eastl::span<const UUID> p_uuids,
|
|
||||||
const eastl::span<const eastl::vector<UUID>> p_hardReferences)
|
|
||||||
{
|
|
||||||
ankerl::unordered_dense::map<UUID, eastl::vector<UUID>> graph;
|
|
||||||
ankerl::unordered_dense::set<UUID> discovered;
|
|
||||||
|
|
||||||
eastl::vector<UUID> toQuery;
|
|
||||||
for (std::size_t i = 0; i < p_uuids.size(); ++i)
|
|
||||||
{
|
|
||||||
discovered.insert(p_uuids[i]);
|
|
||||||
graph[p_uuids[i]] = p_hardReferences[i];
|
|
||||||
}
|
|
||||||
for (const eastl::vector<UUID>& hardReferences: p_hardReferences)
|
|
||||||
{
|
|
||||||
for (const UUID& hardReference: hardReferences)
|
|
||||||
{
|
|
||||||
if (discovered.insert(hardReference).second)
|
|
||||||
{
|
|
||||||
toQuery.push_back(hardReference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!toQuery.empty())
|
|
||||||
{
|
|
||||||
eastl::vector<eastl::vector<UUID>> hardReferencesBatch = g_dataAccessor->GetAssetsHardReferences(toQuery);
|
|
||||||
|
|
||||||
eastl::vector<UUID> nextToQuery;
|
|
||||||
for (std::size_t i = 0; i < toQuery.size(); ++i)
|
|
||||||
{
|
|
||||||
eastl::vector<UUID>& hardReferences = graph[toQuery[i]];
|
|
||||||
hardReferences = std::move(hardReferencesBatch[i]);
|
|
||||||
|
|
||||||
for (const UUID& hardReference: hardReferences)
|
|
||||||
{
|
|
||||||
if (discovered.insert(hardReference).second)
|
|
||||||
{
|
|
||||||
nextToQuery.push_back(hardReference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toQuery = std::move(nextToQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
eastl::vector<eastl::vector<UUID>> waves;
|
|
||||||
eastl::vector<UUID> cyclicUuids;
|
|
||||||
std::ignore = LayeredTopologicalSort(graph, discovered, waves, cyclicUuids);
|
|
||||||
return cyclicUuids;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
bool SaveAsset(const UUID& p_uuid)
|
|
||||||
{
|
|
||||||
AssetContainerBase* container = g_activeAssetLibrary->GetAssetContainer(p_uuid);
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler, container != nullptr, "No AssetContainer registered for asset {}", p_uuid);
|
|
||||||
const AssetBase* asset = container->AcquireContainerHandle(p_uuid)->GetAsset();
|
|
||||||
|
|
||||||
const eastl::vector<std::byte> flatbuffer = asset->Pack();
|
|
||||||
const eastl::vector<UUID> hardReferences = asset->GetHardReferences(flatbuffer);
|
|
||||||
|
|
||||||
const eastl::vector<UUID> cyclicUuids = FindCyclicDependencies(
|
|
||||||
eastl::span<const UUID> {&p_uuid, 1},
|
|
||||||
eastl::span<const eastl::vector<UUID>> {&hardReferences, 1});
|
|
||||||
BIGFOOT_LOG_ERROR_IF(!cyclicUuids.empty(),
|
|
||||||
ENGINE_LOGGER,
|
|
||||||
"Cyclic HardReference dependency detected while saving asset {}, involved UUIDs: {}",
|
|
||||||
p_uuid,
|
|
||||||
cyclicUuids);
|
|
||||||
if (!cyclicUuids.empty())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_dataAccessor->SaveAssetFlatbuffer(p_uuid, flatbuffer, hardReferences);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
bool SaveAssets(const eastl::span<const UUID> p_uuids)
|
|
||||||
{
|
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
|
||||||
eastl::vector<eastl::vector<UUID>> hardReferences;
|
|
||||||
|
|
||||||
flatbuffers.reserve(p_uuids.size());
|
|
||||||
hardReferences.reserve(p_uuids.size());
|
|
||||||
for (const UUID& uuid: p_uuids)
|
|
||||||
{
|
|
||||||
AssetContainerBase* container = g_activeAssetLibrary->GetAssetContainer(uuid);
|
|
||||||
CRITICAL_ASSERT(EngineAssertHandler, container != nullptr, "No AssetContainer registered for asset {}", uuid);
|
|
||||||
const AssetBase* asset = container->AcquireContainerHandle(uuid)->GetAsset();
|
|
||||||
|
|
||||||
const eastl::vector<std::byte> flatbuffer = asset->Pack();
|
|
||||||
|
|
||||||
flatbuffers.push_back(flatbuffer);
|
|
||||||
hardReferences.push_back(asset->GetHardReferences(flatbuffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
const eastl::vector<UUID> cyclicUuids = FindCyclicDependencies(p_uuids, hardReferences);
|
|
||||||
BIGFOOT_LOG_ERROR_IF(!cyclicUuids.empty(),
|
|
||||||
ENGINE_LOGGER,
|
|
||||||
"Cyclic HardReference dependency detected while saving assets, involved UUIDs: {}",
|
|
||||||
cyclicUuids);
|
|
||||||
if (!cyclicUuids.empty())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_dataAccessor->SaveAssetFlatbuffers(p_uuids, flatbuffers, hardReferences);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} // namespace Bigfoot::SerializationManager
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/GraphicsInterface)
|
|
||||||
if(${VULKAN})
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/GraphicsVulkan)
|
|
||||||
endif()
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/GraphicsCore)
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|
||||||
project(${PackageName})
|
|
||||||
|
|
||||||
set(PublicDependencies)
|
|
||||||
set(PrivateDependencies)
|
|
||||||
set(BigfootPublicDependencies
|
|
||||||
GraphicsVulkan
|
|
||||||
Engine)
|
|
||||||
set(BigfootPrivateDependencies)
|
|
||||||
|
|
||||||
bigfoot_create_package_lib(
|
|
||||||
"${PublicDependencies}"
|
|
||||||
"${PrivateDependencies}"
|
|
||||||
"${BigfootPublicDependencies}"
|
|
||||||
"${BigfootPrivateDependencies}"
|
|
||||||
"Bigfoot/Libs/Graphics")
|
|
||||||
|
|
||||||
bigfoot_create_logger()
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
#include <GraphicsCore/GraphicsCoreAssertHandler.hpp>
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file GraphicsCoreAssertHandler.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSCORE_GRAPHICSCOREASSERTHANDLER_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSCORE_GRAPHICSCOREASSERTHANDLER_HPP
|
|
||||||
#include <Utils/Assert/AssertHandler.hpp>
|
|
||||||
|
|
||||||
#include <GraphicsCore/GraphicsCoreLogger_generated.hpp>
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_NOT_OPTIMIZED
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
using GraphicsCoreAssertHandler = AssertHandler<GRAPHICSCORE_LOGGER>;
|
|
||||||
} // namespace Bigfoot
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
-21
@@ -1,21 +0,0 @@
|
|||||||
// AUTO-GENERATED DO NOT TOUCH
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
* \file GraphicsCoreLogger.generated.hpp
|
|
||||||
*
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSCORELOGGER_GENERATED_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSCORELOGGER_GENERATED_HPP
|
|
||||||
#include <Utils/Log/LogMacros.hpp>
|
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Logger
|
|
||||||
*/
|
|
||||||
inline Log::LoggerInfo GRAPHICSCORE_LOGGER { .m_name = "GRAPHICSCORE_LOGGER", .m_level = LogLevel::Trace};
|
|
||||||
} // namespace Bigfoot
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|
||||||
project(${PackageName})
|
|
||||||
|
|
||||||
set(PublicDependencies
|
|
||||||
glm::glm)
|
|
||||||
set(PrivateDependencies)
|
|
||||||
set(BigfootPublicDependencies
|
|
||||||
Utils)
|
|
||||||
set(BigfootPrivateDependencies)
|
|
||||||
|
|
||||||
bigfoot_create_package_lib(
|
|
||||||
"${PublicDependencies}"
|
|
||||||
"${PrivateDependencies}"
|
|
||||||
"${BigfootPublicDependencies}"
|
|
||||||
"${BigfootPrivateDependencies}"
|
|
||||||
"Bigfoot/Libs/Graphics")
|
|
||||||
|
|
||||||
bigfoot_create_logger()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
#include <GraphicsInterface/GraphicsInterfaceAssertHandler.hpp>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Bigfoot;
|
|
||||||
|
|
||||||
enum GraphicsAPI: byte
|
|
||||||
{
|
|
||||||
Vulkan
|
|
||||||
}
|
|
||||||
-71
@@ -1,71 +0,0 @@
|
|||||||
// automatically generated by the FlatBuffers compiler, do not modify
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef FLATBUFFERS_GENERATED_GRAPHICSAPI_BIGFOOT_H_
|
|
||||||
#define FLATBUFFERS_GENERATED_GRAPHICSAPI_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 GraphicsAPI : int8_t {
|
|
||||||
Vulkan = 0,
|
|
||||||
MIN = Vulkan,
|
|
||||||
MAX = Vulkan
|
|
||||||
};
|
|
||||||
|
|
||||||
inline const GraphicsAPI (&EnumValuesGraphicsAPI())[1] {
|
|
||||||
static const GraphicsAPI values[] = {
|
|
||||||
GraphicsAPI::Vulkan
|
|
||||||
};
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char * const *EnumNamesGraphicsAPI() {
|
|
||||||
static const char * const names[2] = {
|
|
||||||
"Vulkan",
|
|
||||||
nullptr
|
|
||||||
};
|
|
||||||
return names;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char *EnumNameGraphicsAPI(GraphicsAPI e) {
|
|
||||||
if (::flatbuffers::IsOutRange(e, GraphicsAPI::Vulkan, GraphicsAPI::Vulkan)) return "";
|
|
||||||
const size_t index = static_cast<size_t>(e);
|
|
||||||
return EnumNamesGraphicsAPI()[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const ::flatbuffers::TypeTable *GraphicsAPITypeTable() {
|
|
||||||
static const ::flatbuffers::TypeCode type_codes[] = {
|
|
||||||
{ ::flatbuffers::ET_CHAR, 0, 0 }
|
|
||||||
};
|
|
||||||
static const ::flatbuffers::TypeFunction type_refs[] = {
|
|
||||||
Bigfoot::GraphicsAPITypeTable
|
|
||||||
};
|
|
||||||
static const ::flatbuffers::TypeTable tt = {
|
|
||||||
::flatbuffers::ST_ENUM, 1, type_codes, type_refs, nullptr, nullptr, nullptr
|
|
||||||
};
|
|
||||||
return &tt;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Bigfoot
|
|
||||||
|
|
||||||
#endif // FLATBUFFERS_GENERATED_GRAPHICSAPI_BIGFOOT_H_
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
-48
@@ -1,48 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file GraphicsInstance.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINSTANCE_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINSTANCE_HPP
|
|
||||||
#include <Utils/Factory.hpp>
|
|
||||||
#include <Utils/LazyGlobal.hpp>
|
|
||||||
#include <Utils/Version.hpp>
|
|
||||||
|
|
||||||
#include <GraphicsInterface/GraphicsAPI_generated.hpp>
|
|
||||||
|
|
||||||
#include <EASTL/functional.h>
|
|
||||||
#include <EASTL/string_view.h>
|
|
||||||
#include <EASTL/unique_ptr.h>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
class GraphicsInstance
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~GraphicsInstance() = default;
|
|
||||||
|
|
||||||
GraphicsInstance(const GraphicsInstance& p_instance) = delete;
|
|
||||||
GraphicsInstance(GraphicsInstance&& p_instance) = delete;
|
|
||||||
|
|
||||||
GraphicsInstance& operator=(const GraphicsInstance& p_instance) = delete;
|
|
||||||
GraphicsInstance& operator=(GraphicsInstance&& p_instance) = delete;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
GraphicsInstance() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
using GraphicsInstanceFactory =
|
|
||||||
Factory<GraphicsInstance,
|
|
||||||
GraphicsAPI,
|
|
||||||
eastl::function<eastl::unique_ptr<GraphicsInstance>(eastl::string_view, Version)>>;
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
inline LazyGlobal<GraphicsInstanceFactory> g_graphicsInstanceFactory;
|
|
||||||
} // namespace Bigfoot
|
|
||||||
|
|
||||||
#endif
|
|
||||||
-20
@@ -1,20 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file GraphicsInterfaceAssertHandler.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINTERFACEASSERTHANDLER_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINTERFACEASSERTHANDLER_HPP
|
|
||||||
#include <Utils/Assert/AssertHandler.hpp>
|
|
||||||
|
|
||||||
#include <GraphicsInterface/GraphicsInterfaceLogger_generated.hpp>
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_NOT_OPTIMIZED
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
using GraphicsInterfaceAssertHandler = AssertHandler<GRAPHICSINTERFACE_LOGGER>;
|
|
||||||
} // namespace Bigfoot
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
-21
@@ -1,21 +0,0 @@
|
|||||||
// AUTO-GENERATED DO NOT TOUCH
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
* \file GraphicsInterfaceLogger.generated.hpp
|
|
||||||
*
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSINTERFACELOGGER_GENERATED_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSINTERFACELOGGER_GENERATED_HPP
|
|
||||||
#include <Utils/Log/LogMacros.hpp>
|
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Logger
|
|
||||||
*/
|
|
||||||
inline Log::LoggerInfo GRAPHICSINTERFACE_LOGGER { .m_name = "GRAPHICSINTERFACE_LOGGER", .m_level = LogLevel::Trace};
|
|
||||||
} // namespace Bigfoot
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file GraphicsQueue.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSQUEUE_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSQUEUE_HPP
|
|
||||||
#include <GraphicsInterface/GraphicsQueueType_generated.hpp>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
class GraphicsQueue
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~GraphicsQueue() = default;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the kind of work this queue can be submitted
|
|
||||||
*
|
|
||||||
* \return The queue type
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
virtual GraphicsQueueType GetType() const = 0;
|
|
||||||
|
|
||||||
GraphicsQueue(const GraphicsQueue& p_queue) = delete;
|
|
||||||
GraphicsQueue(GraphicsQueue&& p_queue) = delete;
|
|
||||||
|
|
||||||
GraphicsQueue& operator=(const GraphicsQueue& p_queue) = delete;
|
|
||||||
GraphicsQueue& operator=(GraphicsQueue&& p_queue) = delete;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
GraphicsQueue() = default;
|
|
||||||
};
|
|
||||||
} // namespace Bigfoot
|
|
||||||
|
|
||||||
#endif
|
|
||||||
-9
@@ -1,9 +0,0 @@
|
|||||||
namespace Bigfoot;
|
|
||||||
|
|
||||||
enum GraphicsQueueType: byte
|
|
||||||
{
|
|
||||||
Graphics,
|
|
||||||
Compute,
|
|
||||||
Transfer,
|
|
||||||
Present
|
|
||||||
}
|
|
||||||
-83
@@ -1,83 +0,0 @@
|
|||||||
// 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_
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file GraphicsSurface.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSSURFACE_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSSURFACE_HPP
|
|
||||||
#include <GraphicsInterface/GraphicsInstance.hpp>
|
|
||||||
|
|
||||||
#include <Utils/Factory.hpp>
|
|
||||||
#include <Utils/LazyGlobal.hpp>
|
|
||||||
#include <Utils/TargetMacros.h>
|
|
||||||
|
|
||||||
#include <GraphicsInterface/GraphicsAPI_generated.hpp>
|
|
||||||
|
|
||||||
#include <EASTL/functional.h>
|
|
||||||
#include <EASTL/unique_ptr.h>
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_WINDOWS
|
|
||||||
#include <Windows.h>
|
|
||||||
#elif defined BIGFOOT_LINUX
|
|
||||||
struct wl_display;
|
|
||||||
struct wl_surface;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The native window handles needed to create a GraphicsSurface
|
|
||||||
*/
|
|
||||||
struct SurfaceCreateInfo
|
|
||||||
{
|
|
||||||
#ifdef BIGFOOT_WINDOWS
|
|
||||||
HWND m_windowHandle = nullptr;
|
|
||||||
HINSTANCE m_windowInstance = nullptr;
|
|
||||||
#elif defined BIGFOOT_LINUX
|
|
||||||
wl_display* m_display = nullptr;
|
|
||||||
wl_surface* m_surface = nullptr;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class GraphicsSurface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~GraphicsSurface() = default;
|
|
||||||
|
|
||||||
GraphicsSurface(const GraphicsSurface& p_surface) = delete;
|
|
||||||
GraphicsSurface(GraphicsSurface&& p_surface) = delete;
|
|
||||||
|
|
||||||
GraphicsSurface& operator=(const GraphicsSurface& p_surface) = delete;
|
|
||||||
GraphicsSurface& operator=(GraphicsSurface&& p_surface) = delete;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
GraphicsSurface() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
using GraphicsSurfaceFactory =
|
|
||||||
Factory<GraphicsSurface,
|
|
||||||
GraphicsAPI,
|
|
||||||
eastl::function<eastl::unique_ptr<GraphicsSurface>(const GraphicsInstance&, const SurfaceCreateInfo&)>>;
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
inline LazyGlobal<GraphicsSurfaceFactory> g_graphicsSurfaceFactory;
|
|
||||||
} // namespace Bigfoot
|
|
||||||
|
|
||||||
#endif
|
|
||||||
-89
@@ -1,89 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace Bigfoot;
|
|
||||||
|
|
||||||
enum PixelFormat: byte
|
|
||||||
{
|
|
||||||
Undefined,
|
|
||||||
R8G8B8A8Unorm,
|
|
||||||
R8G8B8A8Srgb,
|
|
||||||
B8G8R8A8Unorm,
|
|
||||||
B8G8R8A8Srgb,
|
|
||||||
A2B10G10R10UnormPack32,
|
|
||||||
R16G16B16A16Sfloat
|
|
||||||
}
|
|
||||||
-95
@@ -1,95 +0,0 @@
|
|||||||
// 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_
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|
||||||
project(${PackageName})
|
|
||||||
|
|
||||||
set(PublicDependencies
|
|
||||||
vulkan-headers::vulkan-headers
|
|
||||||
GPUOpen::VulkanMemoryAllocator)
|
|
||||||
set(PrivateDependencies)
|
|
||||||
set(BigfootPublicDependencies
|
|
||||||
GraphicsInterface)
|
|
||||||
set(BigfootPrivateDependencies
|
|
||||||
Engine)
|
|
||||||
|
|
||||||
bigfoot_create_package_lib(
|
|
||||||
"${PublicDependencies}"
|
|
||||||
"${PrivateDependencies}"
|
|
||||||
"${BigfootPublicDependencies}"
|
|
||||||
"${BigfootPrivateDependencies}"
|
|
||||||
"Bigfoot/Libs/Graphics")
|
|
||||||
|
|
||||||
bigfoot_create_logger()
|
|
||||||
|
|
||||||
target_compile_definitions(${PackageName}
|
|
||||||
PRIVATE VULKAN_HPP_NO_EXCEPTIONS
|
|
||||||
PRIVATE VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1
|
|
||||||
PRIVATE $<$<PLATFORM_ID:Windows>:VK_USE_PLATFORM_WIN32_KHR>
|
|
||||||
PRIVATE $<$<PLATFORM_ID:Linux>:VK_USE_PLATFORM_WAYLAND_KHR>
|
|
||||||
PUBLIC BIGFOOT_VULKAN)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
#include <GraphicsVulkan/GraphicsVulkanAssertHandler.hpp>
|
|
||||||
-20
@@ -1,20 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file GraphicsVulkanAssertHandler.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSVULKAN_GRAPHICSVULKANASSERTHANDLER_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSVULKAN_GRAPHICSVULKANASSERTHANDLER_HPP
|
|
||||||
#include <Utils/Assert/AssertHandler.hpp>
|
|
||||||
|
|
||||||
#include <GraphicsVulkan/GraphicsVulkanLogger_generated.hpp>
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_NOT_OPTIMIZED
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
using GraphicsVulkanAssertHandler = AssertHandler<GRAPHICSVULKAN_LOGGER>;
|
|
||||||
} // namespace Bigfoot
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
-21
@@ -1,21 +0,0 @@
|
|||||||
// AUTO-GENERATED DO NOT TOUCH
|
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
* \file GraphicsVulkanLogger.generated.hpp
|
|
||||||
*
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSVULKANLOGGER_GENERATED_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSVULKANLOGGER_GENERATED_HPP
|
|
||||||
#include <Utils/Log/LogMacros.hpp>
|
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Logger
|
|
||||||
*/
|
|
||||||
inline Log::LoggerInfo GRAPHICSVULKAN_LOGGER { .m_name = "GRAPHICSVULKAN_LOGGER", .m_level = LogLevel::Trace};
|
|
||||||
} // namespace Bigfoot
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file VulkanFormatters.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANFORMATTERS_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSVULKAN_VULKANFORMATTERS_HPP
|
|
||||||
#include <GraphicsVulkan/VulkanInclude.hpp>
|
|
||||||
|
|
||||||
#include <Utils/TargetMacros.h>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct fmt::formatter<vk::Result>
|
|
||||||
{
|
|
||||||
static constexpr auto parse(format_parse_context& ctx)
|
|
||||||
{
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
static auto format(const vk::Result p_result, format_context& ctx)
|
|
||||||
{
|
|
||||||
return fmt::format_to(ctx.out(), "{}", vk::to_string(p_result));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_NOT_OPTIMIZED
|
|
||||||
#include <quill/DeferredFormatCodec.h>
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct fmtquill::formatter<vk::Result>
|
|
||||||
{
|
|
||||||
static constexpr auto parse(format_parse_context& ctx)
|
|
||||||
{
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
static auto format(const vk::Result p_result, format_context& ctx)
|
|
||||||
{
|
|
||||||
return fmtquill::format_to(ctx.out(), "{}", vk::to_string(p_result));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct quill::Codec<vk::Result>: quill::DeferredFormatCodec<vk::Result>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file VulkanInclude.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANINCLUDE_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSVULKAN_VULKANINCLUDE_HPP
|
|
||||||
#define VULKAN_HPP_ASSERT(result)
|
|
||||||
#define VULKAN_HPP_ASSERT_ON_RESULT(result)
|
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file VulkanInstance.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANINSTANCE_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSVULKAN_VULKANINSTANCE_HPP
|
|
||||||
#include <GraphicsVulkan/VulkanInclude.hpp>
|
|
||||||
|
|
||||||
#include <GraphicsInterface/GraphicsInstance.hpp>
|
|
||||||
|
|
||||||
#include <Utils/TargetMacros.h>
|
|
||||||
#include <Utils/Version.hpp>
|
|
||||||
|
|
||||||
#include <EASTL/string_view.h>
|
|
||||||
|
|
||||||
namespace Bigfoot::Vulkan
|
|
||||||
{
|
|
||||||
class VulkanInstance final: public GraphicsInstance
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Constructor. Creates a vk::Instance
|
|
||||||
*
|
|
||||||
* \param p_applicationName The name of the application
|
|
||||||
* \param p_applicationVersion The version of the application
|
|
||||||
*/
|
|
||||||
VulkanInstance(eastl::string_view p_applicationName, Version p_applicationVersion);
|
|
||||||
|
|
||||||
~VulkanInstance() override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the underlying Vulkan instance handle
|
|
||||||
*
|
|
||||||
* \return The vk::Instance handle
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
vk::Instance GetHandle() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* The vulkan loader.
|
|
||||||
*/
|
|
||||||
vk::detail::DynamicLoader m_loader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The vulkan instance.
|
|
||||||
*/
|
|
||||||
vk::Instance m_instance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The debug messenger (used for validation callbacks).
|
|
||||||
*/
|
|
||||||
BIGFOOT_NOT_OPTIMIZED_ONLY(vk::DebugUtilsMessengerEXT m_debugMessenger;)
|
|
||||||
};
|
|
||||||
} // namespace Bigfoot::Vulkan
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file VulkanQueue.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANQUEUE_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSVULKAN_VULKANQUEUE_HPP
|
|
||||||
#include <GraphicsVulkan/VulkanInclude.hpp>
|
|
||||||
|
|
||||||
#include <GraphicsInterface/GraphicsQueue.hpp>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace Bigfoot::Vulkan
|
|
||||||
{
|
|
||||||
class VulkanQueue final: public GraphicsQueue
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* \param p_queue The underlying Vulkan queue handle
|
|
||||||
* \param p_familyIndex The queue family index this queue was retrieved from
|
|
||||||
* \param p_type The kind of work this queue can submit
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
*
|
|
||||||
* \return The queue type
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
GraphicsQueueType GetType() const override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the underlying Vulkan queue handle
|
|
||||||
*
|
|
||||||
* \return The vk::Queue handle
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
vk::Queue GetHandle() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the index of the queue family this queue was retrieved from
|
|
||||||
*
|
|
||||||
* \return The queue family index
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
std::uint32_t GetFamilyIndex() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* The vulkn queue
|
|
||||||
*/
|
|
||||||
vk::Queue m_queue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of the queue family this queue was retrieved from
|
|
||||||
*/
|
|
||||||
std::uint32_t m_familyIndex;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The kind of work this queue can submit
|
|
||||||
*/
|
|
||||||
GraphicsQueueType m_type;
|
|
||||||
};
|
|
||||||
} // namespace Bigfoot::Vulkan
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file VulkanSurface.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANSURFACE_HPP
|
|
||||||
#define BIGFOOT_GRAPHICSVULKAN_VULKANSURFACE_HPP
|
|
||||||
#include <GraphicsVulkan/VulkanInclude.hpp>
|
|
||||||
#include <GraphicsVulkan/VulkanInstance.hpp>
|
|
||||||
|
|
||||||
#include <GraphicsInterface/GraphicsSurface.hpp>
|
|
||||||
|
|
||||||
namespace Bigfoot::Vulkan
|
|
||||||
{
|
|
||||||
class VulkanSurface final: public GraphicsSurface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
* Creates a vk::SurfaceKHR for the given native window.
|
|
||||||
*
|
|
||||||
* \param p_instance The instance to create the surface from
|
|
||||||
* \param p_surfaceCreateInfo The native window handles to create the surface for
|
|
||||||
*/
|
|
||||||
VulkanSurface(const VulkanInstance& p_instance, const SurfaceCreateInfo& p_surfaceCreateInfo);
|
|
||||||
|
|
||||||
~VulkanSurface() override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the underlying Vulkan surface handle
|
|
||||||
*
|
|
||||||
* \return The vk::SurfaceKHR handle
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
vk::SurfaceKHR GetHandle() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* The instance
|
|
||||||
*/
|
|
||||||
const VulkanInstance& m_instance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The surface
|
|
||||||
*/
|
|
||||||
vk::SurfaceKHR m_surface;
|
|
||||||
};
|
|
||||||
} // namespace Bigfoot::Vulkan
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,352 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file VulkanInstance.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <GraphicsVulkan/VulkanInstance.hpp>
|
|
||||||
|
|
||||||
#include <GraphicsVulkan/GraphicsVulkanAssertHandler.hpp>
|
|
||||||
#include <GraphicsVulkan/VulkanFormatters.hpp>
|
|
||||||
|
|
||||||
#include <Utils/TargetMacros.h>
|
|
||||||
|
|
||||||
#include <Engine/EngineInfo_generated.hpp>
|
|
||||||
|
|
||||||
#include <EASTL/algorithm.h>
|
|
||||||
#include <EASTL/string.h>
|
|
||||||
#include <EASTL/vector.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
namespace Bigfoot::Vulkan
|
|
||||||
{
|
|
||||||
[[nodiscard]]
|
|
||||||
std::uint32_t ToVulkanVersion(const Bigfoot::Version p_version)
|
|
||||||
{
|
|
||||||
return VK_MAKE_VERSION(p_version.GetMajor(), p_version.GetMinor(), p_version.GetPatch());
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_NOT_OPTIMIZED
|
|
||||||
vk::Bool32 VulkanDebugCallback(const vk::DebugUtilsMessageSeverityFlagBitsEXT p_severity,
|
|
||||||
[[maybe_unused]] vk::DebugUtilsMessageTypeFlagsEXT p_type,
|
|
||||||
const vk::DebugUtilsMessengerCallbackDataEXT* p_callbackData,
|
|
||||||
[[maybe_unused]] void* p_userData)
|
|
||||||
{
|
|
||||||
switch (p_severity)
|
|
||||||
{
|
|
||||||
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eError:
|
|
||||||
BIGFOOT_LOG_ERROR(::Bigfoot::GRAPHICSVULKAN_LOGGER, "{}", p_callbackData->pMessage);
|
|
||||||
break;
|
|
||||||
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning:
|
|
||||||
BIGFOOT_LOG_WARN(::Bigfoot::GRAPHICSVULKAN_LOGGER, "{}", p_callbackData->pMessage);
|
|
||||||
break;
|
|
||||||
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo:
|
|
||||||
BIGFOOT_LOG_INFO(::Bigfoot::GRAPHICSVULKAN_LOGGER, "{}", p_callbackData->pMessage);
|
|
||||||
break;
|
|
||||||
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose:
|
|
||||||
default:
|
|
||||||
BIGFOOT_LOG_TRACE(::Bigfoot::GRAPHICSVULKAN_LOGGER, "{}", p_callbackData->pMessage);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return VK_FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
VulkanInstance::VulkanInstance(const eastl::string_view p_applicationName, const Version p_applicationVersion)
|
|
||||||
{
|
|
||||||
const PFN_vkGetInstanceProcAddr getInstanceProcAddr = m_loader.getProcAddress<PFN_vkGetInstanceProcAddr>(
|
|
||||||
"vkGetInstanceProcAddr");
|
|
||||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler, getInstanceProcAddr != nullptr, "vkGetInstanceProcAddr not found!");
|
|
||||||
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(getInstanceProcAddr);
|
|
||||||
|
|
||||||
const eastl::string applicationName {p_applicationName};
|
|
||||||
const vk::ApplicationInfo applicationInfo {applicationName.c_str(),
|
|
||||||
ToVulkanVersion(p_applicationVersion),
|
|
||||||
BIGFOOT_NAME.data(),
|
|
||||||
ToVulkanVersion(BIGFOOT_VERSION),
|
|
||||||
VK_API_VERSION_1_3};
|
|
||||||
|
|
||||||
eastl::vector<const char*> enabledLayers;
|
|
||||||
eastl::vector<const char*> enabledExtensions {
|
|
||||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
|
||||||
BIGFOOT_WINDOWS_OR_LINUX(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME)};
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_NOT_OPTIMIZED
|
|
||||||
const vk::ResultValue<std::vector<vk::LayerProperties>> availableLayers = vk::enumerateInstanceLayerProperties();
|
|
||||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
|
||||||
availableLayers.result == vk::Result::eSuccess,
|
|
||||||
"({}) Failed to enumerate Vulkan instance layers",
|
|
||||||
availableLayers.result);
|
|
||||||
|
|
||||||
const bool validationLayerAvailable = eastl::find_if(availableLayers.value.begin(),
|
|
||||||
availableLayers.value.end(),
|
|
||||||
[](const vk::LayerProperties& p_layer)
|
|
||||||
{
|
|
||||||
return eastl::string_view {p_layer.layerName.data()} ==
|
|
||||||
"VK_LAYER_KHRONOS_validation";
|
|
||||||
}) != availableLayers.value.end();
|
|
||||||
|
|
||||||
if (validationLayerAvailable)
|
|
||||||
{
|
|
||||||
enabledLayers.push_back("VK_LAYER_KHRONOS_validation");
|
|
||||||
enabledExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BIGFOOT_LOG_WARN(GRAPHICSVULKAN_LOGGER, "Vulkan validation layer requested but not available");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const vk::InstanceCreateInfo instanceCreateInfo {{}, &applicationInfo, enabledLayers, enabledExtensions};
|
|
||||||
|
|
||||||
vk::ResultValue<vk::Instance> instance {vk::Result::eSuccess, vk::Instance {}};
|
|
||||||
{
|
|
||||||
BIGFOOT_LSAN_ONLY(const __lsan::ScopedDisabler lsanDisabler;)
|
|
||||||
instance = vk::createInstance(instanceCreateInfo);
|
|
||||||
}
|
|
||||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
|
||||||
instance.result == vk::Result::eSuccess,
|
|
||||||
"({}) Failed to create Vulkan instance",
|
|
||||||
instance.result);
|
|
||||||
m_instance = instance.value;
|
|
||||||
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(m_instance);
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_NOT_OPTIMIZED
|
|
||||||
if (validationLayerAvailable)
|
|
||||||
{
|
|
||||||
vk::DebugUtilsMessengerCreateInfoEXT messengerCreateInfo {};
|
|
||||||
messengerCreateInfo.messageSeverity = vk::DebugUtilsMessageSeverityFlagsEXT {
|
|
||||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose | vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
|
|
||||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | vk::DebugUtilsMessageSeverityFlagBitsEXT::eError};
|
|
||||||
messengerCreateInfo.messageType = vk::DebugUtilsMessageTypeFlagsEXT {
|
|
||||||
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
|
|
||||||
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance};
|
|
||||||
messengerCreateInfo.pfnUserCallback = &VulkanDebugCallback;
|
|
||||||
|
|
||||||
const vk::ResultValue<vk::DebugUtilsMessengerEXT> messenger = m_instance.createDebugUtilsMessengerEXT(
|
|
||||||
messengerCreateInfo);
|
|
||||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
|
||||||
messenger.result == vk::Result::eSuccess,
|
|
||||||
"({}) Failed to create Vulkan debug messenger",
|
|
||||||
messenger.result);
|
|
||||||
m_debugMessenger = messenger.value;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
VulkanInstance::~VulkanInstance()
|
|
||||||
{
|
|
||||||
#ifdef BIGFOOT_NOT_OPTIMIZED
|
|
||||||
if (m_debugMessenger)
|
|
||||||
{
|
|
||||||
m_instance.destroyDebugUtilsMessengerEXT(m_debugMessenger);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
m_instance.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
vk::Instance VulkanInstance::GetHandle() const
|
|
||||||
{
|
|
||||||
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
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file VulkanQueue.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <GraphicsVulkan/VulkanQueue.hpp>
|
|
||||||
|
|
||||||
namespace Bigfoot::Vulkan
|
|
||||||
{
|
|
||||||
VulkanQueue::VulkanQueue(const vk::Queue p_queue, const std::uint32_t p_familyIndex, const GraphicsQueueType p_type):
|
|
||||||
m_queue(p_queue),
|
|
||||||
m_familyIndex(p_familyIndex),
|
|
||||||
m_type(p_type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
vk::Queue VulkanQueue::GetHandle() const
|
|
||||||
{
|
|
||||||
return m_queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
std::uint32_t VulkanQueue::GetFamilyIndex() const
|
|
||||||
{
|
|
||||||
return m_familyIndex;
|
|
||||||
}
|
|
||||||
} // namespace Bigfoot::Vulkan
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file VulkanSurface.cpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#include <GraphicsVulkan/VulkanSurface.hpp>
|
|
||||||
|
|
||||||
#include <GraphicsVulkan/GraphicsVulkanAssertHandler.hpp>
|
|
||||||
#include <GraphicsVulkan/VulkanFormatters.hpp>
|
|
||||||
|
|
||||||
namespace Bigfoot::Vulkan
|
|
||||||
{
|
|
||||||
VulkanSurface::VulkanSurface(const VulkanInstance& p_instance, const SurfaceCreateInfo& p_surfaceCreateInfo):
|
|
||||||
m_instance(p_instance)
|
|
||||||
{
|
|
||||||
#ifdef BIGFOOT_WINDOWS
|
|
||||||
const vk::Win32SurfaceCreateInfoKHR createInfo {{},
|
|
||||||
p_surfaceCreateInfo.m_windowInstance,
|
|
||||||
p_surfaceCreateInfo.m_windowHandle};
|
|
||||||
const vk::ResultValue<vk::SurfaceKHR> surface = m_instance.GetHandle().createWin32SurfaceKHR(createInfo);
|
|
||||||
#elif defined BIGFOOT_LINUX
|
|
||||||
const vk::WaylandSurfaceCreateInfoKHR createInfo {{}, p_surfaceCreateInfo.m_display, p_surfaceCreateInfo.m_surface};
|
|
||||||
const vk::ResultValue<vk::SurfaceKHR> surface = m_instance.GetHandle().createWaylandSurfaceKHR(createInfo);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
|
||||||
surface.result == vk::Result::eSuccess,
|
|
||||||
"({}) Failed to create Vulkan surface",
|
|
||||||
surface.result);
|
|
||||||
m_surface = surface.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
VulkanSurface::~VulkanSurface()
|
|
||||||
{
|
|
||||||
m_instance.GetHandle().destroySurfaceKHR(m_surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
vk::SurfaceKHR VulkanSurface::GetHandle() const
|
|
||||||
{
|
|
||||||
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
|
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file Graph.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date August 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_UTILS_ALGORITHM_GRAPH_HPP
|
|
||||||
#define BIGFOOT_UTILS_ALGORITHM_GRAPH_HPP
|
|
||||||
#include <Utils/UtilsAssertHandler.hpp>
|
|
||||||
|
|
||||||
#include <EASTL/vector.h>
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Kahn's algorithm
|
|
||||||
*
|
|
||||||
* \param p_graph Every discovered node's outgoing edges (eg: its dependencies)
|
|
||||||
* \param p_nodes The set of nodes to sort
|
|
||||||
* \param p_waves The sorted nodes
|
|
||||||
* \param p_cyclicNodes Nodes that could not be sorted (ie: part of a cycle)
|
|
||||||
* \return True if a cycle was found
|
|
||||||
*/
|
|
||||||
template<class NODE_TYPE>
|
|
||||||
[[nodiscard]]
|
|
||||||
bool LayeredTopologicalSort(const ankerl::unordered_dense::map<NODE_TYPE, eastl::vector<NODE_TYPE>>& p_graph,
|
|
||||||
const ankerl::unordered_dense::set<NODE_TYPE>& p_nodes,
|
|
||||||
eastl::vector<eastl::vector<NODE_TYPE>>& p_waves,
|
|
||||||
eastl::vector<NODE_TYPE>& p_cyclicNodes)
|
|
||||||
{
|
|
||||||
ASSERT(UtilsAssertHandler, p_waves.empty(), "p_waves must be empty");
|
|
||||||
ASSERT(UtilsAssertHandler, p_cyclicNodes.empty(), "p_cyclicNodes must be empty");
|
|
||||||
ASSERT(UtilsAssertHandler,
|
|
||||||
p_nodes.size() <= std::numeric_limits<std::uint32_t>::max(),
|
|
||||||
"Can't sort more than {} nodes",
|
|
||||||
std::numeric_limits<std::uint32_t>::max());
|
|
||||||
|
|
||||||
const auto nodeCount = static_cast<std::uint32_t>(p_nodes.size());
|
|
||||||
|
|
||||||
ankerl::unordered_dense::map<NODE_TYPE, std::uint32_t> nodeToIndex;
|
|
||||||
nodeToIndex.reserve(nodeCount);
|
|
||||||
eastl::vector<NODE_TYPE> indexToNode;
|
|
||||||
indexToNode.reserve(nodeCount);
|
|
||||||
for (const NODE_TYPE& node: p_nodes)
|
|
||||||
{
|
|
||||||
nodeToIndex.emplace(node, static_cast<std::uint32_t>(indexToNode.size()));
|
|
||||||
indexToNode.push_back(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 1: Compute in-degree for each node
|
|
||||||
eastl::vector<std::uint32_t> inDegree(nodeCount, 0);
|
|
||||||
|
|
||||||
// Reverse adjacency (which nodes depend on each node) stored as CSR: adjacencyOffsets[i]..adjacencyOffsets[i + 1]
|
|
||||||
// is node i's slice of adjacency. Built in two passes (count listeners per node, then fill) so the whole
|
|
||||||
// structure is a couple of flat allocations instead of one per node.
|
|
||||||
eastl::vector<std::uint32_t> adjacencyOffsets(nodeCount + 1, 0);
|
|
||||||
|
|
||||||
// Initialize queue with nodes having in-degree 0
|
|
||||||
eastl::vector<std::uint32_t> queue;
|
|
||||||
queue.reserve(nodeCount);
|
|
||||||
for (std::uint32_t index = 0; index < nodeCount; ++index)
|
|
||||||
{
|
|
||||||
std::uint32_t degree = 0;
|
|
||||||
for (const NODE_TYPE& edge: p_graph.at(indexToNode[index]))
|
|
||||||
{
|
|
||||||
const auto nodeIt = nodeToIndex.find(edge);
|
|
||||||
if (nodeIt != nodeToIndex.end())
|
|
||||||
{
|
|
||||||
++degree;
|
|
||||||
++adjacencyOffsets[nodeIt->second + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inDegree[index] = degree;
|
|
||||||
if (degree == 0)
|
|
||||||
{
|
|
||||||
queue.push_back(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::uint32_t index = 0; index < nodeCount; ++index)
|
|
||||||
{
|
|
||||||
adjacencyOffsets[index + 1] += adjacencyOffsets[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
eastl::vector<std::uint32_t> adjacency(adjacencyOffsets.back());
|
|
||||||
eastl::vector<std::uint32_t> cursor(adjacencyOffsets.begin(), adjacencyOffsets.end() - 1);
|
|
||||||
for (std::uint32_t index = 0; index < nodeCount; ++index)
|
|
||||||
{
|
|
||||||
for (const NODE_TYPE& edge: p_graph.at(indexToNode[index]))
|
|
||||||
{
|
|
||||||
const auto nodeIt = nodeToIndex.find(edge);
|
|
||||||
if (nodeIt != nodeToIndex.end())
|
|
||||||
{
|
|
||||||
adjacency[cursor[nodeIt->second]++] = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2: Process nodes
|
|
||||||
std::size_t resolvedCount = 0;
|
|
||||||
eastl::vector<std::uint32_t> nextQueue;
|
|
||||||
nextQueue.reserve(nodeCount);
|
|
||||||
while (!queue.empty())
|
|
||||||
{
|
|
||||||
resolvedCount += queue.size();
|
|
||||||
|
|
||||||
// Reduce in-degree for neighbors
|
|
||||||
nextQueue.clear();
|
|
||||||
for (const std::uint32_t index: queue)
|
|
||||||
{
|
|
||||||
for (std::uint32_t i = adjacencyOffsets[index]; i < adjacencyOffsets[index + 1]; ++i)
|
|
||||||
{
|
|
||||||
const std::uint32_t next = adjacency[i];
|
|
||||||
if (--inDegree[next] == 0)
|
|
||||||
{
|
|
||||||
nextQueue.push_back(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eastl::vector<NODE_TYPE> waveNodes;
|
|
||||||
waveNodes.reserve(queue.size());
|
|
||||||
for (const std::uint32_t index: queue)
|
|
||||||
{
|
|
||||||
waveNodes.push_back(indexToNode[index]);
|
|
||||||
}
|
|
||||||
p_waves.push_back(std::move(waveNodes));
|
|
||||||
|
|
||||||
queue.swap(nextQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3 & 4: Check for valid topological order
|
|
||||||
if (resolvedCount != nodeCount)
|
|
||||||
{
|
|
||||||
p_cyclicNodes.reserve(nodeCount - resolvedCount);
|
|
||||||
for (std::uint32_t index = 0; index < nodeCount; ++index)
|
|
||||||
{
|
|
||||||
if (inDegree[index] != 0)
|
|
||||||
{
|
|
||||||
p_cyclicNodes.push_back(indexToNode[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolvedCount != nodeCount;
|
|
||||||
}
|
|
||||||
} // namespace Bigfoot
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file Assert.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date October 2025
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_UTILS_ASSERT_HPP
|
|
||||||
#define BIGFOOT_UTILS_ASSERT_HPP
|
|
||||||
#include <Utils/Log/LogMacros.hpp>
|
|
||||||
#include <Utils/TargetMacros.h>
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_NOT_OPTIMIZED
|
|
||||||
|
|
||||||
#include <Utils/Format.hpp>
|
|
||||||
|
|
||||||
#include <EASTL/fixed_function.h>
|
|
||||||
#include <EASTL/string.h>
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <source_location>
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_LINUX
|
|
||||||
#include <csignal>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BIGFOOT_WINDOWS
|
|
||||||
#define BREAK \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
BIGFOOT_FLUSH_LOG; \
|
|
||||||
__debugbreak(); \
|
|
||||||
} while (false)
|
|
||||||
#elif defined BIGFOOT_LINUX
|
|
||||||
#define BREAK \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
BIGFOOT_FLUSH_LOG; \
|
|
||||||
std::raise(SIGTRAP); \
|
|
||||||
} while (false)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Assert then break
|
|
||||||
*
|
|
||||||
* \param p_condition The condition to check
|
|
||||||
* \param p_message A function that will return the formatting string describing the issue
|
|
||||||
* \param p_location The location the assert originates from
|
|
||||||
*/
|
|
||||||
template<typename HANDLER>
|
|
||||||
BIGFOOT_ALWAYS_INLINE void AssertCheck(const bool p_condition,
|
|
||||||
const eastl::fixed_function<32, eastl::string()>& p_messageFn,
|
|
||||||
const std::source_location p_location = std::source_location::current())
|
|
||||||
{
|
|
||||||
if (!p_condition) [[unlikely]]
|
|
||||||
{
|
|
||||||
HANDLER::Handle(p_location, p_messageFn());
|
|
||||||
BREAK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assert then break then kill
|
|
||||||
*
|
|
||||||
* \param p_condition The condition to check
|
|
||||||
* \param p_message A function that will return the formatting string describing the issue
|
|
||||||
* \param p_location The location the assert originates from
|
|
||||||
*/
|
|
||||||
template<typename HANDLER>
|
|
||||||
BIGFOOT_ALWAYS_INLINE void CriticalAssertCheck(const bool p_condition,
|
|
||||||
const eastl::fixed_function<32, eastl::string()>& p_messageFn,
|
|
||||||
const std::source_location p_location = std::source_location::current())
|
|
||||||
{
|
|
||||||
if (!p_condition) [[unlikely]]
|
|
||||||
{
|
|
||||||
HANDLER::Handle(p_location, p_messageFn());
|
|
||||||
BREAK;
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace Bigfoot
|
|
||||||
|
|
||||||
#define ASSERT(HANDLER, p_assert, p_message, ...) \
|
|
||||||
::Bigfoot::AssertCheck<HANDLER>((p_assert), \
|
|
||||||
[&] \
|
|
||||||
{ \
|
|
||||||
return ::Bigfoot::Format(p_message __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define SOFT_ASSERT(HANDLER, p_assert, p_message, ...) \
|
|
||||||
::Bigfoot::AssertCheck<HANDLER>((p_assert), \
|
|
||||||
[&] \
|
|
||||||
{ \
|
|
||||||
return ::Bigfoot::Format(p_message __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define CRITICAL_ASSERT(HANDLER, p_assert, p_message, ...) \
|
|
||||||
::Bigfoot::CriticalAssertCheck<HANDLER>((p_assert), \
|
|
||||||
[&] \
|
|
||||||
{ \
|
|
||||||
return ::Bigfoot::Format(p_message __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define ASSERT(HANDLER, p_assert, p_message, ...)
|
|
||||||
|
|
||||||
#define SOFT_ASSERT(HANDLER, p_assert, p_message, ...)
|
|
||||||
|
|
||||||
#define CRITICAL_ASSERT(HANDLER, p_assert, p_message, ...)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file Factory.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_UTILS_FACTORY_HPP
|
|
||||||
#define BIGFOOT_UTILS_FACTORY_HPP
|
|
||||||
#include <EASTL/unique_ptr.h>
|
|
||||||
#include <EASTL/utility.h>
|
|
||||||
#include <ankerl/unordered_dense.h>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
template<class TYPE, class KEY, class CREATEFUNCTION>
|
|
||||||
class Factory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Register a key inside the factory
|
|
||||||
*
|
|
||||||
* \param p_key The key
|
|
||||||
* \param p_function The create function
|
|
||||||
* \return True if the key has been registered, false if it was already registered
|
|
||||||
*/
|
|
||||||
[[nodiscard]]
|
|
||||||
bool Register(const KEY p_key, CREATEFUNCTION&& p_function)
|
|
||||||
{
|
|
||||||
if (m_createFunctions.find(p_key) == m_createFunctions.end())
|
|
||||||
{
|
|
||||||
m_createFunctions.emplace(p_key, eastl::move(p_function));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an instance from the factory
|
|
||||||
*
|
|
||||||
* \param p_key The key to create. Needs to have been registered with Register()
|
|
||||||
* \param p_args Arguments for the creation
|
|
||||||
* \return The created instance. nullptr is returned if the key has not been registered
|
|
||||||
*/
|
|
||||||
template<typename... ARGS>
|
|
||||||
[[nodiscard]]
|
|
||||||
eastl::unique_ptr<TYPE> Create(const KEY p_key, ARGS&&... p_args) const
|
|
||||||
{
|
|
||||||
if (const auto createFunction = m_createFunctions.find(p_key); createFunction != m_createFunctions.end())
|
|
||||||
{
|
|
||||||
return createFunction->second(eastl::forward<ARGS>(p_args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a key and its associated create function from the factory
|
|
||||||
*
|
|
||||||
* \param p_key The key to remove
|
|
||||||
*/
|
|
||||||
void Remove(const KEY p_key)
|
|
||||||
{
|
|
||||||
m_createFunctions.erase(p_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* The mapping between keys and create functions
|
|
||||||
*/
|
|
||||||
ankerl::unordered_dense::map<KEY, CREATEFUNCTION> m_createFunctions;
|
|
||||||
};
|
|
||||||
} // namespace Bigfoot
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \file Format.hpp
|
|
||||||
*
|
|
||||||
* \author Romain BOULLARD
|
|
||||||
* \date September 2026
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef BIGFOOT_UTILS_FORMAT_HPP
|
|
||||||
#define BIGFOOT_UTILS_FORMAT_HPP
|
|
||||||
#include <EASTL/string.h>
|
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Format a string, like fmt::format, but returning an eastl::string instead of a std::string.
|
|
||||||
*
|
|
||||||
* \param p_format The format string
|
|
||||||
* \param p_args The arguments for the format string
|
|
||||||
* \return The formatted eastl::string
|
|
||||||
*/
|
|
||||||
template<typename... ARGS>
|
|
||||||
eastl::string Format(fmt::format_string<ARGS...> p_format, ARGS&&... p_args)
|
|
||||||
{
|
|
||||||
fmt::memory_buffer buffer;
|
|
||||||
fmt::format_to(std::back_inserter(buffer), p_format, std::forward<ARGS>(p_args)...);
|
|
||||||
return eastl::string {buffer.data(), buffer.size()};
|
|
||||||
}
|
|
||||||
} // namespace Bigfoot
|
|
||||||
#endif
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
* \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
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System)
|
||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file AssetLibrary.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Engine/Asset/AssetLibrary.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
void SetActiveAssetLibrary(AssetLibrary* p_assetLibrary)
|
||||||
|
{
|
||||||
|
g_activeAssetLibrary = p_assetLibrary;
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -0,0 +1,607 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file BigFile.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date October 2025
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Engine/BigFile/BigFile.hpp>
|
||||||
|
|
||||||
|
#include <Engine/EngineAssertHandler.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/algorithm.h>
|
||||||
|
#include <EASTL/sort.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
#ifdef BIGFOOT_TOOLMODE
|
||||||
|
BigFile::BigFile(const File& p_file)
|
||||||
|
{
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_open_v2(p_file.ToAbsolute().GetPath().data(), &m_db, SQLITE_OPEN_READWRITE, nullptr);
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler,
|
||||||
|
result == SQLITE_OK,
|
||||||
|
"Failed to open BigFile {} DB: {}",
|
||||||
|
p_file.ToAbsolute().GetPath(),
|
||||||
|
sqlite3_errmsg(m_db));
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int synchronousResult = sqlite3_exec(m_db, "PRAGMA synchronous = NORMAL;", nullptr, nullptr, nullptr);
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
synchronousResult == SQLITE_OK,
|
||||||
|
"Failed to set synchronous pragma: {}",
|
||||||
|
sqlite3_errmsg(m_db));
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int foreignKeysResult = sqlite3_exec(m_db, "PRAGMA foreign_keys = ON;", nullptr, nullptr, nullptr);
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
foreignKeysResult == SQLITE_OK,
|
||||||
|
"Failed to set foreign_keys pragma: {}",
|
||||||
|
sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::BeginTransaction()
|
||||||
|
{
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_exec(m_db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr);
|
||||||
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to begin transaction: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::CommitTransaction()
|
||||||
|
{
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_exec(m_db, "COMMIT TRANSACTION;", nullptr, nullptr, nullptr);
|
||||||
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to commit: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::RollbackTransaction()
|
||||||
|
{
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_exec(m_db, "ROLLBACK TRANSACTION;", nullptr, nullptr, nullptr);
|
||||||
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to rollback: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::~BigFile()
|
||||||
|
{
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_close_v2(m_db);
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to close BigFile DB: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::optional<eastl::vector<std::byte>> BigFile::GetAssetFlatbuffer(const UUID& p_uuid) const
|
||||||
|
{
|
||||||
|
BigFile::Request assetRequest {*this, "SELECT Asset FROM Asset WHERE UUID = ?1;"};
|
||||||
|
assetRequest.Bind(1, p_uuid.ToBytes());
|
||||||
|
|
||||||
|
if (!assetRequest.Step())
|
||||||
|
{
|
||||||
|
return eastl::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const eastl::span<const std::byte> flatbuffer = assetRequest.Get(0);
|
||||||
|
return eastl::vector<std::byte> {flatbuffer.begin(), flatbuffer.end()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::vector<eastl::vector<std::byte>> BigFile::GetAssetFlatbuffers(const eastl::span<const UUID> p_uuids) const
|
||||||
|
{
|
||||||
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||||
|
if (p_uuids.empty())
|
||||||
|
{
|
||||||
|
return flatbuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
flatbuffers.reserve(p_uuids.size());
|
||||||
|
|
||||||
|
if (p_uuids.size() == 1)
|
||||||
|
{
|
||||||
|
if (eastl::optional<eastl::vector<std::byte>> flatbuffer = GetAssetFlatbuffer(p_uuids[0]);
|
||||||
|
flatbuffer.has_value())
|
||||||
|
{
|
||||||
|
flatbuffers.push_back(std::move(*flatbuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return flatbuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<UUID> uniqueUUIDs {p_uuids.begin(), p_uuids.end()};
|
||||||
|
eastl::sort(uniqueUUIDs.begin(), uniqueUUIDs.end());
|
||||||
|
uniqueUUIDs.erase(eastl::unique(uniqueUUIDs.begin(), uniqueUUIDs.end()), uniqueUUIDs.end());
|
||||||
|
|
||||||
|
eastl::string placeholders;
|
||||||
|
placeholders.reserve(uniqueUUIDs.size() * 3);
|
||||||
|
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
placeholders += ", ";
|
||||||
|
}
|
||||||
|
placeholders += "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string sqlRequest = fmt::format("SELECT Asset FROM Asset WHERE UUID IN ({});", placeholders);
|
||||||
|
|
||||||
|
BigFile::Request assetRequest {*this, sqlRequest.c_str()};
|
||||||
|
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
||||||
|
{
|
||||||
|
assetRequest.Bind(static_cast<std::uint32_t>(i + 1), uniqueUUIDs[i].ToBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
flatbuffers.reserve(uniqueUUIDs.size());
|
||||||
|
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!assetRequest.Step())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const eastl::span<const std::byte> flatbuffer = assetRequest.Get(0);
|
||||||
|
flatbuffers.emplace_back(flatbuffer.begin(), flatbuffer.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return flatbuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::optional<AssetMetadata> BigFile::GetAssetMetadata(const UUID& p_uuid) const
|
||||||
|
{
|
||||||
|
BigFile::Request assetRequest {
|
||||||
|
*this,
|
||||||
|
"SELECT UUID, Name, TypeID, TypeName, CreateTime, ModificationTime FROM AssetMetadata WHERE UUID = ?1;"};
|
||||||
|
assetRequest.Bind(1, p_uuid.ToBytes());
|
||||||
|
|
||||||
|
if (!assetRequest.Step())
|
||||||
|
{
|
||||||
|
return eastl::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AssetMetadata {.m_uuid = UUID {std::span<const std::byte, UUID::UUID_BYTE_SIZE> {
|
||||||
|
static_cast<eastl::span<const std::byte>>(assetRequest.Get(0)).data(),
|
||||||
|
UUID::UUID_BYTE_SIZE}},
|
||||||
|
.m_name = eastl::string {static_cast<eastl::string_view>(assetRequest.Get(1))},
|
||||||
|
.m_typeID = assetRequest.Get(2),
|
||||||
|
.m_typeName = eastl::string {static_cast<eastl::string_view>(assetRequest.Get(3))},
|
||||||
|
.m_creationTime = Time {static_cast<std::uint64_t>(assetRequest.Get(4))},
|
||||||
|
.m_modificationTime = Time {static_cast<std::uint64_t>(assetRequest.Get(5))}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::vector<AssetMetadata> BigFile::GetAssetMetadatas(const eastl::span<const UUID> p_uuids) const
|
||||||
|
{
|
||||||
|
eastl::vector<AssetMetadata> metadatas;
|
||||||
|
if (p_uuids.empty())
|
||||||
|
{
|
||||||
|
return metadatas;
|
||||||
|
}
|
||||||
|
|
||||||
|
metadatas.reserve(p_uuids.size());
|
||||||
|
|
||||||
|
if (p_uuids.size() == 1)
|
||||||
|
{
|
||||||
|
if (eastl::optional<AssetMetadata> metadata = GetAssetMetadata(p_uuids[0]); metadata.has_value())
|
||||||
|
{
|
||||||
|
metadatas.push_back(std::move(*metadata));
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadatas;
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<UUID> uniqueUUIDs {p_uuids.begin(), p_uuids.end()};
|
||||||
|
eastl::sort(uniqueUUIDs.begin(), uniqueUUIDs.end());
|
||||||
|
uniqueUUIDs.erase(eastl::unique(uniqueUUIDs.begin(), uniqueUUIDs.end()), uniqueUUIDs.end());
|
||||||
|
|
||||||
|
eastl::string placeholders;
|
||||||
|
placeholders.reserve(uniqueUUIDs.size() * 3);
|
||||||
|
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
placeholders += ", ";
|
||||||
|
}
|
||||||
|
placeholders += "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string sqlRequest = fmt::format("SELECT UUID, Name, TypeID, TypeName, CreateTime, ModificationTime "
|
||||||
|
"FROM AssetMetadata WHERE UUID IN ({});",
|
||||||
|
placeholders);
|
||||||
|
|
||||||
|
BigFile::Request assetRequest {*this, sqlRequest.c_str()};
|
||||||
|
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
||||||
|
{
|
||||||
|
assetRequest.Bind(static_cast<std::uint32_t>(i + 1), uniqueUUIDs[i].ToBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
metadatas.reserve(uniqueUUIDs.size());
|
||||||
|
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!assetRequest.Step())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
metadatas.push_back(
|
||||||
|
AssetMetadata {.m_uuid = UUID {std::span<const std::byte, UUID::UUID_BYTE_SIZE> {
|
||||||
|
static_cast<eastl::span<const std::byte>>(assetRequest.Get(0)).data(),
|
||||||
|
UUID::UUID_BYTE_SIZE}},
|
||||||
|
.m_name = eastl::string {static_cast<eastl::string_view>(assetRequest.Get(1))},
|
||||||
|
.m_typeID = assetRequest.Get(2),
|
||||||
|
.m_typeName = eastl::string {static_cast<eastl::string_view>(assetRequest.Get(3))},
|
||||||
|
.m_creationTime = Time {static_cast<std::uint64_t>(assetRequest.Get(4))},
|
||||||
|
.m_modificationTime = Time {static_cast<std::uint64_t>(assetRequest.Get(5))}});
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadatas;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::SaveAssetFlatbuffer(const AssetMetadata& p_metadata, const eastl::span<const std::byte> p_flatbuffer)
|
||||||
|
{
|
||||||
|
BeginTransaction();
|
||||||
|
|
||||||
|
BigFile::Request metadataRequest {
|
||||||
|
*this,
|
||||||
|
"INSERT INTO AssetMetadata (UUID, Name, TypeID, TypeName) VALUES (?1, ?2, ?3, ?4) "
|
||||||
|
"ON CONFLICT(UUID) DO UPDATE SET Name = excluded.Name, TypeID = excluded.TypeID, TypeName = excluded.TypeName;"};
|
||||||
|
metadataRequest.Bind(1, p_metadata.m_uuid.ToBytes());
|
||||||
|
metadataRequest.Bind(2, p_metadata.m_name);
|
||||||
|
metadataRequest.Bind(3, p_metadata.m_typeID);
|
||||||
|
metadataRequest.Bind(4, p_metadata.m_typeName);
|
||||||
|
metadataRequest.Execute();
|
||||||
|
|
||||||
|
BigFile::Request assetRequest {*this,
|
||||||
|
"INSERT INTO Asset (UUID, Asset) VALUES (?1, ?2) "
|
||||||
|
"ON CONFLICT(UUID) DO UPDATE SET Asset = excluded.Asset;"};
|
||||||
|
assetRequest.Bind(1, p_metadata.m_uuid.ToBytes());
|
||||||
|
assetRequest.Bind(2, p_flatbuffer);
|
||||||
|
assetRequest.Execute();
|
||||||
|
|
||||||
|
CommitTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::SaveAssetFlatbuffers(const eastl::span<const AssetMetadata> p_metadatas,
|
||||||
|
const eastl::span<const eastl::vector<std::byte>> p_flatbuffers)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
p_metadatas.size() == p_flatbuffers.size(),
|
||||||
|
"p_metadatas and p_flatbuffers must have the same size");
|
||||||
|
|
||||||
|
if (p_metadatas.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BeginTransaction();
|
||||||
|
|
||||||
|
constexpr std::size_t METADATA_PARAMS_PER_ROW = 4;
|
||||||
|
const std::size_t maxRowsPerStatement = static_cast<std::size_t>(
|
||||||
|
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
||||||
|
METADATA_PARAMS_PER_ROW;
|
||||||
|
|
||||||
|
for (std::size_t chunkStart = 0; chunkStart < p_metadatas.size(); chunkStart += maxRowsPerStatement)
|
||||||
|
{
|
||||||
|
const std::size_t chunkSize = eastl::min(maxRowsPerStatement, p_metadatas.size() - chunkStart);
|
||||||
|
|
||||||
|
eastl::string metadataPlaceholders;
|
||||||
|
metadataPlaceholders.reserve(chunkSize * 14);
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
metadataPlaceholders += ", ";
|
||||||
|
}
|
||||||
|
metadataPlaceholders += "(?, ?, ?, ?)";
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string metadataSQL = fmt::format(
|
||||||
|
"INSERT INTO AssetMetadata (UUID, Name, TypeID, TypeName) VALUES {} "
|
||||||
|
"ON CONFLICT(UUID) DO UPDATE SET Name = excluded.Name, TypeID = excluded.TypeID, TypeName = "
|
||||||
|
"excluded.TypeName;",
|
||||||
|
metadataPlaceholders);
|
||||||
|
|
||||||
|
BigFile::Request metadataRequest {*this, metadataSQL.c_str()};
|
||||||
|
std::uint32_t metadataBindIndex = 1;
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
const AssetMetadata& metadata = p_metadatas[chunkStart + i];
|
||||||
|
metadataRequest.Bind(metadataBindIndex++, metadata.m_uuid.ToBytes());
|
||||||
|
metadataRequest.Bind(metadataBindIndex++, metadata.m_name);
|
||||||
|
metadataRequest.Bind(metadataBindIndex++, metadata.m_typeID);
|
||||||
|
metadataRequest.Bind(metadataBindIndex++, metadata.m_typeName);
|
||||||
|
}
|
||||||
|
metadataRequest.Execute();
|
||||||
|
|
||||||
|
eastl::string assetPlaceholders;
|
||||||
|
assetPlaceholders.reserve(chunkSize * 8);
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
assetPlaceholders += ", ";
|
||||||
|
}
|
||||||
|
assetPlaceholders += "(?, ?)";
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string assetSQL = fmt::format(
|
||||||
|
"INSERT INTO Asset (UUID, Asset) VALUES {} ON CONFLICT(UUID) DO UPDATE SET Asset = excluded.Asset;",
|
||||||
|
assetPlaceholders);
|
||||||
|
|
||||||
|
BigFile::Request assetRequest {*this, assetSQL.c_str()};
|
||||||
|
std::uint32_t assetBindIndex = 1;
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
assetRequest.Bind(assetBindIndex++, p_metadatas[chunkStart + i].m_uuid.ToBytes());
|
||||||
|
assetRequest.Bind(assetBindIndex++, p_flatbuffers[chunkStart + i]);
|
||||||
|
}
|
||||||
|
assetRequest.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
CommitTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
bool BigFile::Has(const UUID& p_uuid) const
|
||||||
|
{
|
||||||
|
BigFile::Request request {*this, "SELECT 1 FROM AssetMetadata WHERE UUID = ?1;"};
|
||||||
|
request.Bind(1, p_uuid.ToBytes());
|
||||||
|
|
||||||
|
return request.Step();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Request(const BigFile& p_bigFile, const eastl::string_view p_request):
|
||||||
|
m_db(p_bigFile.m_db)
|
||||||
|
{
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_prepare_v2(m_db,
|
||||||
|
p_request.data(),
|
||||||
|
static_cast<std::uint32_t>(p_request.size()),
|
||||||
|
&m_statement,
|
||||||
|
nullptr);
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler,
|
||||||
|
result == SQLITE_OK,
|
||||||
|
"Failed to create statement from BigFile DB: {}",
|
||||||
|
sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::Request::Bind(const std::uint32_t p_index, const std::int32_t p_value)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
|
"Invalid index for statement");
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_bind_int(m_statement, p_index, p_value);
|
||||||
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint32_t p_value)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
|
"Invalid index for statement");
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_bind_int(m_statement, p_index, p_value);
|
||||||
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::Request::Bind(const std::uint32_t p_index, const std::int64_t p_value)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
|
"Invalid index for statement");
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_bind_int64(m_statement, p_index, p_value);
|
||||||
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint64_t p_value)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
|
"Invalid index for statement");
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_bind_int64(m_statement, p_index, std::bit_cast<std::int64_t>(p_value));
|
||||||
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::Request::Bind(const std::uint32_t p_index, const float p_value)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
|
"Invalid index for statement");
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_bind_double(m_statement, p_index, p_value);
|
||||||
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::Request::Bind(const std::uint32_t p_index, const double p_value)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
|
"Invalid index for statement");
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_bind_double(m_statement, p_index, p_value);
|
||||||
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::Request::Bind(const std::uint32_t p_index, const eastl::string_view p_value, const CopyValue p_copy)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
|
"Invalid index for statement");
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_bind_text(m_statement,
|
||||||
|
p_index,
|
||||||
|
p_value.data(),
|
||||||
|
static_cast<std::uint32_t>(p_value.size()),
|
||||||
|
p_copy ? SQLITE_TRANSIENT : SQLITE_STATIC);
|
||||||
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::Request::Bind(const std::uint32_t p_index,
|
||||||
|
const eastl::span<const std::byte> p_value,
|
||||||
|
const CopyValue p_copy)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
|
"Invalid index for statement");
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_bind_blob(m_statement,
|
||||||
|
p_index,
|
||||||
|
p_value.data(),
|
||||||
|
static_cast<std::uint32_t>(p_value.size()),
|
||||||
|
p_copy ? SQLITE_TRANSIENT : SQLITE_STATIC);
|
||||||
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
bool BigFile::Request::Step()
|
||||||
|
{
|
||||||
|
const int result = sqlite3_step(m_statement);
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
(result == SQLITE_DONE) || (result == SQLITE_ROW),
|
||||||
|
"Failed to step through the statement: {}",
|
||||||
|
sqlite3_errmsg(m_db));
|
||||||
|
|
||||||
|
return result == SQLITE_ROW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
std::uint32_t BigFile::Request::Execute()
|
||||||
|
{
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_step(m_statement);
|
||||||
|
ASSERT(EngineAssertHandler, (result == SQLITE_DONE), "Failed to execute the statement: {}", sqlite3_errmsg(m_db));
|
||||||
|
|
||||||
|
return sqlite3_changes(m_db);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Column::Column(const Request& p_request, const std::uint32_t p_index):
|
||||||
|
m_statement(p_request.m_statement),
|
||||||
|
m_index(p_index)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Column::operator std::int32_t() const
|
||||||
|
{
|
||||||
|
return sqlite3_column_int(m_statement, m_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Column::operator std::uint32_t() const
|
||||||
|
{
|
||||||
|
return sqlite3_column_int(m_statement, m_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Column::operator std::int64_t() const
|
||||||
|
{
|
||||||
|
return sqlite3_column_int64(m_statement, m_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Column::operator std::uint64_t() const
|
||||||
|
{
|
||||||
|
return std::bit_cast<std::uint64_t>(sqlite3_column_int64(m_statement, m_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Column::operator float() const
|
||||||
|
{
|
||||||
|
return static_cast<float>(sqlite3_column_double(m_statement, m_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Column::operator double() const
|
||||||
|
{
|
||||||
|
return sqlite3_column_double(m_statement, m_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Column::operator eastl::string_view() const
|
||||||
|
{
|
||||||
|
return eastl::string_view {reinterpret_cast<const char*>(sqlite3_column_text(m_statement, m_index)),
|
||||||
|
static_cast<std::size_t>(sqlite3_column_bytes(m_statement, m_index))};
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Column::operator eastl::span<const std::byte>() const
|
||||||
|
{
|
||||||
|
return eastl::span<const std::byte> {static_cast<const std::byte*>(sqlite3_column_blob(m_statement, m_index)),
|
||||||
|
static_cast<std::size_t>(sqlite3_column_bytes(m_statement, m_index))};
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Column BigFile::Request::Get(const std::uint32_t p_index) const
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
p_index < static_cast<std::uint32_t>(sqlite3_column_count(m_statement)),
|
||||||
|
"Invalid index for column!");
|
||||||
|
return {*this, p_index};
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::~Request()
|
||||||
|
{
|
||||||
|
[[maybe_unused]]
|
||||||
|
const int result = sqlite3_finalize(m_statement);
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to finalize statement: {}", sqlite3_errmsg(m_db));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace Bigfoot
|
||||||
+11
-11
@@ -2,6 +2,9 @@ PRAGMA journal_mode=WAL;
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS AssetMetadata (
|
CREATE TABLE IF NOT EXISTS AssetMetadata (
|
||||||
UUID BLOB NOT NULL,
|
UUID BLOB NOT NULL,
|
||||||
|
Name TEXT NOT NULL UNIQUE,
|
||||||
|
TypeID INTEGER NOT NULL,
|
||||||
|
TypeName TEXT NOT NULL,
|
||||||
|
|
||||||
CreateTime INTEGER NOT NULL DEFAULT(CAST(unixepoch('subsec') * 1000000 AS INTEGER)),
|
CreateTime INTEGER NOT NULL DEFAULT(CAST(unixepoch('subsec') * 1000000 AS INTEGER)),
|
||||||
ModificationTime INTEGER NOT NULL DEFAULT(CAST(unixepoch('subsec') * 1000000 AS INTEGER)),
|
ModificationTime INTEGER NOT NULL DEFAULT(CAST(unixepoch('subsec') * 1000000 AS INTEGER)),
|
||||||
@@ -9,6 +12,14 @@ CREATE TABLE IF NOT EXISTS AssetMetadata (
|
|||||||
PRIMARY KEY(UUID)
|
PRIMARY KEY(UUID)
|
||||||
) WITHOUT ROWID;
|
) WITHOUT ROWID;
|
||||||
|
|
||||||
|
CREATE TRIGGER IF NOT EXISTS AssetMetadata_UpdateTime
|
||||||
|
AFTER UPDATE OF Name, TypeID, TypeName ON AssetMetadata FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE AssetMetadata
|
||||||
|
SET ModificationTime = CAST(unixepoch('subsec') * 1000000 AS INTEGER)
|
||||||
|
WHERE UUID = NEW.UUID;
|
||||||
|
END;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS Asset (
|
CREATE TABLE IF NOT EXISTS Asset (
|
||||||
UUID BLOB NOT NULL,
|
UUID BLOB NOT NULL,
|
||||||
|
|
||||||
@@ -25,14 +36,3 @@ BEGIN
|
|||||||
SET ModificationTime = CAST(unixepoch('subsec') * 1000000 AS INTEGER)
|
SET ModificationTime = CAST(unixepoch('subsec') * 1000000 AS INTEGER)
|
||||||
WHERE UUID = NEW.UUID;
|
WHERE UUID = NEW.UUID;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS AssetHardReference (
|
|
||||||
UUID BLOB NOT NULL,
|
|
||||||
HardReference BLOB NOT NULL,
|
|
||||||
|
|
||||||
PRIMARY KEY(UUID, HardReference),
|
|
||||||
FOREIGN KEY(UUID) REFERENCES AssetMetadata(UUID)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS AssetHardReference_ReferencedUUID ON AssetHardReference(HardReference);
|
|
||||||
@@ -21,4 +21,4 @@ bigfoot_create_package_lib(
|
|||||||
"${PrivateDependencies}"
|
"${PrivateDependencies}"
|
||||||
"${BigfootPublicDependencies}"
|
"${BigfootPublicDependencies}"
|
||||||
"${BigfootPrivateDependencies}"
|
"${BigfootPrivateDependencies}"
|
||||||
"Bigfoot/Libs")
|
"")
|
||||||
+1
@@ -10,6 +10,7 @@ table AssetHeader
|
|||||||
name: string (required, id: 1);
|
name: string (required, id: 1);
|
||||||
type_id: AssetTypeID (required, native_inline, id: 2);
|
type_id: AssetTypeID (required, native_inline, id: 2);
|
||||||
type_name: string (required, id: 3);
|
type_name: string (required, id: 3);
|
||||||
|
version: uint = 0 (id: 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
table Asset
|
table Asset
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user