BigFile/Sasquatch #1
@@ -12,6 +12,7 @@
|
||||
#include <EngineBenchmarks/SasquatchInfo_generated.hpp>
|
||||
|
||||
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
||||
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred.hpp>
|
||||
|
||||
#include <EASTL/optional.h>
|
||||
#include <EASTL/vector.h>
|
||||
@@ -29,6 +30,13 @@ using Random = effolkronium::random_static;
|
||||
class SasquatchFixture: public benchmark::Fixture
|
||||
{
|
||||
protected:
|
||||
struct SasquatchData
|
||||
{
|
||||
UUID m_uuid;
|
||||
eastl::span<const std::byte> m_flatbuffer;
|
||||
eastl::span<const UUID> m_hardReferences;
|
||||
};
|
||||
|
||||
static constexpr std::uint32_t ASSET_COUNT = 20'000;
|
||||
static constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
|
||||
|
||||
@@ -37,7 +45,9 @@ class SasquatchFixture: public benchmark::Fixture
|
||||
File {SASQUATCH_ENGINEBENCHMARKS_LOCATION}.Delete();
|
||||
|
||||
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||
eastl::vector<eastl::vector<UUID>> hardReferences;
|
||||
flatbuffers.reserve(ASSET_COUNT);
|
||||
hardReferences.reserve(ASSET_COUNT);
|
||||
|
||||
m_uuids.clear();
|
||||
m_uuids.reserve(ASSET_COUNT);
|
||||
@@ -47,8 +57,17 @@ class SasquatchFixture: public benchmark::Fixture
|
||||
BenchmarkAsset asset;
|
||||
asset.SetName(asset.GetHeader().uuid.ToString().c_str());
|
||||
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||
for (std::uint32_t j = 0; j < 4; ++j)
|
||||
{
|
||||
BenchmarkAssetReferred assetReferred;
|
||||
assetReferred.SetName(assetReferred.GetHeader().uuid.ToString().c_str());
|
||||
|
||||
flatbuffers.push_back(asset.Pack());
|
||||
asset.GetAsset().refs.emplace_back(assetReferred.GetHeader().uuid);
|
||||
}
|
||||
|
||||
const eastl::vector<std::byte> flatbuffer = asset.Pack();
|
||||
flatbuffers.push_back(flatbuffer);
|
||||
hardReferences.push_back(BenchmarkAsset::GetHardReferences(flatbuffer));
|
||||
m_uuids.push_back(asset.GetHeader().uuid);
|
||||
}
|
||||
|
||||
@@ -56,20 +75,24 @@ class SasquatchFixture: public benchmark::Fixture
|
||||
assets.reserve(ASSET_COUNT);
|
||||
for (std::uint32_t i = 0; i < ASSET_COUNT; ++i)
|
||||
{
|
||||
assets.push_back(SasquatchData {.m_uuid = m_uuids[i], .m_flatbuffer = flatbuffers[i]});
|
||||
assets.push_back(SasquatchData {.m_uuid = m_uuids[i],
|
||||
.m_flatbuffer = flatbuffers[i],
|
||||
.m_hardReferences = hardReferences[i]});
|
||||
}
|
||||
|
||||
std::uint64_t totalFlatbufferBytes = 0;
|
||||
std::size_t totalFlatbufferBytes = 0;
|
||||
std::size_t totalHardReferencesBytes = 0;
|
||||
for (const SasquatchData& asset: assets)
|
||||
{
|
||||
totalFlatbufferBytes += asset.m_flatbuffer.size();
|
||||
totalHardReferencesBytes += asset.m_hardReferences.size() * UUID::UUID_BYTE_SIZE;
|
||||
}
|
||||
|
||||
{
|
||||
SasquatchWriter writer {File {SASQUATCH_ENGINEBENCHMARKS_LOCATION}, assets.size(), totalFlatbufferBytes};
|
||||
SasquatchWriter writer {File {SASQUATCH_ENGINEBENCHMARKS_LOCATION}, assets.size(), totalFlatbufferBytes, totalHardReferencesBytes};
|
||||
for (const SasquatchData& asset: assets)
|
||||
{
|
||||
writer.WriteAsset(asset.m_uuid, asset.m_flatbuffer);
|
||||
writer.WriteAsset(asset.m_uuid, asset.m_flatbuffer, asset.m_hardReferences);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +137,48 @@ class SasquatchFixture: public benchmark::Fixture
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetHardReferences)->Name("Sasquatch/GetAssetHardReferences");
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetsHardReferences)
|
||||
->Name("Sasquatch/GetAssetsHardReferences")
|
||||
->Arg(1)
|
||||
->Arg(8)
|
||||
->Arg(64)
|
||||
->Arg(512)
|
||||
->Arg(4096);
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetFlatbuffer)(benchmark::State& state)
|
||||
{
|
||||
std::int64_t bytesProcessed = 0;
|
||||
|
||||
@@ -91,14 +91,14 @@ BigFile::~BigFile()
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
eastl::optional<eastl::vector<std::byte>> BigFile::GetAssetFlatbuffer(const UUID& p_uuid) const
|
||||
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;
|
||||
return {};
|
||||
}
|
||||
|
||||
const eastl::span<const std::byte> flatbuffer = assetRequest.Get(0);
|
||||
@@ -168,7 +168,7 @@ eastl::vector<eastl::vector<std::byte>> BigFile::GetAssetFlatbuffers(const eastl
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
eastl::optional<AssetMetadata> BigFile::GetAssetMetadata(const UUID& p_uuid) const
|
||||
AssetMetadata BigFile::GetAssetMetadata(const UUID& p_uuid) const
|
||||
{
|
||||
BigFile::Request assetRequest {
|
||||
*this,
|
||||
@@ -177,7 +177,7 @@ eastl::optional<AssetMetadata> BigFile::GetAssetMetadata(const UUID& p_uuid) con
|
||||
|
||||
if (!assetRequest.Step())
|
||||
{
|
||||
return eastl::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
return AssetMetadata {.m_uuid = UUID {std::span<const std::byte, UUID::UUID_BYTE_SIZE> {
|
||||
|
||||
@@ -63,7 +63,7 @@ class BigFile: public DataAccessor
|
||||
* \param p_uuid The asset to get the flatbuffer of
|
||||
* \return The flatbuffer, or nullopt if the asset was not found
|
||||
*/
|
||||
eastl::optional<eastl::vector<std::byte>> GetAssetFlatbuffer(const UUID& p_uuid) const override;
|
||||
eastl::vector<std::byte> GetAssetFlatbuffer(const UUID& p_uuid) const override;
|
||||
|
||||
/**
|
||||
* Get several Asset flatbuffers
|
||||
@@ -79,7 +79,7 @@ class BigFile: public DataAccessor
|
||||
* \param p_uuid The asset to get the metadata of
|
||||
* \return The metadata, or nullopt if the asset was not found
|
||||
*/
|
||||
eastl::optional<AssetMetadata> GetAssetMetadata(const UUID& p_uuid) const override;
|
||||
AssetMetadata GetAssetMetadata(const UUID& p_uuid) const override;
|
||||
|
||||
/**
|
||||
* Get several Asset metadatas
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <System/Time/Time.hpp>
|
||||
#include <System/UUID/UUID.hpp>
|
||||
|
||||
#include <EASTL/optional.h>
|
||||
#include <EASTL/span.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <EASTL/vector.h>
|
||||
@@ -46,7 +45,7 @@ class DataAccessor
|
||||
* \param p_uuid The asset to get the flatbuffer of
|
||||
* \return The flatbuffer, or nullopt if the asset was not found
|
||||
*/
|
||||
virtual eastl::optional<eastl::vector<std::byte>> GetAssetFlatbuffer(const UUID& p_uuid) const = 0;
|
||||
virtual eastl::vector<std::byte> GetAssetFlatbuffer(const UUID& p_uuid) const = 0;
|
||||
|
||||
/**
|
||||
* Get several Asset flatbuffers
|
||||
@@ -62,7 +61,7 @@ class DataAccessor
|
||||
* \param p_uuid The asset to get the metadata of
|
||||
* \return The metadata, or nullopt if the asset was not found
|
||||
*/
|
||||
virtual eastl::optional<AssetMetadata> GetAssetMetadata(const UUID& p_uuid) const = 0;
|
||||
virtual AssetMetadata GetAssetMetadata(const UUID& p_uuid) const = 0;
|
||||
|
||||
/**
|
||||
* Get several Asset metadatas
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <EASTL/vector.h>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
@@ -35,7 +34,6 @@ struct SasquatchHeader
|
||||
std::uint64_t m_assetCount = 0;
|
||||
};
|
||||
|
||||
static_assert(sizeof(SasquatchHeader) == 16);
|
||||
static_assert(std::is_trivially_copyable_v<SasquatchHeader>);
|
||||
|
||||
/****************************************************************************************/
|
||||
@@ -43,22 +41,19 @@ static_assert(std::is_trivially_copyable_v<SasquatchHeader>);
|
||||
struct SasquatchEntry
|
||||
{
|
||||
std::array<std::byte, UUID::UUID_BYTE_SIZE> m_uuid {};
|
||||
std::size_t m_offset = 0;
|
||||
std::size_t m_size = 0;
|
||||
|
||||
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(sizeof(SasquatchEntry) == 32);
|
||||
static_assert(std::is_trivially_copyable_v<SasquatchEntry>);
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
#if defined(BIGFOOT_TOOLMODE) || defined(BIGFOOT_BUILD_TESTS) || defined(BIGFOOT_BUILD_BENCHMARKS)
|
||||
struct SasquatchData
|
||||
{
|
||||
UUID m_uuid;
|
||||
eastl::span<const std::byte> m_flatbuffer;
|
||||
};
|
||||
|
||||
class SasquatchWriter
|
||||
{
|
||||
public:
|
||||
@@ -69,8 +64,12 @@ class SasquatchWriter
|
||||
* \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, std::uint64_t p_assetCount, std::size_t p_totalFlatbufferBytes);
|
||||
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;
|
||||
@@ -88,7 +87,9 @@ class SasquatchWriter
|
||||
* \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);
|
||||
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;
|
||||
@@ -99,12 +100,7 @@ class SasquatchWriter
|
||||
/**
|
||||
* The number of assets expected
|
||||
*/
|
||||
BIGFOOT_NOT_OPTIMIZED_ONLY(std::uint64_t m_assetCount;)
|
||||
|
||||
/**
|
||||
* The offset the next WriteAsset call will write to
|
||||
*/
|
||||
std::size_t m_nextOffset;
|
||||
std::uint64_t m_assetCount;
|
||||
|
||||
/**
|
||||
* How far into m_file has already been prefetched
|
||||
@@ -147,7 +143,7 @@ class Sasquatch: public DataAccessor
|
||||
* \param p_uuid The asset to get the flatbuffer of
|
||||
* \return The flatbuffer, or nullopt if the asset was not found
|
||||
*/
|
||||
eastl::optional<eastl::vector<std::byte>> GetAssetFlatbuffer(const UUID& p_uuid) const override;
|
||||
eastl::vector<std::byte> GetAssetFlatbuffer(const UUID& p_uuid) const override;
|
||||
|
||||
/**
|
||||
* Get several Asset flatbuffers
|
||||
@@ -161,7 +157,7 @@ class Sasquatch: public DataAccessor
|
||||
* Sasquatch only serves flatbuffers: this will always fail
|
||||
*
|
||||
*/
|
||||
eastl::optional<AssetMetadata> GetAssetMetadata(const UUID& p_uuid) const override;
|
||||
AssetMetadata GetAssetMetadata(const UUID& p_uuid) const override;
|
||||
|
||||
/**
|
||||
* Sasquatch only serves flatbuffers: this will always fail
|
||||
@@ -169,6 +165,22 @@ class Sasquatch: public DataAccessor
|
||||
*/
|
||||
eastl::vector<AssetMetadata> GetAssetMetadatas(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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
eastl::vector<eastl::vector<UUID>> GetAssetsHardReferences(eastl::span<const UUID> p_uuids) const override;
|
||||
|
||||
/**
|
||||
* Sasquatch is read-only: this will always fail
|
||||
*
|
||||
@@ -199,8 +211,11 @@ class Sasquatch: public DataAccessor
|
||||
private:
|
||||
struct Entry
|
||||
{
|
||||
std::size_t m_offset;
|
||||
std::size_t m_size;
|
||||
std::size_t m_assetOffset = 0;
|
||||
std::size_t m_assetSize = 0;
|
||||
|
||||
std::size_t m_hardReferencesOffset = 0;
|
||||
std::size_t m_hardReferencesSize = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,16 +16,18 @@ 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):
|
||||
BIGFOOT_NOT_OPTIMIZED_ONLY(m_assetCount(p_assetCount), )
|
||||
m_nextOffset(sizeof(SasquatchHeader) + p_assetCount * sizeof(SasquatchEntry)),
|
||||
const std::size_t p_totalFlatbufferBytes,
|
||||
const std::size_t p_totalHardReferencesBytes):
|
||||
m_assetCount(p_assetCount),
|
||||
m_prefetchedUpTo(0),
|
||||
m_file(p_file, m_nextOffset + p_totalFlatbufferBytes)
|
||||
m_file(p_file,
|
||||
sizeof(SasquatchHeader) + m_assetCount * sizeof(SasquatchEntry) + p_totalFlatbufferBytes +
|
||||
p_totalHardReferencesBytes)
|
||||
{
|
||||
m_entries.reserve(p_assetCount);
|
||||
m_entries.reserve(m_assetCount);
|
||||
|
||||
SasquatchHeader header;
|
||||
header.m_assetCount = p_assetCount;
|
||||
header.m_assetCount = m_assetCount;
|
||||
|
||||
std::memcpy(m_file.GetData().data(), &header, sizeof(SasquatchHeader));
|
||||
}
|
||||
@@ -52,20 +54,30 @@ SasquatchWriter::~SasquatchWriter()
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
void SasquatchWriter::WriteAsset(const UUID& p_uuid, const eastl::span<const std::byte> p_flatbuffer)
|
||||
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 = std::accumulate(m_entries.begin(),
|
||||
m_entries.end(),
|
||||
sizeof(SasquatchHeader) + m_assetCount * sizeof(SasquatchEntry),
|
||||
[](const std::size_t p_value, const SasquatchEntry& p_entry)
|
||||
{
|
||||
return p_value + p_entry.m_assetSize + p_entry.m_hardReferencesSize;
|
||||
});
|
||||
|
||||
const eastl::span<std::byte> data = m_file.GetData();
|
||||
ASSERT(EngineAssertHandler,
|
||||
m_nextOffset + p_flatbuffer.size() <= data.size(),
|
||||
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 = m_nextOffset + p_flatbuffer.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());
|
||||
@@ -75,12 +87,22 @@ void SasquatchWriter::WriteAsset(const UUID& p_uuid, const eastl::span<const std
|
||||
|
||||
SasquatchEntry entry;
|
||||
std::memcpy(entry.m_uuid.data(), p_uuid.ToBytes().data(), UUID::UUID_BYTE_SIZE);
|
||||
entry.m_offset = m_nextOffset;
|
||||
entry.m_size = p_flatbuffer.size();
|
||||
m_entries.push_back(entry);
|
||||
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() + m_nextOffset, p_flatbuffer.data(), p_flatbuffer.size());
|
||||
m_nextOffset += entry.m_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 + i * UUID::UUID_BYTE_SIZE,
|
||||
rawUUID.data(),
|
||||
UUID::UUID_BYTE_SIZE);
|
||||
}
|
||||
|
||||
m_entries.push_back(entry);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -130,27 +152,31 @@ Sasquatch::Sasquatch(const File& p_file):
|
||||
for (const SasquatchEntry& entry: entries)
|
||||
{
|
||||
CRITICAL_ASSERT(EngineAssertHandler,
|
||||
entry.m_offset + entry.m_size <= data.size(),
|
||||
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_offset = entry.m_offset, .m_size = entry.m_size});
|
||||
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});
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
eastl::optional<eastl::vector<std::byte>> Sasquatch::GetAssetFlatbuffer(const UUID& p_uuid) const
|
||||
eastl::vector<std::byte> Sasquatch::GetAssetFlatbuffer(const UUID& p_uuid) const
|
||||
{
|
||||
const auto it = m_entries.find(p_uuid);
|
||||
if (it == m_entries.end())
|
||||
{
|
||||
return eastl::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
const eastl::span<const std::byte> data = m_file.GetData();
|
||||
const eastl::span<const std::byte> bytes {data.data() + it->second.m_offset,
|
||||
static_cast<std::size_t>(it->second.m_size)};
|
||||
const eastl::span<const std::byte> bytes {data.data() + it->second.m_assetOffset,
|
||||
static_cast<std::size_t>(it->second.m_assetSize)};
|
||||
return eastl::vector<std::byte> {bytes.begin(), bytes.end()};
|
||||
}
|
||||
|
||||
@@ -159,40 +185,11 @@ eastl::optional<eastl::vector<std::byte>> Sasquatch::GetAssetFlatbuffer(const UU
|
||||
eastl::vector<eastl::vector<std::byte>> Sasquatch::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)
|
||||
for (const UUID& uuid : p_uuids)
|
||||
{
|
||||
if (eastl::optional<eastl::vector<std::byte>> flatbuffer = GetAssetFlatbuffer(p_uuids[0]);
|
||||
flatbuffer.has_value())
|
||||
{
|
||||
flatbuffers.push_back(std::move(*flatbuffer));
|
||||
}
|
||||
|
||||
return flatbuffers;
|
||||
}
|
||||
|
||||
ankerl::unordered_dense::set<UUID> seen;
|
||||
seen.reserve(p_uuids.size());
|
||||
for (const UUID& uuid: p_uuids)
|
||||
{
|
||||
if (!seen.insert(uuid).second)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const auto it = m_entries.find(uuid); it != m_entries.end())
|
||||
{
|
||||
const eastl::span<const std::byte> data = m_file.GetData();
|
||||
const eastl::span<const std::byte> bytes {data.data() + it->second.m_offset,
|
||||
static_cast<std::size_t>(it->second.m_size)};
|
||||
flatbuffers.emplace_back(bytes.begin(), bytes.end());
|
||||
}
|
||||
flatbuffers.push_back(GetAssetFlatbuffer(uuid));
|
||||
}
|
||||
|
||||
return flatbuffers;
|
||||
@@ -200,10 +197,10 @@ eastl::vector<eastl::vector<std::byte>> Sasquatch::GetAssetFlatbuffers(const eas
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
eastl::optional<AssetMetadata> Sasquatch::GetAssetMetadata([[maybe_unused]] const UUID& p_uuid) const
|
||||
AssetMetadata Sasquatch::GetAssetMetadata([[maybe_unused]] const UUID& p_uuid) const
|
||||
{
|
||||
ASSERT(EngineAssertHandler, false, "Sasquatch does not support metadata queries, only flatbuffers");
|
||||
return eastl::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
@@ -211,7 +208,51 @@ eastl::optional<AssetMetadata> Sasquatch::GetAssetMetadata([[maybe_unused]] cons
|
||||
eastl::vector<AssetMetadata> Sasquatch::GetAssetMetadatas([[maybe_unused]] const eastl::span<const UUID> p_uuids) const
|
||||
{
|
||||
ASSERT(EngineAssertHandler, false, "Sasquatch does not support metadata queries, only flatbuffers");
|
||||
return {};
|
||||
return eastl::vector<AssetMetadata>{p_uuids.size()};
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
eastl::vector<UUID> Sasquatch::GetAssetHardReferences(const UUID& p_uuid) const
|
||||
{
|
||||
eastl::vector<UUID> hardReferences;
|
||||
|
||||
const auto it = m_entries.find(p_uuid);
|
||||
if (it == m_entries.end())
|
||||
{
|
||||
return hardReferences;
|
||||
}
|
||||
|
||||
const eastl::span<const std::byte> data = m_file.GetData();
|
||||
const eastl::span<const std::byte> bytes {data.data() + it->second.m_hardReferencesOffset,
|
||||
static_cast<std::size_t>(it->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;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
@@ -32,23 +32,33 @@ void Bake(const BigFile& p_bigFile, const File& p_outputFile)
|
||||
totalFlatbufferBytes = sizeRequest.Get(0);
|
||||
}
|
||||
|
||||
SasquatchWriter writer {p_outputFile, assetCount, totalFlatbufferBytes};
|
||||
std::uint64_t totalHardReferencesBytes = 0;
|
||||
{
|
||||
BigFile::Request sizeRequest {p_bigFile, "SELECT COALESCE(SUM(LENGTH(AssetHardReference)), 0) FROM AssetHardReference;"};
|
||||
[[maybe_unused]]
|
||||
const bool hasSize = sizeRequest.Step();
|
||||
ASSERT(SasquatchBakerAssertHandler, hasSize, "Failed to sum the hardreferences sizes of the BigFile");
|
||||
totalFlatbufferBytes = sizeRequest.Get(0);
|
||||
}
|
||||
|
||||
BigFile::Request request {p_bigFile, "SELECT UUID, Asset FROM Asset;"};
|
||||
SasquatchWriter writer {p_outputFile, assetCount, totalFlatbufferBytes, totalHardReferencesBytes};
|
||||
|
||||
BigFile::Request request {p_bigFile, "SELECT UUID FROM Asset;"};
|
||||
while (request.Step())
|
||||
{
|
||||
const eastl::span<const std::byte> uuidBytes = request.Get(0);
|
||||
const eastl::span<const std::byte> flatbuffer = request.Get(1);
|
||||
|
||||
const eastl::span<const std::byte> rawUUID = request.Get(0);
|
||||
|
||||
ASSERT(SasquatchBakerAssertHandler,
|
||||
uuidBytes.size() == UUID::UUID_BYTE_SIZE,
|
||||
rawUUID.size() == UUID::UUID_BYTE_SIZE,
|
||||
"Unexpected UUID blob size in BigFile (got {} / expected {})",
|
||||
uuidBytes.size(),
|
||||
rawUUID.size(),
|
||||
UUID::UUID_BYTE_SIZE);
|
||||
|
||||
writer.WriteAsset(
|
||||
UUID {{std::span<const std::byte, UUID::UUID_BYTE_SIZE> {uuidBytes.data(), UUID::UUID_BYTE_SIZE}}},
|
||||
flatbuffer);
|
||||
const UUID uuid {std::span<const std::byte, UUID::UUID_BYTE_SIZE> {rawUUID.data(), UUID::UUID_BYTE_SIZE}};
|
||||
const eastl::vector<std::byte> flatbuffer = p_bigFile.GetAssetFlatbuffer(uuid);
|
||||
const eastl::vector<UUID> hardReferences = p_bigFile.GetAssetHardReferences(uuid);
|
||||
|
||||
writer.WriteAsset(uuid, flatbuffer, hardReferences);
|
||||
}
|
||||
}
|
||||
} // namespace Bigfoot
|
||||
|
||||
@@ -68,22 +68,22 @@ TEST_F(BigFileFixture, Clear_ShouldRemoveAllAssetsMetadataAndHardReferences)
|
||||
EXPECT_FALSE(m_bigFile.Has(referencedAsset.GetHeader().uuid));
|
||||
EXPECT_FALSE(m_bigFile.Has(asset.GetHeader().uuid));
|
||||
|
||||
EXPECT_FALSE(m_bigFile.GetAssetMetadata(referencedAsset.GetHeader().uuid).has_value());
|
||||
EXPECT_FALSE(m_bigFile.GetAssetMetadata(asset.GetHeader().uuid).has_value());
|
||||
EXPECT_EQ(m_bigFile.GetAssetMetadata(referencedAsset.GetHeader().uuid).m_uuid, UUID::NULL_UUID);
|
||||
EXPECT_EQ(m_bigFile.GetAssetMetadata(asset.GetHeader().uuid).m_uuid, UUID::NULL_UUID);
|
||||
|
||||
EXPECT_FALSE(m_bigFile.GetAssetFlatbuffer(referencedAsset.GetHeader().uuid).has_value());
|
||||
EXPECT_FALSE(m_bigFile.GetAssetFlatbuffer(asset.GetHeader().uuid).has_value());
|
||||
EXPECT_TRUE(m_bigFile.GetAssetFlatbuffer(referencedAsset.GetHeader().uuid).empty());
|
||||
EXPECT_TRUE(m_bigFile.GetAssetFlatbuffer(asset.GetHeader().uuid).empty());
|
||||
|
||||
EXPECT_TRUE(m_bigFile.GetAssetHardReferences(asset.GetHeader().uuid).empty());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(BigFileFixture, GetAssetFlatbuffer_ShouldReturnNulloptForNonExistentUUID)
|
||||
TEST_F(BigFileFixture, GetAssetFlatbuffer_ShouldReturnEmptyForNonExistentUUID)
|
||||
{
|
||||
const UUID uuid;
|
||||
|
||||
EXPECT_FALSE(m_bigFile.GetAssetFlatbuffer(uuid).has_value());
|
||||
EXPECT_TRUE(m_bigFile.GetAssetFlatbuffer(uuid).empty());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
@@ -166,11 +166,11 @@ TEST_F(BigFileFixture, GetAssetFlatbuffers_ShouldNotDuplicateResultsForADuplicat
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(BigFileFixture, GetAssetMetadata_ShouldReturnNulloptForNonExistentUUID)
|
||||
TEST_F(BigFileFixture, GetAssetMetadata_ShouldReturnNullForNonExistentUUID)
|
||||
{
|
||||
const UUID uuid;
|
||||
|
||||
EXPECT_FALSE(m_bigFile.GetAssetMetadata(uuid).has_value());
|
||||
EXPECT_EQ(m_bigFile.GetAssetMetadata(uuid).m_uuid, UUID::NULL_UUID);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
@@ -17,7 +17,7 @@ class DataAccessorFixture: public ::testing::Test
|
||||
class DataAccessorMock: public DataAccessor
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD(eastl::optional<eastl::vector<std::byte>>,
|
||||
MOCK_METHOD(eastl::vector<std::byte>,
|
||||
GetAssetFlatbuffer,
|
||||
(const UUID& p_uuid),
|
||||
(const, override));
|
||||
@@ -25,7 +25,7 @@ class DataAccessorFixture: public ::testing::Test
|
||||
GetAssetFlatbuffers,
|
||||
(eastl::span<const UUID> p_uuids),
|
||||
(const, override));
|
||||
MOCK_METHOD(eastl::optional<AssetMetadata>, GetAssetMetadata, (const UUID& p_uuid), (const, override));
|
||||
MOCK_METHOD(AssetMetadata, GetAssetMetadata, (const UUID& p_uuid), (const, override));
|
||||
MOCK_METHOD(eastl::vector<AssetMetadata>,
|
||||
GetAssetMetadatas,
|
||||
(eastl::span<const UUID> p_uuids),
|
||||
|
||||
@@ -21,6 +21,13 @@ namespace Bigfoot
|
||||
class SasquatchFixture: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
struct SasquatchData
|
||||
{
|
||||
UUID m_uuid;
|
||||
eastl::span<const std::byte> m_flatbuffer;
|
||||
eastl::vector<UUID> m_hardReferences;
|
||||
};
|
||||
|
||||
void SetUp()
|
||||
{
|
||||
File {SASQUATCH_ENGINETESTS_LOCATION}.Delete();
|
||||
@@ -29,23 +36,30 @@ class SasquatchFixture: public ::testing::Test
|
||||
m_flatbufferA = m_assetA.Pack();
|
||||
|
||||
m_assetB.SetName("world");
|
||||
m_assetB.GetAsset().ref_a = HardReference<AssetA> {m_assetA.GetHeader().uuid};
|
||||
m_flatbufferB = m_assetB.Pack();
|
||||
|
||||
const eastl::vector<SasquatchData> assets {
|
||||
SasquatchData {.m_uuid = m_assetA.GetHeader().uuid, .m_flatbuffer = m_flatbufferA},
|
||||
SasquatchData {.m_uuid = m_assetB.GetHeader().uuid, .m_flatbuffer = m_flatbufferB}};
|
||||
SasquatchData {.m_uuid = m_assetA.GetHeader().uuid,
|
||||
.m_flatbuffer = m_flatbufferA,
|
||||
.m_hardReferences = AssetA::GetHardReferences(m_flatbufferA)},
|
||||
SasquatchData {.m_uuid = m_assetB.GetHeader().uuid,
|
||||
.m_flatbuffer = m_flatbufferB,
|
||||
.m_hardReferences = AssetB::GetHardReferences(m_flatbufferB)}};
|
||||
|
||||
std::uint64_t totalFlatbufferBytes = 0;
|
||||
std::size_t totalHardReferencesBytes = 0;
|
||||
for (const SasquatchData& asset: assets)
|
||||
{
|
||||
totalFlatbufferBytes += asset.m_flatbuffer.size();
|
||||
totalFlatbufferBytes += asset.m_hardReferences.size() * UUID::UUID_BYTE_SIZE;
|
||||
}
|
||||
|
||||
{
|
||||
SasquatchWriter writer {File {SASQUATCH_ENGINETESTS_LOCATION}, assets.size(), totalFlatbufferBytes};
|
||||
SasquatchWriter writer {File {SASQUATCH_ENGINETESTS_LOCATION}, assets.size(), totalFlatbufferBytes, totalHardReferencesBytes};
|
||||
for (const SasquatchData& asset: assets)
|
||||
{
|
||||
writer.WriteAsset(asset.m_uuid, asset.m_flatbuffer);
|
||||
writer.WriteAsset(asset.m_uuid, asset.m_flatbuffer, asset.m_hardReferences);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,42 +77,96 @@ class SasquatchFixture: public ::testing::Test
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(SasquatchFixture, GetAssetFlatbuffer_ShouldReturnNulloptForNonExistentUUID)
|
||||
TEST_F(SasquatchFixture, GetAssetHardReference_ShouldReturnEmptyVectorForNonExistentUUID)
|
||||
{
|
||||
EXPECT_FALSE(m_sasquatch->GetAssetFlatbuffer(UUID {}).has_value());
|
||||
const UUID uuid;
|
||||
|
||||
const eastl::vector<UUID> hardReferences = m_sasquatch->GetAssetHardReferences(uuid);
|
||||
|
||||
EXPECT_TRUE(hardReferences.empty());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(SasquatchFixture, GetAssetHardReference_ShouldGetTheAssetHardReferences)
|
||||
{
|
||||
const eastl::vector<UUID> hardReferences = m_sasquatch->GetAssetHardReferences(m_assetB.GetHeader().uuid);
|
||||
|
||||
ASSERT_EQ(hardReferences.size(), 1);
|
||||
EXPECT_TRUE(std::find(hardReferences.begin(), hardReferences.end(), m_assetA.GetHeader().uuid) !=
|
||||
hardReferences.end());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(SasquatchFixture, GetAssetHardReferences_ShouldReturnEmptyVectorsForUUIDsThatDoNotExistOrHaveNoReferences)
|
||||
{
|
||||
const UUID missingUUID;
|
||||
const eastl::array<UUID, 2> uuids {missingUUID,
|
||||
m_assetB.GetHeader().uuid};
|
||||
|
||||
const eastl::vector<eastl::vector<UUID>> hardReferences = m_sasquatch->GetAssetsHardReferences(uuids);
|
||||
|
||||
ASSERT_EQ(hardReferences.size(), 2);
|
||||
EXPECT_TRUE(hardReferences[0].empty());
|
||||
EXPECT_EQ(hardReferences[1][0], m_assetA.GetHeader().uuid);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(SasquatchFixture, GetAssetHardReferences_ShouldDuplicateResultsForADuplicateUUID)
|
||||
{
|
||||
const eastl::array<UUID, 2> uuids {m_assetB.GetHeader().uuid, m_assetB.GetHeader().uuid};
|
||||
|
||||
const eastl::vector<eastl::vector<UUID>> hardReferences = m_sasquatch->GetAssetsHardReferences(uuids);
|
||||
|
||||
ASSERT_EQ(hardReferences.size(), 2);
|
||||
for (const eastl::vector<UUID>& entry: hardReferences)
|
||||
{
|
||||
ASSERT_EQ(entry.size(), 1);
|
||||
EXPECT_TRUE(std::find(entry.begin(), entry.end(), m_assetA.GetHeader().uuid) != entry.end());
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(SasquatchFixture, GetAssetFlatbuffer_ShouldReturnEmptyForNonExistentUUID)
|
||||
{
|
||||
EXPECT_TRUE(m_sasquatch->GetAssetFlatbuffer(UUID {}).empty());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(SasquatchFixture, GetAssetFlatbuffer_ShouldGetTheAssetFlatbuffer)
|
||||
{
|
||||
const eastl::optional<eastl::vector<std::byte>> savedFlatbuffer = m_sasquatch->GetAssetFlatbuffer(
|
||||
const eastl::vector<std::byte> savedFlatbuffer = m_sasquatch->GetAssetFlatbuffer(
|
||||
m_assetA.GetHeader().uuid);
|
||||
ASSERT_TRUE(savedFlatbuffer.has_value());
|
||||
EXPECT_EQ(*savedFlatbuffer, m_flatbufferA);
|
||||
EXPECT_EQ(savedFlatbuffer, m_flatbufferA);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(SasquatchFixture, GetAssetFlatbuffers_ShouldOmitUUIDsThatDoNotExist)
|
||||
TEST_F(SasquatchFixture, GetAssetFlatbuffers_ShouldReturnEmptyForNonExistentUUID)
|
||||
{
|
||||
const eastl::vector<UUID> uuids {m_assetA.GetHeader().uuid, UUID {}, m_assetB.GetHeader().uuid};
|
||||
const eastl::vector<eastl::vector<std::byte>> flatbuffers = m_sasquatch->GetAssetFlatbuffers(uuids);
|
||||
|
||||
ASSERT_EQ(flatbuffers.size(), 2);
|
||||
EXPECT_TRUE((flatbuffers[0] == m_flatbufferA && flatbuffers[1] == m_flatbufferB) ||
|
||||
(flatbuffers[0] == m_flatbufferB && flatbuffers[1] == m_flatbufferA));
|
||||
ASSERT_EQ(flatbuffers.size(), 3);
|
||||
EXPECT_EQ(flatbuffers[0], m_flatbufferA);
|
||||
EXPECT_TRUE(flatbuffers[1].empty());
|
||||
EXPECT_EQ(flatbuffers[2], m_flatbufferB);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(SasquatchFixture, GetAssetFlatbuffers_ShouldNotDuplicateResultsForADuplicateUUID)
|
||||
TEST_F(SasquatchFixture, GetAssetFlatbuffers_ShouldDuplicateResultsForADuplicateUUID)
|
||||
{
|
||||
const eastl::vector<UUID> uuids {m_assetA.GetHeader().uuid, m_assetA.GetHeader().uuid};
|
||||
const eastl::vector<eastl::vector<std::byte>> flatbuffers = m_sasquatch->GetAssetFlatbuffers(uuids);
|
||||
|
||||
ASSERT_EQ(flatbuffers.size(), 1);
|
||||
ASSERT_EQ(flatbuffers.size(), 2);
|
||||
EXPECT_EQ(flatbuffers[0], m_flatbufferA);
|
||||
EXPECT_EQ(flatbuffers[1], m_flatbufferA);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
@@ -96,8 +96,9 @@ TEST_F(SasquatchBakerFixture, Bake_ShouldWriteEveryAssetOfTheBigFile)
|
||||
flatbufferA,
|
||||
AssetA::GetHardReferences(flatbufferA));
|
||||
|
||||
AssetA assetB;
|
||||
AssetB assetB;
|
||||
assetB.SetName("world");
|
||||
assetB.GetAsset().ref_a = HardReference<AssetA> {assetA.GetHeader().uuid};
|
||||
|
||||
const eastl::vector<std::byte> flatbufferB = assetB.Pack();
|
||||
|
||||
@@ -106,7 +107,7 @@ TEST_F(SasquatchBakerFixture, Bake_ShouldWriteEveryAssetOfTheBigFile)
|
||||
.m_typeID = assetB.GetHeader().type_id,
|
||||
.m_typeName = assetB.GetHeader().type_name},
|
||||
flatbufferB,
|
||||
AssetA::GetHardReferences(flatbufferB));
|
||||
AssetB::GetHardReferences(flatbufferB));
|
||||
|
||||
Bake(m_bigFile, m_sasquatch);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user