This commit is contained in:
xsl
2025-09-04 10:54:47 +08:00
commit 6bc8f61b18
1808 changed files with 208268 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
# Copyright (c) 2023-2025, Thomas Atkinson
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 the "License";
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
vkb__register_component(
NAME filesystem
HEADERS
include/filesystem/filesystem.hpp
include/filesystem/legacy.h
# private
src/std_filesystem.hpp
SRC
src/legacy.cpp
src/filesystem.cpp
src/std_filesystem.cpp
LINK_LIBS
vkb__core
stb
)
# GCC 9.0 and later has std::filesystem in the stdc++ library
# Earlier versions require linking against stdc++fs
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
target_link_libraries(vkb__filesystem PRIVATE stdc++fs)
endif()
+19
View File
@@ -0,0 +1,19 @@
////
- Copyright (c) 2023-2024, Thomas Atkinson
-
- SPDX-License-Identifier: Apache-2.0
-
- Licensed under the Apache License, Version 2.0 the "License";
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
////
= File System
@@ -0,0 +1,85 @@
/* Copyright (c) 2024, Thomas Atkinson
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <filesystem>
#include <memory>
#include <string>
#include <vector>
#include "core/platform/context.hpp"
#include "core/util/logging.hpp"
namespace vkb
{
namespace filesystem
{
struct FileStat
{
bool is_file;
bool is_directory;
size_t size;
};
using Path = std::filesystem::path;
// A thin filesystem wrapper
class FileSystem
{
public:
FileSystem() = default;
virtual ~FileSystem() = default;
virtual FileStat stat_file(const Path &path) = 0;
virtual bool is_file(const Path &path) = 0;
virtual bool is_directory(const Path &path) = 0;
virtual bool exists(const Path &path) = 0;
virtual bool create_directory(const Path &path) = 0;
virtual std::vector<uint8_t> read_chunk(const Path &path, size_t offset, size_t count) = 0;
virtual void write_file(const Path &path, const std::vector<uint8_t> &data) = 0;
virtual void remove(const Path &path) = 0;
virtual void set_external_storage_directory(const std::string &dir) = 0;
virtual const Path &external_storage_directory() const = 0;
virtual const Path &temp_directory() const = 0;
void write_file(const Path &path, const std::string &data);
// Read the entire file into a string
std::string read_file_string(const Path &path);
// Read the entire file into a vector of bytes
std::vector<uint8_t> read_file_binary(const Path &path);
};
using FileSystemPtr = std::shared_ptr<FileSystem>;
void init();
// Initialize the filesystem with the given context
void init_with_context(const PlatformContext &context);
// Get the filesystem instance
FileSystemPtr get();
namespace helpers
{
std::string filename(const std::string &path);
}
} // namespace filesystem
} // namespace vkb
@@ -0,0 +1,142 @@
/* Copyright (c) 2019-2025, Arm Limited and Contributors
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <fstream>
#include <string>
#include <sys/stat.h>
#include <unordered_map>
#include <vector>
namespace vkb
{
namespace fs
{
namespace path
{
enum Type
{
// Relative paths
Assets,
Shaders,
Storage,
Screenshots,
Logs,
/* NewFolder */
TotalRelativePathTypes,
// Special paths
ExternalStorage,
Temp
};
extern const std::unordered_map<Type, std::string> relative_paths;
/**
* @brief Gets the absolute path of a given type or a specific file
* @param type The type of file path
* @param file (Optional) The filename
* @throws runtime_error if the platform didn't initialize each path properly, path wasn't found or the path was found but is empty
* @return Path to the directory of a certain type
*/
const std::string get(const Type type, const std::string &file = "");
} // namespace path
/**
* @brief Helper to tell if a given path is a directory
* @param path A path to a directory
* @return True if the path points to a valid directory, false if not
*/
bool is_directory(const std::string &path);
/**
* @brief Checks if a file exists
* @param filename The filename to check
* @return True if the path points to a valid file, false if not
*/
bool is_file(const std::string &filename);
/**
* @brief Platform specific implementation to create a directory
* @param path A path to a directory
*/
void create_directory(const std::string &path);
/**
* @brief Recursively creates a directory
* @param root The root directory that the path is relative to
* @param path A path in the format 'this/is/an/example/path/'
*/
void create_path(const std::string &root, const std::string &path);
/**
* @brief Helper to read an asset file into a byte-array
*
* @param filename The path to the file (relative to the assets directory)
* @return A vector filled with data read from the file
*/
std::vector<uint8_t> read_asset(const std::string &filename);
/**
* @brief Helper to read a text file into a single string
*
* @param filename The path to the file (relative to the assets directory)
* @return A string of the text the file
*/
std::string read_text_file(const std::string &filename);
/**
* @brief Helper to read a shader file into an array of unsigned 32 bit integers
*
* @param filename The path to the file (relative to the assets directory)
* @return A vector filled with data read from the file
*/
std::vector<uint32_t> read_shader_binary_u32(const std::string &filename);
/**
* @brief Helper to read a temporary file into a byte-array
*
* @param filename The path to the file (relative to the temporary storage directory)
* @return A vector filled with data read from the file
*/
std::vector<uint8_t> read_temp(const std::string &filename);
/**
* @brief Helper to write to a file in temporary storage
*
* @param data A vector filled with data to write
* @param filename The path to the file (relative to the temporary storage directory)
* of data will be used.
*/
void write_temp(const std::vector<uint8_t> &data, const std::string &filename);
/**
* @brief Helper to write to a png image in permanent storage
*
* @param data A vector filled with pixel data to write in (R, G, B, A) format
* @param filename The name of the image file without an extension
* @param width The width of the image
* @param height The height of the image
* @param components The number of bytes per element
* @param row_stride The stride in bytes of a row of pixels
*/
void write_image(const uint8_t *data, const std::string &filename, const uint32_t width, const uint32_t height, const uint32_t components, const uint32_t row_stride);
} // namespace fs
} // namespace vkb
+67
View File
@@ -0,0 +1,67 @@
/* Copyright (c) 2024, Thomas Atkinson
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "filesystem/filesystem.hpp"
#include "core/platform/context.hpp"
#include "core/util/error.hpp"
#include "std_filesystem.hpp"
namespace vkb
{
namespace filesystem
{
static FileSystemPtr fs = nullptr;
void init()
{
fs = std::make_shared<StdFileSystem>();
}
void init_with_context(const PlatformContext &context)
{
fs = std::make_shared<StdFileSystem>(
context.external_storage_directory(),
context.temp_directory());
}
FileSystemPtr get()
{
assert(fs && "Filesystem not initialized");
return fs;
}
void FileSystem::write_file(const Path &path, const std::string &data)
{
write_file(path, std::vector<uint8_t>(data.begin(), data.end()));
}
std::string FileSystem::read_file_string(const Path &path)
{
auto bin = read_file_binary(path);
return {bin.begin(), bin.end()};
}
std::vector<uint8_t> FileSystem::read_file_binary(const Path &path)
{
auto stat = stat_file(path);
return read_chunk(path, 0, stat.size);
}
} // namespace filesystem
} // namespace vkb
+141
View File
@@ -0,0 +1,141 @@
/* Copyright (c) 2019-2025, Arm Limited and Contributors
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "filesystem/legacy.h"
#include "core/util/error.hpp"
VKBP_DISABLE_WARNINGS()
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>
VKBP_ENABLE_WARNINGS()
#include "filesystem/filesystem.hpp"
namespace vkb
{
namespace fs
{
namespace path
{
const std::unordered_map<Type, std::string> relative_paths = {
{Type::Assets, "assets/"},
{Type::Shaders, "shaders/"},
{Type::Storage, "output/"},
{Type::Screenshots, "output/images/"},
{Type::Logs, "output/logs/"},
};
const std::string get(const Type type, const std::string &file)
{
assert(relative_paths.size() == Type::TotalRelativePathTypes && "Not all paths are defined in filesystem, please check that each enum is specified");
// Check for special cases first
if (type == Type::Temp)
{
return vkb::filesystem::get()->temp_directory().string();
}
// Check for relative paths
auto it = relative_paths.find(type);
if (relative_paths.size() < Type::TotalRelativePathTypes)
{
throw std::runtime_error("Platform hasn't initialized the paths correctly");
}
else if (it == relative_paths.end())
{
throw std::runtime_error("Path enum doesn't exist, or wasn't specified in the path map");
}
else if (it->second.empty())
{
throw std::runtime_error("Path was found, but it is empty");
}
auto fs = vkb::filesystem::get();
auto path = fs->external_storage_directory() / it->second;
if (!is_directory(path))
{
create_path(fs->external_storage_directory().string(), it->second);
}
auto full_path = path / file;
return full_path.string();
}
} // namespace path
bool is_directory(const std::string &path)
{
return vkb::filesystem::get()->is_directory(path);
}
bool is_file(const std::string &filename)
{
return vkb::filesystem::get()->is_file(filename);
}
void create_directory(const std::string &path)
{
vkb::filesystem::get()->create_directory(path);
}
void create_path(const std::string &root, const std::string &path)
{
std::filesystem::path full_path = std::filesystem::path(root) / path;
if (!vkb::filesystem::get()->create_directory(full_path))
{
ERRORF("Failed to create directory: {}", full_path.string());
}
}
std::vector<uint8_t> read_asset(const std::string &filename)
{
return vkb::filesystem::get()->read_file_binary(path::get(path::Type::Assets) + filename);
}
std::string read_text_file(const std::string &filename)
{
return vkb::filesystem::get()->read_file_string(path::get(path::Type::Shaders) + filename);
}
std::vector<uint32_t> read_shader_binary_u32(const std::string &filename)
{
auto buffer = vkb::filesystem::get()->read_file_binary(path::get(path::Type::Shaders) + filename);
assert(buffer.size() % sizeof(uint32_t) == 0);
auto spirv = std::vector<uint32_t>(reinterpret_cast<uint32_t *>(buffer.data()), reinterpret_cast<uint32_t *>(buffer.data()) + buffer.size() / sizeof(uint32_t));
return spirv;
}
std::vector<uint8_t> read_temp(const std::string &filename)
{
return vkb::filesystem::get()->read_file_binary(path::get(path::Type::Temp) + filename);
}
void write_temp(const std::vector<uint8_t> &data, const std::string &filename)
{
vkb::filesystem::get()->write_file(path::get(path::Type::Temp) + filename, data);
}
void write_image(const uint8_t *data, const std::string &filename, const uint32_t width, const uint32_t height, const uint32_t components, const uint32_t row_stride)
{
stbi_write_png((path::get(path::Type::Screenshots) + filename + ".png").c_str(), width, height, components, data, row_stride);
}
} // namespace fs
} // namespace vkb
@@ -0,0 +1,159 @@
/* Copyright (c) 2024, Thomas Atkinson
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "std_filesystem.hpp"
#include <core/util/logging.hpp>
#include <filesystem>
#include <fstream>
namespace vkb
{
namespace filesystem
{
FileStat StdFileSystem::stat_file(const Path &path)
{
std::error_code ec;
auto fs_stat = std::filesystem::status(path, ec);
if (ec)
{
return FileStat{
false,
false,
0,
};
}
auto size = std::filesystem::file_size(path, ec);
if (ec)
{
size = 0;
}
return FileStat{
fs_stat.type() == std::filesystem::file_type::regular,
fs_stat.type() == std::filesystem::file_type::directory,
size,
};
}
bool StdFileSystem::is_file(const Path &path)
{
auto stat = stat_file(path);
return stat.is_file;
}
bool StdFileSystem::is_directory(const Path &path)
{
auto stat = stat_file(path);
return stat.is_directory;
}
bool StdFileSystem::exists(const Path &path)
{
auto stat = stat_file(path);
return stat.is_file || stat.is_directory;
}
bool StdFileSystem::create_directory(const Path &path)
{
std::error_code ec;
std::filesystem::create_directories(path, ec);
if (ec)
{
throw std::runtime_error("Failed to create directory at path: " + path.string());
}
return !ec;
}
std::vector<uint8_t> StdFileSystem::read_chunk(const Path &path, size_t offset, size_t count)
{
std::ifstream file{path, std::ios::binary | std::ios::ate};
if (!file.is_open())
{
throw std::runtime_error("Failed to open file for reading at path: " + path.string());
}
auto size = stat_file(path).size;
if (offset + count > size)
{
return {};
}
// read file contents
file.seekg(offset, std::ios::beg);
std::vector<uint8_t> data(count);
file.read(reinterpret_cast<char *>(data.data()), count);
return data;
}
void StdFileSystem::write_file(const Path &path, const std::vector<uint8_t> &data)
{
// create directory if it doesn't exist
auto parent = path.parent_path();
if (!std::filesystem::exists(parent))
{
create_directory(parent);
}
std::ofstream file{path, std::ios::binary | std::ios::trunc};
if (!file.is_open())
{
throw std::runtime_error("Failed to open file for writing at path: " + path.string());
}
file.write(reinterpret_cast<const char *>(data.data()), data.size());
}
void StdFileSystem::remove(const Path &path)
{
std::error_code ec;
std::filesystem::remove_all(path, ec);
if (ec)
{
throw std::runtime_error("Failed to remove file at path: " + path.string());
}
}
void StdFileSystem::set_external_storage_directory(const std::string &dir)
{
_external_storage_directory = dir;
}
const Path &StdFileSystem::external_storage_directory() const
{
return _external_storage_directory;
}
const Path &StdFileSystem::temp_directory() const
{
return _temp_directory;
}
} // namespace filesystem
} // namespace vkb
@@ -0,0 +1,63 @@
/* Copyright (c) 2024, Thomas Atkinson
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "filesystem/filesystem.hpp"
#include <filesystem>
namespace vkb
{
namespace filesystem
{
class StdFileSystem final : public FileSystem
{
public:
StdFileSystem(Path external_storage_directory = std::filesystem::current_path(), Path temp_directory = std::filesystem::temp_directory_path()) :
_external_storage_directory(std::move(external_storage_directory)),
_temp_directory(std::move(temp_directory))
{}
virtual ~StdFileSystem() = default;
FileStat stat_file(const Path &path) override;
bool is_file(const Path &path) override;
bool is_directory(const Path &path) override;
bool exists(const Path &path) override;
bool create_directory(const Path &path) override;
std::vector<uint8_t> read_chunk(const Path &path, size_t offset, size_t count) override;
void write_file(const Path &path, const std::vector<uint8_t> &data) override;
virtual void remove(const Path &path) override;
virtual void set_external_storage_directory(const std::string &dir) override;
const Path &external_storage_directory() const override;
const Path &temp_directory() const override;
private:
Path _external_storage_directory;
Path _temp_directory;
};
} // namespace filesystem
} // namespace vkb