Merge remote-tracking branch 'origin/master' into
feature/BinSearchArrayMap
This commit is contained in:
1
3rdParty/msdf/CMakeLists.txt
vendored
1
3rdParty/msdf/CMakeLists.txt
vendored
@@ -93,6 +93,7 @@ function(LinkMsdf TARGET)
|
||||
if (FREETYPE_BUILT_FROM_SOURCES)
|
||||
target_include_directories(${TARGET} PUBLIC ${FREETYPE_INCLUDE_DIR})
|
||||
else()
|
||||
find_package(Freetype REQUIRED)
|
||||
target_include_directories(${TARGET} PUBLIC ${FREETYPE_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
17
3rdParty/opencv/CMakeLists.txt
vendored
17
3rdParty/opencv/CMakeLists.txt
vendored
@@ -1,17 +0,0 @@
|
||||
Find_Package(OpenCV)
|
||||
include(FetchContent)
|
||||
|
||||
if(NOT DEFINED OPENCV_REPO)
|
||||
set(OPENCV_REPO https://github.com/opencv/opencv.git)
|
||||
endif ()
|
||||
|
||||
if (NOT OpenCV_FOUND)
|
||||
FetchContent_Declare(
|
||||
opencv
|
||||
EXCLUDE_FROM_ALL
|
||||
GIT_REPOSITORY ${OPENCV_REPO}
|
||||
GIT_TAG v4.8.1
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(opencv)
|
||||
endif()
|
||||
7
3rdParty/tinyusdz/CMakeLists.txt
vendored
7
3rdParty/tinyusdz/CMakeLists.txt
vendored
@@ -18,6 +18,13 @@ FetchContent_Declare(
|
||||
-DTINYUSDZ_BUILD_TESTS:BOOL=OFF
|
||||
-DTINYUSDZ_BUILD_EXAMPLES:BOOL=OFF
|
||||
)
|
||||
|
||||
set(TINYUSDZ_NO_WERROR ON)
|
||||
set(TINYUSDZ_BUILD_TESTS OFF)
|
||||
set(TINYUSDZ_BUILD_BENCHMARKS OFF)
|
||||
set(TINYUSDZ_BUILD_EXAMPLES OFF)
|
||||
set(TINYUSDZ_WITH_BUILTIN_IMAGE_LOADER OFF)
|
||||
|
||||
FetchContent_MakeAvailable(tinyusdz)
|
||||
|
||||
function (LinkTinyUSDZ TARGET)
|
||||
|
||||
@@ -109,6 +109,7 @@ namespace OpenVulkano::AR
|
||||
}
|
||||
}
|
||||
tjFree(outBuffer);
|
||||
tjDestroy(handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace OpenVulkano
|
||||
EngineConfiguration::EngineConfiguration()
|
||||
{
|
||||
const std::string filePath = (AppFolders::GetAppConfigHomeDir() / "EngineConfig.yml").string();
|
||||
Array<char> fileContents = Utils::ReadFile(filePath, true);
|
||||
Array<char> fileContents = Utils::ReadFile(filePath, true, true);
|
||||
if(fileContents.Size() == 0)
|
||||
return;
|
||||
|
||||
|
||||
@@ -167,6 +167,12 @@ namespace OpenVulkano
|
||||
|
||||
bool HasRenderResource() const { return renderResource; }
|
||||
|
||||
RenderResourceHolder& operator =(const RenderResourceHolder& copy) noexcept
|
||||
{
|
||||
renderResource.Release();
|
||||
return *this;
|
||||
}
|
||||
|
||||
RenderResourceHolder& operator =(RenderResourceHolder&& move) noexcept
|
||||
{
|
||||
renderResource = std::move(move.renderResource);
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace OpenVulkano
|
||||
if (GetCamera()->IsOrtho())
|
||||
{
|
||||
HandleMovementOrtho();
|
||||
if (GetCamera()->GetZoom() > 50)
|
||||
/*if (GetCamera()->GetZoom() > 50)
|
||||
{
|
||||
float nDist = std::max<float>(((ZOOM_RANGE - sqrt(GetCamera()->GetZoom())) / ZOOM_RANGE) * m_distance, 0.1f);
|
||||
if (nDist != m_frameDistance)
|
||||
@@ -116,7 +116,7 @@ namespace OpenVulkano
|
||||
m_distUpated = true;
|
||||
m_frameDistance = nDist;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
464
openVulkanoCpp/Data/Containers/StableVector.hpp
Normal file
464
openVulkanoCpp/Data/Containers/StableVector.hpp
Normal file
@@ -0,0 +1,464 @@
|
||||
#pragma once
|
||||
|
||||
#include "Base/Wrapper.hpp"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4200)
|
||||
#pragma warning(disable : 6011)
|
||||
#pragma warning(disable : 6386)
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
/**
|
||||
* @class Stable Vector
|
||||
* @brief Stable Vector is an alternative version for std::vector that provides chunk based memory allocation without re-aligning
|
||||
*
|
||||
* @throw Please know that this vector creates array gaps when you remove an element.
|
||||
*/
|
||||
template<typename T, size_t DEFAULT_CHUNK_SIZE = 32, int GROWTH_FACTOR = 2> class StableVector
|
||||
{
|
||||
struct VectorChunk
|
||||
{
|
||||
VectorChunk* m_prev = nullptr;
|
||||
VectorChunk* m_next = nullptr;
|
||||
size_t m_chunkSize;
|
||||
int64_t m_lastUsedIndex;
|
||||
bool* m_fill;
|
||||
T m_data[0];
|
||||
|
||||
VectorChunk(size_t size) : m_chunkSize(size), m_lastUsedIndex(-1)
|
||||
{
|
||||
m_fill = reinterpret_cast<bool*>(m_data + size);
|
||||
memset(m_fill, 0, size * sizeof(bool));
|
||||
}
|
||||
|
||||
~VectorChunk()
|
||||
{
|
||||
for (size_t i = 0; i < m_chunkSize; i++)
|
||||
{
|
||||
if (m_fill[i])
|
||||
{
|
||||
m_data[i].~T();
|
||||
}
|
||||
}
|
||||
m_prev = nullptr;
|
||||
m_next = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(VectorChunk* ptr, size_t index = 0) : m_ptr(ptr), m_index(index) {}
|
||||
|
||||
T& operator*() { return m_ptr->m_data[m_index]; }
|
||||
T* operator->() { return &m_ptr->m_data[m_index]; }
|
||||
|
||||
Iterator operator++()
|
||||
{
|
||||
++m_index;
|
||||
MovetoNextValidChunk();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int)
|
||||
{
|
||||
Iterator temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool operator==(const Iterator& other) const { return m_ptr == other.m_ptr && m_index == other.m_index; }
|
||||
bool operator!=(const Iterator& other) const { return !(*this == other); }
|
||||
|
||||
private:
|
||||
void MovetoNextValidChunk()
|
||||
{
|
||||
while (m_ptr && (m_index > m_ptr->m_chunkSize || !m_ptr->m_fill[m_index]))
|
||||
{
|
||||
if (m_index >= m_ptr->m_chunkSize)
|
||||
{
|
||||
m_ptr = m_ptr->m_next;
|
||||
m_index = 0;
|
||||
}
|
||||
else ++m_index;
|
||||
}
|
||||
|
||||
if (m_ptr && m_index >= m_ptr->m_chunkSize)
|
||||
{
|
||||
m_ptr = m_ptr->m_next;
|
||||
m_index = 0;
|
||||
MovetoNextValidChunk();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
VectorChunk* m_ptr;
|
||||
size_t m_index;
|
||||
};
|
||||
|
||||
public:
|
||||
StableVector() : m_firstChunk(nullptr), m_lastChunk(nullptr)
|
||||
{
|
||||
VectorChunk* chunk = SpawnChunk(DEFAULT_CHUNK_SIZE);
|
||||
m_firstChunk = chunk;
|
||||
m_lastChunk = chunk;
|
||||
m_currentSize = 0;
|
||||
m_totalCap = DEFAULT_CHUNK_SIZE;
|
||||
}
|
||||
|
||||
StableVector(const StableVector<T>& copy)
|
||||
{
|
||||
m_firstChunk = nullptr;
|
||||
m_lastChunk = nullptr;
|
||||
m_currentSize = 0;
|
||||
m_totalCap = 0;
|
||||
|
||||
VectorChunk* currentChunk = copy.m_firstChunk;
|
||||
while (currentChunk)
|
||||
{
|
||||
for (size_t i = 0; i < currentChunk->m_chunkSize; i++)
|
||||
{
|
||||
if (currentChunk->m_fill[i]) { PushBack(currentChunk->m_data[i]); }
|
||||
}
|
||||
|
||||
currentChunk = currentChunk->m_next;
|
||||
}
|
||||
}
|
||||
|
||||
StableVector(StableVector<T>&& move) noexcept
|
||||
{
|
||||
m_firstChunk = move.m_firstChunk;
|
||||
m_lastChunk = move.m_lastChunk;
|
||||
m_currentSize = move.m_currentSize;
|
||||
m_totalCap = move.m_totalCap;
|
||||
|
||||
move.m_firstChunk = nullptr;
|
||||
move.m_lastChunk = nullptr;
|
||||
move.m_currentSize = 0;
|
||||
move.m_totalCap = 0;
|
||||
}
|
||||
|
||||
~StableVector()
|
||||
{
|
||||
VectorChunk* currentChunk = m_firstChunk;
|
||||
while (currentChunk)
|
||||
{
|
||||
VectorChunk* temp = currentChunk;
|
||||
currentChunk = currentChunk->m_next;
|
||||
temp->~VectorChunk();
|
||||
::operator delete(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the value to the first empty slot in the StableVector
|
||||
*
|
||||
* @param value - The value to be added
|
||||
*/
|
||||
void Add(const T& value)
|
||||
{
|
||||
VectorChunk* currentChunk = m_firstChunk;
|
||||
while (currentChunk)
|
||||
{
|
||||
for (size_t i = 0; i < currentChunk->m_chunkSize; i++)
|
||||
{
|
||||
if (!currentChunk->m_fill[i])
|
||||
{
|
||||
currentChunk->m_data[i] = value;
|
||||
currentChunk->m_fill[i] = true;
|
||||
m_currentSize++;
|
||||
|
||||
if (i > currentChunk->m_lastUsedIndex) currentChunk->m_lastUsedIndex = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
currentChunk = currentChunk->m_next;
|
||||
}
|
||||
|
||||
VectorChunk* chunk = SpawnChunk(size_t(m_lastChunk->m_chunkSize * GROWTH_FACTOR));
|
||||
|
||||
new (&m_lastChunk->m_data[++m_lastChunk->m_lastUsedIndex]) T(value);
|
||||
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true;
|
||||
m_currentSize++;
|
||||
}
|
||||
|
||||
void PushBack(const T& value)
|
||||
{
|
||||
if (m_lastChunk->m_lastUsedIndex + 1 == m_lastChunk->m_chunkSize)
|
||||
{
|
||||
VectorChunk* chunk = SpawnChunk(size_t(m_lastChunk->m_chunkSize * GROWTH_FACTOR));
|
||||
}
|
||||
|
||||
new (&m_lastChunk->m_data[++m_lastChunk->m_lastUsedIndex]) T(value);
|
||||
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true;
|
||||
m_currentSize++;
|
||||
}
|
||||
|
||||
void PushBack(T&& value) noexcept
|
||||
{
|
||||
if (m_lastChunk->m_lastUsedIndex + 1 == m_lastChunk->m_chunkSize)
|
||||
{
|
||||
VectorChunk* chunk = SpawnChunk(size_t(m_lastChunk->m_chunkSize * GROWTH_FACTOR));
|
||||
}
|
||||
|
||||
new (&m_lastChunk->m_data[++m_lastChunk->m_lastUsedIndex]) T(std::move(value));
|
||||
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true;
|
||||
m_currentSize++;
|
||||
}
|
||||
|
||||
template<typename... Args> void Emplace(Args&&... args)
|
||||
{
|
||||
VectorChunk* currentChunk = m_firstChunk;
|
||||
|
||||
while (currentChunk)
|
||||
{
|
||||
for (size_t i = 0; i < currentChunk->m_chunkSize; i++)
|
||||
{
|
||||
if (!currentChunk->m_fill[i])
|
||||
{
|
||||
currentChunk->m_data[i] = T(std::forward<Args>(args)...);
|
||||
currentChunk->m_fill[i] = true;
|
||||
m_currentSize++;
|
||||
|
||||
if (i > currentChunk->m_lastUsedIndex) currentChunk->m_lastUsedIndex = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
currentChunk = currentChunk->m_next;
|
||||
}
|
||||
|
||||
VectorChunk* chunk = SpawnChunk(size_t(m_lastChunk->m_chunkSize * GROWTH_FACTOR));
|
||||
|
||||
new (&m_lastChunk->m_data[++m_lastChunk->m_lastUsedIndex]) T(std::forward<Args>(args)...);
|
||||
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true;
|
||||
m_currentSize++;
|
||||
}
|
||||
|
||||
template<typename... Args> void EmplaceBack(Args&&... args)
|
||||
{
|
||||
if (m_lastChunk->m_lastUsedIndex + 1 == m_lastChunk->m_chunkSize)
|
||||
VectorChunk* chunk = SpawnChunk(size_t(m_lastChunk->m_chunkSize * GROWTH_FACTOR));
|
||||
|
||||
new (&m_lastChunk->m_data[++m_lastChunk->m_lastUsedIndex]) T(std::forward<Args>(args)...);
|
||||
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = true;
|
||||
m_currentSize++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops the last element of the StableVector
|
||||
*
|
||||
* @throw Please know that this pop function also reduces the chunk's lastUsedIndex
|
||||
*/
|
||||
void PopBack()
|
||||
{
|
||||
if (m_currentSize == 0) return;
|
||||
|
||||
if (m_lastChunk->m_lastUsedIndex == -1)
|
||||
{
|
||||
VectorChunk* temp = m_lastChunk;
|
||||
m_lastChunk = m_lastChunk->m_prev;
|
||||
m_lastChunk->m_next = nullptr;
|
||||
temp->~VectorChunk();
|
||||
::operator delete(temp);
|
||||
}
|
||||
|
||||
m_lastChunk->m_data[m_lastChunk->m_lastUsedIndex].~T();
|
||||
m_lastChunk->m_fill[m_lastChunk->m_lastUsedIndex] = false;
|
||||
m_lastChunk->m_lastUsedIndex--;
|
||||
m_currentSize--;
|
||||
}
|
||||
|
||||
void Remove(size_t index)
|
||||
{
|
||||
size_t localIndex = index;
|
||||
VectorChunk* chunk = GetChunk(localIndex);
|
||||
|
||||
if (chunk)
|
||||
{
|
||||
chunk->m_data[localIndex].~T();
|
||||
chunk->m_fill[localIndex] = false;
|
||||
m_currentSize--;
|
||||
}
|
||||
else throw std::out_of_range("Index out of range!");
|
||||
}
|
||||
|
||||
void Remove(const T& value)
|
||||
{
|
||||
VectorChunk* currentChunk = m_firstChunk;
|
||||
while (currentChunk)
|
||||
{
|
||||
for (size_t i = 0; i < currentChunk->m_chunkSize; i++)
|
||||
{
|
||||
if (currentChunk->m_fill[i] && currentChunk->m_data[i] == value)
|
||||
{
|
||||
currentChunk->m_data[i].~T();
|
||||
currentChunk->m_fill[i] = false;
|
||||
m_currentSize--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
currentChunk = currentChunk->m_next;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<T> ToVector() const
|
||||
{
|
||||
std::vector<T> vec;
|
||||
VectorChunk* currentChunk = m_firstChunk;
|
||||
while (currentChunk)
|
||||
{
|
||||
for (size_t i = 0; i < currentChunk->m_chunkSize; i++)
|
||||
{
|
||||
if (currentChunk->m_fill[i])
|
||||
{
|
||||
vec.push_back(currentChunk->m_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
currentChunk = currentChunk->m_next;
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
T& At(size_t index) const
|
||||
{
|
||||
if (index >= Size()) [[unlikely]]
|
||||
throw std::out_of_range("Index out of range!");
|
||||
return (*this)[index];
|
||||
}
|
||||
|
||||
T& operator[](size_t index) const
|
||||
{
|
||||
VectorChunk* chunk = m_firstChunk;
|
||||
size_t localIndex = index;
|
||||
while (chunk)
|
||||
{
|
||||
if (localIndex > chunk->m_chunkSize - 1)
|
||||
{
|
||||
localIndex -= (chunk->m_chunkSize);
|
||||
chunk = chunk->m_next;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
return chunk->m_data[localIndex];
|
||||
}
|
||||
|
||||
size_t Size() const { return m_currentSize; }
|
||||
size_t Capacity() const { return m_totalCap; }
|
||||
|
||||
void Clear()
|
||||
{
|
||||
VectorChunk* currentChunk = m_firstChunk;
|
||||
while (currentChunk)
|
||||
{
|
||||
VectorChunk* temp = currentChunk;
|
||||
currentChunk = currentChunk->m_next;
|
||||
delete temp;
|
||||
}
|
||||
|
||||
m_firstChunk = nullptr;
|
||||
m_lastChunk = nullptr;
|
||||
m_currentSize = 0;
|
||||
m_totalCap = DEFAULT_CHUNK_SIZE;
|
||||
|
||||
m_firstChunk = SpawnChunk(DEFAULT_CHUNK_SIZE);
|
||||
m_lastChunk = m_firstChunk;
|
||||
}
|
||||
|
||||
StableVector<T>& operator=(const StableVector<T>& copy)
|
||||
{
|
||||
if (this == ©) return *this;
|
||||
|
||||
Clear();
|
||||
|
||||
m_firstChunk = nullptr;
|
||||
m_lastChunk = nullptr;
|
||||
m_currentSize = 0;
|
||||
m_totalCap = 0;
|
||||
|
||||
VectorChunk* currentChunk = copy.m_firstChunk;
|
||||
|
||||
for (auto it = copy.begin(); it != copy.end(); ++it) PushBack(*it);
|
||||
}
|
||||
|
||||
StableVector<T>& operator=(StableVector<T>&& move) noexcept
|
||||
{
|
||||
if (this == &move) return *this;
|
||||
|
||||
Clear();
|
||||
|
||||
m_firstChunk = move.m_firstChunk;
|
||||
m_lastChunk = move.m_lastChunk;
|
||||
m_currentSize = move.m_currentSize;
|
||||
m_totalCap = move.m_totalCap;
|
||||
|
||||
move.m_firstChunk = nullptr;
|
||||
move.m_lastChunk = nullptr;
|
||||
move.m_currentSize = 0;
|
||||
move.m_totalCap = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator begin() { return Iterator(m_firstChunk, 0); }
|
||||
Iterator end() { return Iterator(m_lastChunk, m_lastChunk->m_lastUsedIndex + 1); }
|
||||
|
||||
const Iterator& cbegin() const { return Iterator(m_firstChunk, 0); }
|
||||
const Iterator& cend() const { return Iterator(m_lastChunk, m_lastChunk->m_lastUsedIndex + 1); }
|
||||
|
||||
private:
|
||||
VectorChunk* SpawnChunk(size_t requestedSize)
|
||||
{
|
||||
VectorChunk* chunk = static_cast<VectorChunk*>(
|
||||
::operator new(sizeof(VectorChunk) + requestedSize * sizeof(T) + requestedSize * sizeof(bool)));
|
||||
new (chunk) VectorChunk(requestedSize);
|
||||
|
||||
if (m_lastChunk)
|
||||
{
|
||||
chunk->m_prev = m_lastChunk;
|
||||
m_lastChunk->m_next = chunk;
|
||||
m_lastChunk = chunk;
|
||||
m_totalCap += m_lastChunk->m_chunkSize;
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
VectorChunk* GetChunk(size_t& localIndex)
|
||||
{
|
||||
VectorChunk* chunk = m_firstChunk;
|
||||
while (chunk)
|
||||
{
|
||||
if (localIndex > chunk->m_chunkSize - 1)
|
||||
{
|
||||
localIndex -= (chunk->m_chunkSize);
|
||||
chunk = chunk->m_next;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private:
|
||||
VectorChunk* m_firstChunk;
|
||||
VectorChunk* m_lastChunk;
|
||||
size_t m_currentSize;
|
||||
size_t m_totalCap;
|
||||
};
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
@@ -15,7 +15,10 @@
|
||||
#include <thread>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <tracy/Tracy.hpp>
|
||||
#if __has_include("tracy/Tracy.hpp")
|
||||
#include <tracy/Tracy.hpp>
|
||||
#define HAS_TRACY
|
||||
#endif
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
@@ -25,7 +28,10 @@ namespace OpenVulkano
|
||||
: app(app), renderApi(renderApi)
|
||||
{
|
||||
Utils::SetThreadName("Main");
|
||||
#ifdef HAS_TRACY
|
||||
ZoneScoped;
|
||||
#endif
|
||||
|
||||
|
||||
Logger::SetupLogger();
|
||||
if (!app)
|
||||
@@ -53,7 +59,9 @@ namespace OpenVulkano
|
||||
: app(app), renderApi(renderApi)
|
||||
{
|
||||
Utils::SetThreadName("Main");
|
||||
#ifdef HAS_TRACY
|
||||
ZoneScoped;
|
||||
#endif
|
||||
|
||||
Logger::SetupLogger();
|
||||
if (!app)
|
||||
@@ -136,7 +144,9 @@ namespace OpenVulkano
|
||||
|
||||
void GraphicsAppManager::StartUp()
|
||||
{
|
||||
#ifdef HAS_TRACY
|
||||
ZoneScoped;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
Logger::MANAGER->info("Initializing ...");
|
||||
@@ -169,8 +179,11 @@ namespace OpenVulkano
|
||||
|
||||
void GraphicsAppManager::LoopTick()
|
||||
{
|
||||
#ifdef HAS_TRACY
|
||||
FrameMark;
|
||||
ZoneScoped;
|
||||
#endif
|
||||
|
||||
if (platform) platform->Tick();
|
||||
if (paused)
|
||||
{ // The rendering is paused
|
||||
@@ -197,7 +210,9 @@ namespace OpenVulkano
|
||||
|
||||
void GraphicsAppManager::ShutDown()
|
||||
{
|
||||
#ifdef HAS_TRACY
|
||||
ZoneScoped;
|
||||
#endif
|
||||
Logger::MANAGER->info("Shutting down ...");
|
||||
app->Close();
|
||||
renderer->Close();
|
||||
|
||||
45
openVulkanoCpp/Host/Windows/ErrorUtils.cpp
Normal file
45
openVulkanoCpp/Host/Windows/ErrorUtils.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "ErrorUtils.hpp"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include "Windows.h"
|
||||
#endif
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
std::string ErrorUtils::GetLastErrorMessage()
|
||||
{
|
||||
// Get the error message ID, if any.
|
||||
DWORD errorID = GetLastError();
|
||||
if (errorID == 0)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
LPSTR messageBuffer = nullptr;
|
||||
// Format the error message
|
||||
uint64_t size =
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errorID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &messageBuffer, 0, NULL);
|
||||
|
||||
// Buffer it up
|
||||
std::string message(messageBuffer, size);
|
||||
|
||||
// Free the buffer and return the message
|
||||
LocalFree(messageBuffer);
|
||||
return message;
|
||||
}
|
||||
#else
|
||||
std::string ErrorUtils::GetLastErrorMessage()
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
18
openVulkanoCpp/Host/Windows/ErrorUtils.hpp
Normal file
18
openVulkanoCpp/Host/Windows/ErrorUtils.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
class ErrorUtils
|
||||
{
|
||||
public:
|
||||
static std::string GetLastErrorMessage();
|
||||
};
|
||||
}
|
||||
@@ -6,121 +6,15 @@
|
||||
|
||||
#include "MemMappedFile.hpp"
|
||||
#include "Base/Logger.hpp"
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "MemMappedFileInternal.hpp"
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
class MemMappedFile::Internal final
|
||||
{
|
||||
public:
|
||||
void* address = nullptr;
|
||||
size_t size = 0;
|
||||
#ifdef _MSC_VER
|
||||
HANDLE fileHandle;
|
||||
HANDLE fileMappingHandle;
|
||||
|
||||
Internal(const char* file, FileMode fileMode)
|
||||
{ //TODO handle other file modes than read
|
||||
fileHandle = CreateFile(
|
||||
TEXT(file), // file to open
|
||||
GENERIC_READ, // open for reading
|
||||
0, // do not share
|
||||
NULL, // default security
|
||||
OPEN_EXISTING, // existing file only
|
||||
FILE_ATTRIBUTE_NORMAL, // normal file
|
||||
NULL); // no attribute template
|
||||
if (fileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to open file: {}", file);
|
||||
return;
|
||||
}
|
||||
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(fileHandle, &fileSize))
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to get size of file: {}", file);
|
||||
CloseHandle(fileHandle);
|
||||
return;
|
||||
}
|
||||
size = fileSize.QuadPart;
|
||||
|
||||
fileMappingHandle = CreateFileMapping(
|
||||
fileHandle,
|
||||
NULL, // default security
|
||||
PAGE_READONLY, // read-only access
|
||||
0, // maximum object size (high-order)
|
||||
0, // maximum object size (low-order)
|
||||
NULL); // name of the mapping object
|
||||
if (fileMappingHandle == 0)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to create file mapping handle: {}", file);
|
||||
CloseHandle(fileHandle);
|
||||
size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
address = MapViewOfFile(
|
||||
fileMappingHandle, // handle to the map object
|
||||
FILE_MAP_READ, // read access
|
||||
0, // max. object size
|
||||
0, // size of the hFile
|
||||
0); // map the entire file
|
||||
|
||||
if (address == nullptr)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to create file mapping: {}", file);
|
||||
CloseHandle(fileMappingHandle);
|
||||
CloseHandle(fileHandle);
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~Internal()
|
||||
{
|
||||
UnmapViewOfFile(address);
|
||||
CloseHandle(fileMappingHandle);
|
||||
CloseHandle(fileHandle);
|
||||
}
|
||||
#else
|
||||
int fileHandle;
|
||||
struct stat fileStat;
|
||||
|
||||
Internal(const char* file, FileMode fileMode)
|
||||
{
|
||||
fileHandle = open(file, fileMode);
|
||||
if (fstat(fileHandle, &fileStat) == -1)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to query stats for file: {}", file);
|
||||
return;
|
||||
}
|
||||
address = mmap(nullptr, fileStat.st_size, fileMode + 1, MAP_PRIVATE, fileHandle, 0);
|
||||
if (address == MAP_FAILED)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to memory map file: {}", file);
|
||||
address = nullptr;
|
||||
}
|
||||
size = fileStat.st_size;
|
||||
}
|
||||
|
||||
~Internal()
|
||||
{
|
||||
munmap(address, fileStat.st_size);
|
||||
close(fileHandle);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
MemMappedFile::MemMappedFile(const std::filesystem::path& path, FileMode fileMode)
|
||||
: m_data(nullptr), m_size(0)
|
||||
{
|
||||
m_internal = std::make_shared<Internal>(path.string().c_str(), fileMode);
|
||||
std::string file = path.string();
|
||||
m_internal = std::make_shared<MemMappedFileInternal>(file.c_str(), fileMode);
|
||||
m_data = m_internal->address;
|
||||
m_size = (m_data) ? m_internal->size : 0;
|
||||
}
|
||||
|
||||
@@ -10,16 +10,22 @@
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
class MemMappedFileInternal;
|
||||
class MemMappedFile
|
||||
{
|
||||
class Internal;
|
||||
friend class MemMappedFileWriteHelper;
|
||||
|
||||
std::shared_ptr<Internal> m_internal;
|
||||
std::shared_ptr<MemMappedFileInternal> m_internal;
|
||||
void* m_data;
|
||||
size_t m_size;
|
||||
|
||||
public:
|
||||
enum FileMode : int { READ_ONLY = 0, WRITE_ONLY, READ_WRITE };
|
||||
enum FileMode : int
|
||||
{
|
||||
READ_ONLY = 0,
|
||||
WRITE_ONLY,
|
||||
READ_WRITE
|
||||
};
|
||||
|
||||
MemMappedFile(const std::filesystem::path& path, FileMode fileMode = READ_ONLY);
|
||||
|
||||
|
||||
125
openVulkanoCpp/IO/MemMappedFileInternal.cpp
Normal file
125
openVulkanoCpp/IO/MemMappedFileInternal.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "MemMappedFileInternal.hpp"
|
||||
|
||||
#include "Base/Logger.hpp"
|
||||
#include "Host/Windows/ErrorUtils.hpp"
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
MemMappedFileInternal::MemMappedFileInternal(const char* file, MemMappedFile::FileMode fileMode)
|
||||
: size(0), fileHandle(nullptr), fileMappingHandle(nullptr)
|
||||
{
|
||||
DWORD openMode { 0 }, mapMode { 0 }, viewMode { 0 };
|
||||
|
||||
switch (fileMode)
|
||||
{
|
||||
case MemMappedFile::FileMode::READ_ONLY:
|
||||
openMode = GENERIC_READ;
|
||||
mapMode = PAGE_READONLY;
|
||||
viewMode = FILE_MAP_READ;
|
||||
break;
|
||||
case MemMappedFile::FileMode::WRITE_ONLY:
|
||||
openMode = GENERIC_WRITE;
|
||||
mapMode = PAGE_READWRITE;
|
||||
viewMode = FILE_MAP_WRITE;
|
||||
break;
|
||||
case MemMappedFile::FileMode::READ_WRITE:
|
||||
openMode = GENERIC_ALL;
|
||||
mapMode = PAGE_READWRITE;
|
||||
viewMode = FILE_MAP_ALL_ACCESS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fileHandle = CreateFileA(file, // file to open
|
||||
openMode, // open for switch case
|
||||
NULL, // share mode
|
||||
NULL, // default security
|
||||
OPEN_ALWAYS, // always
|
||||
FILE_ATTRIBUTE_NORMAL, // normal file
|
||||
NULL); // no attribute template
|
||||
|
||||
if (fileHandle == INVALID_HANDLE_VALUE || fileHandle == NULL)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to open file: {}.", ErrorUtils::GetLastErrorMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(fileHandle, &fileSize))
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to get size of file: {}", ErrorUtils::GetLastErrorMessage());
|
||||
CloseHandle(fileHandle);
|
||||
return;
|
||||
}
|
||||
size = fileSize.QuadPart;
|
||||
|
||||
fileMappingHandle = CreateFileMappingA(fileHandle,
|
||||
NULL, // default security
|
||||
mapMode, // mod for switch case
|
||||
0, // maximum object size (high-order)
|
||||
0, // maximum object size (low-order)
|
||||
NULL); // name of the mapping object
|
||||
if (fileMappingHandle == INVALID_HANDLE_VALUE || fileMappingHandle == NULL)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to create file mapping handle: {}", ErrorUtils::GetLastErrorMessage());
|
||||
CloseHandle(fileHandle);
|
||||
size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
address = MapViewOfFile(fileMappingHandle, // handle to the map object
|
||||
viewMode, // access for switch case
|
||||
0, // max. object size
|
||||
0, // size of the hFile
|
||||
0); // map the entire file
|
||||
|
||||
if (address == nullptr)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to create file mapping: {}", ErrorUtils::GetLastErrorMessage());
|
||||
CloseHandle(fileMappingHandle);
|
||||
CloseHandle(fileHandle);
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MemMappedFileInternal::~MemMappedFileInternal()
|
||||
{
|
||||
UnmapViewOfFile(address);
|
||||
CloseHandle(fileMappingHandle);
|
||||
CloseHandle(fileHandle);
|
||||
}
|
||||
#else
|
||||
MemMappedFileInternal::MemMappedFileInternal(const char* file, MemMappedFile::FileMode fileMode)
|
||||
{
|
||||
fileHandle = open(file, fileMode);
|
||||
if (fstat(fileHandle, &fileStat) == -1)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to query stats for file: {}", file);
|
||||
return;
|
||||
}
|
||||
address = mmap(nullptr, fileStat.st_size, fileMode + 1, MAP_SHARED, fileHandle, 0);
|
||||
if (address == MAP_FAILED)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to memory map file: {}", file);
|
||||
address = nullptr;
|
||||
}
|
||||
size = fileStat.st_size;
|
||||
}
|
||||
|
||||
MemMappedFileInternal::~MemMappedFileInternal()
|
||||
{
|
||||
munmap(address, fileStat.st_size);
|
||||
close(fileHandle);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
50
openVulkanoCpp/IO/MemMappedFileInternal.hpp
Normal file
50
openVulkanoCpp/IO/MemMappedFileInternal.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "MemMappedFile.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
class MemMappedFileInternal
|
||||
{
|
||||
friend class MemMappedFileWriteHelper;
|
||||
friend class MemMappedFile;
|
||||
|
||||
public:
|
||||
MemMappedFileInternal(const char* file, MemMappedFile::FileMode fileMode);
|
||||
~MemMappedFileInternal();
|
||||
|
||||
private:
|
||||
#if defined(_MSC_VER)
|
||||
bool InvalidHandle() const { return fileHandle == INVALID_HANDLE_VALUE || fileHandle == NULL; }
|
||||
#else
|
||||
[[nodiscard]] bool InvalidHandle() const { return fileHandle == -1; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
void* address = nullptr;
|
||||
size_t size = 0;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
HANDLE fileHandle;
|
||||
HANDLE fileMappingHandle;
|
||||
#else
|
||||
int fileHandle;
|
||||
struct stat fileStat;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
367
openVulkanoCpp/IO/MemMappedFileWriteHelper.cpp
Normal file
367
openVulkanoCpp/IO/MemMappedFileWriteHelper.cpp
Normal file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "MemMappedFileWriteHelper.hpp"
|
||||
|
||||
#include "MemMappedFile.hpp"
|
||||
#include "MemMappedFileInternal.hpp"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <Host/Windows/ErrorUtils.hpp>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "Base/Logger.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
|
||||
MemMappedFileWriteHelper::MemMappedFileWriteHelper(const std::filesystem::path& path, size_t maxFileSize)
|
||||
: m_path(path), m_file(nullptr)
|
||||
{
|
||||
// Check if file exists, so we can open it in the correct mode
|
||||
DWORD openMode = CREATE_ALWAYS;
|
||||
if (std::filesystem::exists(path))
|
||||
{
|
||||
openMode = OPEN_ALWAYS;
|
||||
}
|
||||
|
||||
// Open the file
|
||||
HANDLE fileHandle =
|
||||
CreateFileA(path.string().c_str(), GENERIC_ALL, FILE_SHARE_WRITE, NULL, openMode, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (fileHandle == INVALID_HANDLE_VALUE || fileHandle == NULL)
|
||||
{
|
||||
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
|
||||
}
|
||||
|
||||
// Control the file size
|
||||
LARGE_INTEGER currentSize {};
|
||||
if (fileHandle)
|
||||
{
|
||||
if (!GetFileSizeEx(fileHandle, ¤tSize))
|
||||
{
|
||||
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (currentSize.QuadPart <= 0 && maxFileSize == 0)
|
||||
{
|
||||
throw std::runtime_error("Either the file size has to be greater than 0 or Initial Size!");
|
||||
}
|
||||
|
||||
// Set the file size
|
||||
if (maxFileSize > 0)
|
||||
{
|
||||
if (fileHandle)
|
||||
{
|
||||
// Set the file size
|
||||
if (!SetFilePointer(fileHandle, DWORD(maxFileSize), NULL, FILE_BEGIN))
|
||||
{
|
||||
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
|
||||
}
|
||||
|
||||
if (!SetEndOfFile(fileHandle))
|
||||
{
|
||||
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fileHandle)
|
||||
{
|
||||
CloseHandle(fileHandle);
|
||||
}
|
||||
|
||||
m_file = new MemMappedFile(path.string().c_str(), MemMappedFile::FileMode::READ_WRITE);
|
||||
}
|
||||
|
||||
MemMappedFileWriteHelper::~MemMappedFileWriteHelper() = default;
|
||||
|
||||
bool MemMappedFileWriteHelper::Resize(const size_t newSize)
|
||||
{
|
||||
if (newSize == 0)
|
||||
{
|
||||
// Handle the case where the new size is zero
|
||||
Logger::FILESYS->critical("New size is zero.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the current file handle
|
||||
if (m_file->m_internal->fileHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
Logger::FILESYS->critical("Invalid file handle.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unmap the old view of the file and close the file mapping handle
|
||||
if (!(m_file->m_internal->fileMappingHandle == NULL)
|
||||
&& !(m_file->m_internal->fileMappingHandle == INVALID_HANDLE_VALUE))
|
||||
{
|
||||
UnmapViewOfFile(m_file->m_internal->address);
|
||||
CloseHandle(m_file->m_internal->fileMappingHandle);
|
||||
}
|
||||
|
||||
// Resize the file
|
||||
if (!SetFilePointer(m_file->m_internal->fileHandle, static_cast<DWORD>(newSize), NULL, FILE_BEGIN))
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to set file pointer. Reason: {}", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetEndOfFile(m_file->m_internal->fileHandle))
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to set end of file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a new file mapping handle
|
||||
m_file->m_internal->fileMappingHandle =
|
||||
CreateFileMappingW(m_file->m_internal->fileHandle, NULL, PAGE_READWRITE, 0, 0, NULL);
|
||||
if (m_file->m_internal->fileMappingHandle == NULL)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to create file mapping.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map the file to a new view
|
||||
m_file->m_internal->address =
|
||||
MapViewOfFile(m_file->m_internal->fileMappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
if (m_file->m_internal->address == NULL || m_file->m_internal->address == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to map view of file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool MemMappedFileWriteHelper::Trim(const size_t finalFileSize)
|
||||
{
|
||||
HANDLE fileHandle {};
|
||||
if (m_file->m_internal->InvalidHandle())
|
||||
{
|
||||
auto file = m_path.string();
|
||||
fileHandle = CreateFileA(file.c_str(), // file to open
|
||||
GENERIC_WRITE, // open for reading
|
||||
0, // do not share
|
||||
NULL, // default security
|
||||
CREATE_ALWAYS, // existing file only
|
||||
FILE_ATTRIBUTE_NORMAL, // normal file
|
||||
NULL); // no attribute template
|
||||
}
|
||||
else
|
||||
{
|
||||
fileHandle = m_file->m_internal->fileHandle;
|
||||
}
|
||||
|
||||
if (m_file)
|
||||
{
|
||||
if (!UnmapViewOfFile(m_file->m_internal->address))
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to unmap view of file on trim.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CloseHandle(m_file->m_internal->fileMappingHandle))
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to close file mapping handle.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LARGE_INTEGER liSize;
|
||||
liSize.QuadPart = finalFileSize;
|
||||
if (!SetFilePointerEx(fileHandle, liSize, NULL, FILE_BEGIN) || !SetEndOfFile(fileHandle))
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to trim file: {}", ErrorUtils::GetLastErrorMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a new file mapping handle
|
||||
if (m_file)
|
||||
{
|
||||
m_file->m_internal->fileMappingHandle = CreateFileMappingW(fileHandle, NULL, PAGE_READWRITE, 0, 0, NULL);
|
||||
if (m_file->m_internal->fileMappingHandle == NULL)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to create file mapping.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map the file to a new view
|
||||
m_file->m_internal->address =
|
||||
MapViewOfFile(m_file->m_internal->fileMappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
if (m_file->m_internal->address == NULL || m_file->m_internal->address == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to map view of file.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_file)
|
||||
{
|
||||
m_file->m_size = finalFileSize;
|
||||
m_file->m_internal->size = finalFileSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
MemMappedFileWriteHelper::MemMappedFileWriteHelper(const std::filesystem::path& path, size_t maxFileSize)
|
||||
{
|
||||
const auto file = path.string();
|
||||
const int fileHandle = open(file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
if (fileHandle == -1)
|
||||
{
|
||||
throw std::runtime_error("Failed to open file: " + file);
|
||||
}
|
||||
|
||||
struct stat fileStat
|
||||
{
|
||||
};
|
||||
if (fstat(fileHandle, &fileStat) == -1)
|
||||
{
|
||||
close(fileHandle);
|
||||
throw std::runtime_error("Failed to get file size: " + file);
|
||||
}
|
||||
|
||||
if (const size_t fileSize = fileStat.st_size; fileSize < maxFileSize)
|
||||
{
|
||||
if (ftruncate(fileHandle, maxFileSize) == -1)
|
||||
{
|
||||
close(fileHandle);
|
||||
throw std::runtime_error("Failed to resize file: " + file);
|
||||
}
|
||||
}
|
||||
|
||||
close(fileHandle);
|
||||
m_file = new MemMappedFile(file.c_str(), MemMappedFile::FileMode::READ_WRITE);
|
||||
}
|
||||
|
||||
MemMappedFileWriteHelper::~MemMappedFileWriteHelper() = default;
|
||||
|
||||
bool MemMappedFileWriteHelper::Resize(const size_t newSize)
|
||||
{
|
||||
if (newSize == 0)
|
||||
{
|
||||
// Handle the case where the new size is zero
|
||||
Logger::FILESYS->error("New size is zero. New size must be greater than zero.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the current file handle
|
||||
if (m_file->m_internal->fileHandle == -1)
|
||||
{
|
||||
Logger::FILESYS->critical("Invalid file handle.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resize the file
|
||||
if (ftruncate(m_file->m_internal->fileHandle, newSize) == -1)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to resize file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unmap the old view and map a new view of the resized file
|
||||
if (m_file->m_internal->address != nullptr)
|
||||
{
|
||||
if (munmap(m_file->m_internal->address, m_file->m_internal->size) == -1)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to unmap view of file.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Map the file to a new view
|
||||
m_file->m_internal->address =
|
||||
mmap(nullptr, newSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_file->m_internal->fileHandle, 0);
|
||||
if (m_file->m_internal->address == MAP_FAILED)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to map file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the size of the file
|
||||
m_file->m_internal->size = newSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MemMappedFileWriteHelper::Trim(const size_t finalFileSize)
|
||||
{
|
||||
// If getting handle returns invalid file recreate the file
|
||||
if (m_file->m_internal->InvalidHandle())
|
||||
{
|
||||
const auto file = m_path.string();
|
||||
m_file->m_internal->fileHandle = open(file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
}
|
||||
|
||||
// Unmap the old view of the file
|
||||
if(munmap(m_file->m_internal->address, m_file->m_internal->size) == -1)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to unmap address.");
|
||||
}
|
||||
|
||||
// Trim the file
|
||||
if (ftruncate(m_file->m_internal->fileHandle, finalFileSize) == -1)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to trim file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remap the file with the new size
|
||||
m_file->m_internal->address = mmap(nullptr, finalFileSize, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
m_file->m_internal->fileHandle, 0);
|
||||
if (m_file->m_internal->address == MAP_FAILED)
|
||||
{
|
||||
Logger::FILESYS->critical("Failed to map file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the size in MemMappedFile structure
|
||||
m_file->m_size = finalFileSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void MemMappedFileWriteHelper::Close()
|
||||
{
|
||||
if (m_file->IsOpen())
|
||||
{
|
||||
delete m_file;
|
||||
}
|
||||
}
|
||||
|
||||
MemMappedFileWriter::MemMappedFileWriter(const std::filesystem::path& path, size_t maxFileSize)
|
||||
: m_helper(MemMappedFileWriteHelper(path, maxFileSize))
|
||||
{
|
||||
}
|
||||
|
||||
MemMappedFileWriter::~MemMappedFileWriter() { m_helper.Close(); }
|
||||
|
||||
void MemMappedFileWriter::Write(const char* data, const size_t size)
|
||||
{
|
||||
// If the new size is greater than the current size, resize the file
|
||||
if (m_writtenSize + size > m_helper.Size())
|
||||
{
|
||||
m_helper.Resize(m_writtenSize + size);
|
||||
}
|
||||
|
||||
// Write to the end of the file
|
||||
memcpy(static_cast<char*>(m_helper.Data()) + m_writtenSize, data, size);
|
||||
m_writtenSize += size;
|
||||
}
|
||||
}
|
||||
48
openVulkanoCpp/IO/MemMappedFileWriteHelper.hpp
Normal file
48
openVulkanoCpp/IO/MemMappedFileWriteHelper.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IO/MemMappedFile.hpp"
|
||||
#include <filesystem>
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
class MemMappedFileWriteHelper
|
||||
{
|
||||
public:
|
||||
MemMappedFileWriteHelper(const std::filesystem::path& path, size_t maxFileSize);
|
||||
~MemMappedFileWriteHelper();
|
||||
|
||||
[[nodiscard]] void* Data() const { return m_file->Data(); }
|
||||
[[nodiscard]] size_t Size() const { return m_file->Size(); }
|
||||
|
||||
bool Resize(size_t newSize);
|
||||
void Close();
|
||||
bool Trim(size_t finalFileSize);
|
||||
|
||||
static constexpr size_t USE_CURRENT_FILE_SIZE = 0;
|
||||
|
||||
private:
|
||||
MemMappedFile* m_file;
|
||||
std::filesystem::path m_path;
|
||||
};
|
||||
|
||||
class MemMappedFileWriter final
|
||||
{
|
||||
public:
|
||||
MemMappedFileWriter(const std::filesystem::path& path, size_t maxFileSize);
|
||||
~MemMappedFileWriter();
|
||||
|
||||
void Write(const char* data, size_t size);
|
||||
void SetOffset(size_t offset) { m_writtenSize = offset; }
|
||||
[[nodiscard]] size_t GetOffset() const { return m_writtenSize; }
|
||||
|
||||
private:
|
||||
MemMappedFileWriteHelper m_helper;
|
||||
size_t m_writtenSize = 0;
|
||||
};
|
||||
}
|
||||
@@ -6,7 +6,8 @@
|
||||
|
||||
#include "ImageLoaderJpeg.hpp"
|
||||
#include "Base/Utils.hpp"
|
||||
#include <Data/Containers/Array.hpp>
|
||||
#include "Base/Logger.hpp"
|
||||
#include "Data/Containers/Array.hpp"
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
@@ -21,8 +22,8 @@ namespace OpenVulkano::Image
|
||||
{
|
||||
std::unique_ptr<Image> ImageLoaderJpeg::loadFromFile(const std::string& filePath)
|
||||
{
|
||||
Array<char> buffer = OpenVulkano::Utils::ReadFile(filePath);
|
||||
return loadJpeg(reinterpret_cast<uint8_t*>(buffer.Data()), buffer.Size());
|
||||
const auto file = Utils::ReadFile(filePath);
|
||||
return loadJpeg(reinterpret_cast<const uint8_t*>(file.Data()), file.Size());
|
||||
}
|
||||
|
||||
std::unique_ptr<Image> ImageLoaderJpeg::loadFromMemory(const std::vector<uint8_t>& buffer)
|
||||
@@ -36,19 +37,29 @@ namespace OpenVulkano::Image
|
||||
{
|
||||
Image result;
|
||||
|
||||
int rows, cols;
|
||||
int rows = 0, cols = 0;
|
||||
unsigned char* compressedImage = const_cast<uint8_t*>(data);
|
||||
|
||||
int jpegSubsamp;
|
||||
int jpegSubsamp = 0;
|
||||
tjhandle jpegDecompressor = tjInitDecompress();
|
||||
tjDecompressHeader2(jpegDecompressor, compressedImage, size, &cols, &rows, &jpegSubsamp);
|
||||
if (!jpegDecompressor)
|
||||
{
|
||||
Logger::FILESYS->error("Failed to read jpeg header. Error: {}", tjGetErrorStr());
|
||||
return nullptr;
|
||||
}
|
||||
int status = tjDecompressHeader2(jpegDecompressor, compressedImage, size, &cols, &rows, &jpegSubsamp);
|
||||
if (status != 0)
|
||||
{
|
||||
Logger::FILESYS->error("Failed to read jpeg header. Error: {}", tjGetErrorStr());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const int channels = 4;
|
||||
result.data = OpenVulkano::Array<uint8_t>(cols * rows * channels);
|
||||
result.dataFormat = OpenVulkano::DataFormat::R8G8B8A8_UINT;
|
||||
result.dataFormat = OpenVulkano::DataFormat::B8G8R8A8_UINT;
|
||||
|
||||
tjDecompress2(jpegDecompressor, compressedImage, size, result.data.Data(), cols, 0 /*pitch*/, rows,
|
||||
TJPF_RGBA, TJFLAG_FASTDCT);
|
||||
TJPF_BGRA, TJFLAG_FASTDCT);
|
||||
tjDestroy(jpegDecompressor);
|
||||
result.resolution.x = cols;
|
||||
result.resolution.y = rows;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Math.hpp"
|
||||
#include <fmt/format.h>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
@@ -109,9 +110,14 @@ namespace OpenVulkano::Math
|
||||
data = (data & !(BITMASK << BITS)) | ((z & BITMASK) << BITS);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string ToString(const std::string& separator = ", ") const
|
||||
[[nodiscard]] std::string ToString(const std::string& separator) const
|
||||
{
|
||||
return std::to_string(X()) + "," + std::to_string(Y()) + "," + std::to_string(Z());
|
||||
return std::to_string(X()) + separator + std::to_string(Y()) + separator + std::to_string(Z());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string ToString() const
|
||||
{
|
||||
return fmt::format("{},{},{}", X(), Y(), Z());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr operator T() const { return data; }
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Base/Wrapper.hpp"
|
||||
#include "Math/Math.hpp"
|
||||
#include "Image/Image.hpp"
|
||||
#include "Scene/Texture.hpp"
|
||||
@@ -56,7 +57,7 @@ namespace OpenVulkano::Scene
|
||||
{
|
||||
std::map<uint32_t, GlyphInfo> glyphs;
|
||||
AtlasMetadata meta;
|
||||
std::unique_ptr<Image::Image> img;
|
||||
Unique<Image::Image> img;
|
||||
Texture texture;
|
||||
};
|
||||
|
||||
|
||||
@@ -93,7 +93,6 @@ namespace OpenVulkano::Scene
|
||||
m_atlasData = std::make_shared<AtlasData>();
|
||||
if (isPacked)
|
||||
{
|
||||
m_atlasData->texture = Texture();
|
||||
m_material.texture = &m_atlasData->texture;
|
||||
m_atlasData->img = Image::IImageLoader::loadData((const uint8_t*) atlasMetadata.Data(),
|
||||
offsetToMetadata);
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace OpenVulkano::Vulkan
|
||||
if (labelDrawable->IsBillboard())
|
||||
{
|
||||
OpenVulkano::Scene::UniformBuffer* buffer = labelDrawable->GetBillboardBuffer();
|
||||
VulkanUniformBuffer* vkBuffer = static_cast<VulkanUniformBuffer*>(buffer->renderBuffer);
|
||||
VulkanUniformBuffer* vkBuffer = buffer->GetRenderResource();
|
||||
if (!vkBuffer)
|
||||
{
|
||||
vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(buffer);
|
||||
@@ -32,7 +32,7 @@ namespace OpenVulkano::Vulkan
|
||||
}
|
||||
|
||||
OpenVulkano::Scene::UniformBuffer* labelBuffer = labelDrawable->GetLabelBuffer();
|
||||
VulkanUniformBuffer* vkBuffer = static_cast<VulkanUniformBuffer*>(labelBuffer->renderBuffer);
|
||||
VulkanUniformBuffer* vkBuffer = labelBuffer->GetRenderResource();
|
||||
if (!vkBuffer)
|
||||
{
|
||||
vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(labelBuffer);
|
||||
@@ -57,7 +57,7 @@ namespace OpenVulkano::Vulkan
|
||||
OpenVulkano::Scene::Shader* shader = entry.GetShader();
|
||||
drawContext->EncodeShader(shader);
|
||||
Geometry* mesh = entry.GetMesh();
|
||||
VulkanGeometry* renderGeo = static_cast<VulkanGeometry*>(mesh->renderGeo);
|
||||
VulkanGeometry* renderGeo = mesh->GetRenderResource();
|
||||
if (!renderGeo)
|
||||
{
|
||||
renderGeo = drawContext->renderer->GetResourceManager().PrepareGeometry(mesh);
|
||||
@@ -77,7 +77,7 @@ namespace OpenVulkano::Vulkan
|
||||
{
|
||||
if (buffer)
|
||||
{
|
||||
VulkanUniformBuffer* vkBuffer = static_cast<VulkanUniformBuffer*>(buffer->renderBuffer);
|
||||
VulkanUniformBuffer* vkBuffer = buffer->GetRenderResource();
|
||||
if (!vkBuffer)
|
||||
{
|
||||
vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(buffer);
|
||||
@@ -90,11 +90,11 @@ namespace OpenVulkano::Vulkan
|
||||
{
|
||||
if (Texture* texture = material->texture)
|
||||
{
|
||||
VulkanTexture* renderTexture = static_cast<VulkanTexture*>(texture->renderTexture);
|
||||
VulkanTexture* renderTexture = texture->GetRenderResource();
|
||||
if (!renderTexture)
|
||||
{
|
||||
drawContext->renderer->GetResourceManager().PrepareMaterial(entry.GetMaterial());
|
||||
renderTexture = static_cast<VulkanTexture*>(texture->renderTexture);
|
||||
renderTexture = texture->GetRenderResource();
|
||||
}
|
||||
renderTexture->Record(drawContext);
|
||||
}
|
||||
|
||||
126
tests/MemFileTests.cpp
Normal file
126
tests/MemFileTests.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include "IO/MemMappedFile.hpp"
|
||||
#include "IO/MemMappedFileWriteHelper.hpp"
|
||||
#include "IO/AppFolders.hpp"
|
||||
#include "Base/Logger.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
TEST_CASE("MemMappedFileWrite")
|
||||
{
|
||||
OpenVulkano::Logger::SetupLogger("", "tests.log");
|
||||
|
||||
auto path = OpenVulkano::AppFolders::GetAppTempDir();
|
||||
path += "/MemFileTest.txt";
|
||||
|
||||
std::string data = "Hello World X\n"
|
||||
"Hello World Y\n"
|
||||
"Hello World Z\n"
|
||||
"Hello World W\n"
|
||||
"Hello World A\n"
|
||||
"Hello World B\n"
|
||||
"Hello World C\n"
|
||||
"Hello World D\n"
|
||||
"Hello World E\n"
|
||||
"Hello World F\n"
|
||||
"Hello World G\n"
|
||||
"Hello World H\n"
|
||||
"Hello World I\n"
|
||||
"Hello World J\n"
|
||||
"Hello World K\n"
|
||||
"Hello World L\n"
|
||||
"Hello World M\n"
|
||||
"Hello World N\n";
|
||||
|
||||
|
||||
SECTION("Write to MemMappedFile")
|
||||
{
|
||||
OpenVulkano::MemMappedFileWriter writer(path, 1024);
|
||||
writer.Write(data.data(), data.size());
|
||||
|
||||
REQUIRE(writer.GetOffset() == data.size());
|
||||
}
|
||||
|
||||
SECTION("Control Size")
|
||||
{
|
||||
OpenVulkano::MemMappedFile memFile(path, OpenVulkano::MemMappedFile::READ_ONLY);
|
||||
REQUIRE(memFile.Size() == 1024); // The size that comes from the first Test.
|
||||
}
|
||||
|
||||
SECTION("Compare String Data for per char")
|
||||
{
|
||||
OpenVulkano::MemMappedFileWriteHelper memFileHelper(path, OpenVulkano::MemMappedFile::READ_ONLY);
|
||||
REQUIRE(memFileHelper.Trim(data.size()));
|
||||
|
||||
std::string testData((char*) memFileHelper.Data());
|
||||
|
||||
for (size_t i = 0; i < data.size(); i++)
|
||||
{
|
||||
if (data[i] != testData[i])
|
||||
{
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
memFileHelper.Close();
|
||||
}
|
||||
|
||||
SECTION("Trim File")
|
||||
{
|
||||
OpenVulkano::MemMappedFileWriteHelper helper(path,
|
||||
OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
|
||||
REQUIRE(helper.Trim(100));
|
||||
REQUIRE(helper.Size() == 100);
|
||||
|
||||
helper.Close();
|
||||
}
|
||||
|
||||
SECTION("Write Data 2")
|
||||
{
|
||||
OpenVulkano::MemMappedFileWriter writer(path, OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
|
||||
writer.Write(data.data(), data.size());
|
||||
writer.Write(data.data(), data.size());
|
||||
writer.Write(data.data(), data.size());
|
||||
|
||||
REQUIRE(writer.GetOffset() == data.size() * 3);
|
||||
}
|
||||
|
||||
SECTION("Compare Data")
|
||||
{
|
||||
OpenVulkano::MemMappedFileWriteHelper helper(path,
|
||||
OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
|
||||
REQUIRE(helper.Data() != nullptr);
|
||||
std::string testData((char*) helper.Data());
|
||||
printf("size: %llu", helper.Size());
|
||||
helper.Close();
|
||||
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
std::string streamData;
|
||||
std::getline(file, streamData, '\0');
|
||||
file.close();
|
||||
|
||||
for (size_t i = 0; i < testData.size(); i++)
|
||||
{
|
||||
if (streamData[i] != testData[i])
|
||||
{
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE(streamData.size() == testData.size());
|
||||
|
||||
printf("helper size: %llu\n", helper.Size());
|
||||
}
|
||||
|
||||
SECTION("Actual Size")
|
||||
{
|
||||
std::error_code ec;
|
||||
std::uintmax_t size = fs::file_size(path, ec);
|
||||
|
||||
REQUIRE(size == 756);
|
||||
}
|
||||
}
|
||||
190
tests/StableVectorTest.cpp
Normal file
190
tests/StableVectorTest.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include "Data/Containers/StableVector.hpp"
|
||||
|
||||
using namespace OpenVulkano;
|
||||
|
||||
struct Test
|
||||
{
|
||||
uint32_t mValue;
|
||||
Test(uint32_t value) : mValue(value) {}
|
||||
Test() : mValue(0) {}
|
||||
};
|
||||
|
||||
static int incrementCounter = 0;
|
||||
static int decrementCounter = 0;
|
||||
|
||||
struct TestCount
|
||||
{
|
||||
TestCount() : m_value("") { ++incrementCounter; }
|
||||
TestCount(const std::string& val) : m_value(val) { ++incrementCounter; }
|
||||
TestCount(TestCount&& other) noexcept : m_value(std::move(other.m_value)) { ++incrementCounter; }
|
||||
TestCount(const TestCount& other) : m_value(other.m_value) { ++incrementCounter; }
|
||||
|
||||
TestCount& operator=(const TestCount& other)
|
||||
{
|
||||
m_value = other.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TestCount& operator=(TestCount&& other) noexcept
|
||||
{
|
||||
m_value = std::move(other.m_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~TestCount() { ++decrementCounter; }
|
||||
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
TEST_CASE("ChunkVector")
|
||||
{
|
||||
SECTION("PushBack")
|
||||
{
|
||||
StableVector<uint32_t> vec;
|
||||
|
||||
REQUIRE(vec.Size() == 0);
|
||||
REQUIRE(vec.Capacity() == 32);
|
||||
|
||||
for (uint32_t i = 0; i < 100; ++i)
|
||||
{
|
||||
vec.PushBack(i);
|
||||
}
|
||||
|
||||
REQUIRE(vec.Size() == 100);
|
||||
REQUIRE(vec.Capacity() == 224); // 32 + 64 + 128 = 3 | previous chunk size multiplied by 2
|
||||
}
|
||||
|
||||
SECTION("EmplaceBack")
|
||||
{
|
||||
StableVector<Test> vec;
|
||||
|
||||
REQUIRE(vec.Size() == 0);
|
||||
REQUIRE(vec.Capacity() == 32);
|
||||
|
||||
for (uint32_t i = 0; i < 100; ++i)
|
||||
{
|
||||
vec.EmplaceBack(i);
|
||||
}
|
||||
|
||||
REQUIRE(vec.Size() == 100);
|
||||
|
||||
for (uint32_t i = 0; i < 100; ++i)
|
||||
{
|
||||
REQUIRE(vec[i].mValue == i);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("PopBack")
|
||||
{
|
||||
StableVector<uint32_t> vec;
|
||||
|
||||
REQUIRE(vec.Size() == 0);
|
||||
REQUIRE(vec.Capacity() == 32);
|
||||
|
||||
for (uint32_t i = 0; i < 100; ++i)
|
||||
{
|
||||
vec.PushBack(i);
|
||||
}
|
||||
|
||||
REQUIRE(vec.Size() == 100);
|
||||
|
||||
uint64_t tempVal = vec.Capacity();
|
||||
|
||||
for (uint32_t i = 0; i < 50; ++i)
|
||||
{
|
||||
vec.PopBack();
|
||||
}
|
||||
|
||||
REQUIRE(vec.Size() == 50);
|
||||
REQUIRE(vec.Capacity() == tempVal);
|
||||
}
|
||||
|
||||
SECTION("Clear")
|
||||
{
|
||||
StableVector<uint32_t> vec;
|
||||
|
||||
REQUIRE(vec.Size() == 0);
|
||||
REQUIRE(vec.Capacity() == 32);
|
||||
|
||||
for (uint32_t i = 0; i < 100; ++i)
|
||||
{
|
||||
vec.PushBack(i);
|
||||
}
|
||||
|
||||
REQUIRE(vec.Size() == 100);
|
||||
|
||||
vec.Clear();
|
||||
|
||||
REQUIRE(vec.Size() == 0);
|
||||
REQUIRE(vec.Capacity() == 32);
|
||||
}
|
||||
|
||||
SECTION("Add/Fill")
|
||||
{
|
||||
StableVector<std::string> vec;
|
||||
|
||||
REQUIRE(vec.Size() == 0);
|
||||
REQUIRE(vec.Capacity() == 32);
|
||||
|
||||
for (uint32_t i = 0; i < 100; ++i)
|
||||
{
|
||||
vec.PushBack("a");
|
||||
}
|
||||
|
||||
REQUIRE(vec.Size() == 100);
|
||||
|
||||
vec.Remove(56);
|
||||
vec.Add("z");
|
||||
|
||||
REQUIRE(vec.Size() == 100);
|
||||
REQUIRE(vec[56] == "z");
|
||||
}
|
||||
|
||||
SECTION("Correct Initialization")
|
||||
{
|
||||
StableVector<TestCount> vec;
|
||||
|
||||
REQUIRE(incrementCounter == 0);
|
||||
REQUIRE(decrementCounter == 0);
|
||||
|
||||
vec.EmplaceBack("a");
|
||||
|
||||
REQUIRE(incrementCounter == 1);
|
||||
REQUIRE(decrementCounter == 0);
|
||||
|
||||
vec.PushBack(TestCount("b"));
|
||||
|
||||
REQUIRE(incrementCounter == 3);
|
||||
REQUIRE(decrementCounter == 1);
|
||||
|
||||
TestCount testClass = TestCount("c");
|
||||
vec.PushBack(std::move(testClass));
|
||||
|
||||
REQUIRE(incrementCounter == 5);
|
||||
REQUIRE(decrementCounter == 1);
|
||||
|
||||
vec.Clear();
|
||||
|
||||
REQUIRE(incrementCounter == 5);
|
||||
REQUIRE(decrementCounter == 4);
|
||||
|
||||
vec.PushBack(TestCount("d"));
|
||||
|
||||
REQUIRE(incrementCounter == 7);
|
||||
REQUIRE(decrementCounter == 5);
|
||||
|
||||
TestCount testClass2 = TestCount("e");
|
||||
vec.PushBack(testClass2);
|
||||
|
||||
REQUIRE(incrementCounter == 9);
|
||||
REQUIRE(decrementCounter == 5);
|
||||
}
|
||||
|
||||
SECTION("Out of scope check")
|
||||
{
|
||||
REQUIRE(incrementCounter == 9);
|
||||
REQUIRE(decrementCounter == 9);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user