diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 378c7aaef..a8f303600 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2023, Arm Limited and Contributors +# Copyright (c) 2019-2024, Arm Limited and Contributors # # SPDX-License-Identifier: Apache-2.0 # @@ -41,7 +41,7 @@ else() add_executable(${PROJECT_NAME} WIN32 ${SRC}) endif() -target_link_libraries(${PROJECT_NAME} PRIVATE vkb__core apps plugins) +target_link_libraries(${PROJECT_NAME} PRIVATE vkb__core vkb__filesystem apps plugins) # Create android project if(ANDROID) diff --git a/app/android/java/com/khronos/vulkan_samples/SampleLauncherActivity.java b/app/android/java/com/khronos/vulkan_samples/SampleLauncherActivity.java index 8736594bf..499a0dff4 100644 --- a/app/android/java/com/khronos/vulkan_samples/SampleLauncherActivity.java +++ b/app/android/java/com/khronos/vulkan_samples/SampleLauncherActivity.java @@ -66,13 +66,6 @@ protected void onCreate(Bundle savedInstanceState) { setSupportActionBar(toolbar); if (loadNativeLibrary(getResources().getString(R.string.native_lib_name))) { - // Initialize cpp android platform - File external_files_dir = getExternalFilesDir(""); - File temp_files_dir = getCacheDir(); - if (external_files_dir != null && temp_files_dir != null) { - initFilePath(external_files_dir.toString(), temp_files_dir.toString()); - } - // Get sample info from cpp cmake generated file samples = new SampleStore(Arrays.asList(getSamples())); } @@ -340,9 +333,4 @@ public void launchSample(String sampleID) { * @param args The arguments that are to be passed to the app */ private native void sendArgumentsToPlatform(String[] args); - - /** - * @brief Initiate the file system for the Native Application - */ - private native void initFilePath(String external_dir, String temp_path); } diff --git a/app/main.cpp b/app/main.cpp index 39c1e864e..97c441dcc 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -15,11 +15,12 @@ * limitations under the License. */ -#include "common/logging.h" +#include "core/util/logging.hpp" #include "platform/platform.h" #include "plugins/plugins.h" #include +#include #if defined(PLATFORM__ANDROID) # include "platform/android/android_platform.h" @@ -35,6 +36,8 @@ CUSTOM_MAIN(context) { + vkb::filesystem::init_with_context(context); + #if defined(PLATFORM__ANDROID) vkb::AndroidPlatform platform{context}; #elif defined(PLATFORM__WINDOWS) diff --git a/app/plugins/screenshot/screenshot.h b/app/plugins/screenshot/screenshot.h index 5778ab9ff..3a11f8319 100644 --- a/app/plugins/screenshot/screenshot.h +++ b/app/plugins/screenshot/screenshot.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020-2021, Arm Limited and Contributors +/* Copyright (c) 2020-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -17,7 +17,7 @@ #pragma once -#include "platform/filesystem.h" +#include "filesystem/legacy.h" #include "platform/plugins/plugin_base.h" namespace plugins @@ -28,11 +28,11 @@ using ScreenshotTags = vkb::PluginBase; /** * @brief Screenshot - * + * * Capture a screen shot of the last rendered image at a given frame. The output can also be named - * + * * Usage: vulkan_sample sample afbc --screenshot 1 --screenshot-output afbc-screenshot - * + * */ class Screenshot : public ScreenshotTags { diff --git a/bldsys/cmake/template/sample/sample.cpp.in b/bldsys/cmake/template/sample/sample.cpp.in index c239462e0..dfda32cd5 100644 --- a/bldsys/cmake/template/sample/sample.cpp.in +++ b/bldsys/cmake/template/sample/sample.cpp.in @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -20,7 +20,7 @@ #include "common/vk_common.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" +#include "filesystem/legacy.h" #include "platform/platform.h" #include "rendering/subpasses/forward_subpass.h" #include "stats/stats.h" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 86035733f..aeff39b4b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2023, Thomas Atkinson +# Copyright (c) 2023-2024, Thomas Atkinson # # SPDX-License-Identifier: Apache-2.0 # @@ -25,3 +25,6 @@ elseif(APPLE OR UNIX) else() message(FATAL_ERROR "Unsupported platform") endif() + + +add_subdirectory(filesystem) \ No newline at end of file diff --git a/components/android/src/context.cpp b/components/android/src/context.cpp index 161660f1a..fd44fa8cc 100644 --- a/components/android/src/context.cpp +++ b/components/android/src/context.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, Thomas Atkinson +/* Copyright (c) 2023-2024, Thomas Atkinson * * SPDX-License-Identifier: Apache-2.0 * @@ -21,18 +21,7 @@ extern "C" { - JNIEXPORT void JNICALL - Java_com_khronos_vulkan_1samples_SampleLauncherActivity_initFilePath(JNIEnv *env, jobject thiz, jstring external_dir, jstring temp_dir) - { - const char *external_dir_cstr = env->GetStringUTFChars(external_dir, 0); - vkb::AndroidPlatformContext::android_external_storage_directory = std::string(external_dir_cstr) + "/"; - env->ReleaseStringUTFChars(external_dir, external_dir_cstr); - - const char *temp_dir_cstr = env->GetStringUTFChars(temp_dir, 0); - vkb::AndroidPlatformContext::android_temp_directory = std::string(temp_dir_cstr) + "/"; - env->ReleaseStringUTFChars(temp_dir, temp_dir_cstr); - } - + // TODO: Arguments can be parsed from the bundle JNIEXPORT void JNICALL Java_com_khronos_vulkan_1samples_SampleLauncherActivity_sendArgumentsToPlatform(JNIEnv *env, jobject thiz, jobjectArray arg_strings) { @@ -53,17 +42,44 @@ extern "C" } } +namespace details +{ +std::string get_external_storage_directory(android_app *app) +{ + return app->activity->externalDataPath; +} + +std::string get_external_cache_directory(android_app *app) +{ + JNIEnv *env; + app->activity->vm->AttachCurrentThread(&env, NULL); + + jclass cls = env->FindClass("android/app/NativeActivity"); + jmethodID getCacheDir = env->GetMethodID(cls, "getCacheDir", "()Ljava/io/File;"); + jobject cache_dir = env->CallObjectMethod(app->activity->javaGameActivity, getCacheDir); + + jclass fcls = env->FindClass("java/io/File"); + jmethodID getPath = env->GetMethodID(fcls, "getPath", "()Ljava/lang/String;"); + jstring path_string = (jstring) env->CallObjectMethod(cache_dir, getPath); + + const char *path_chars = env->GetStringUTFChars(path_string, NULL); + std::string temp_folder(path_chars); + + env->ReleaseStringUTFChars(path_string, path_chars); + app->activity->vm->DetachCurrentThread(); + return temp_folder; +} +} // namespace details + namespace vkb { -std::string AndroidPlatformContext::android_external_storage_directory = {}; -std::string AndroidPlatformContext::android_temp_directory = {}; -std::vector AndroidPlatformContext::android_arguments = {}; +std::vector AndroidPlatformContext::android_arguments = {}; AndroidPlatformContext::AndroidPlatformContext(android_app *app) : PlatformContext{}, app{app} { - _external_storage_directory = android_external_storage_directory; - _temp_directory = android_temp_directory; + _external_storage_directory = details::get_external_storage_directory(app); + _temp_directory = details::get_external_cache_directory(app); _arguments = android_arguments; } } // namespace vkb \ No newline at end of file diff --git a/components/core/CMakeLists.txt b/components/core/CMakeLists.txt index 5a33b3dd6..817832060 100644 --- a/components/core/CMakeLists.txt +++ b/components/core/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2023, Thomas Atkinson +# Copyright (c) 2023-2024, Thomas Atkinson # # SPDX-License-Identifier: Apache-2.0 # @@ -17,14 +17,18 @@ vkb__register_component( NAME core HEADERS + include/core/platform/context.hpp + include/core/platform/entrypoint.hpp + include/core/util/strings.hpp include/core/util/error.hpp include/core/util/hash.hpp + include/core/util/logging.hpp SRC src/strings.cpp + src/logging.cpp LINK_LIBS - spdlog - fmt + spdlog::spdlog ) vkb__register_tests( diff --git a/framework/common/logging.h b/components/core/include/core/util/logging.hpp similarity index 72% rename from framework/common/logging.h rename to components/core/include/core/util/logging.hpp index 571f21d3d..e9f53b3fb 100644 --- a/framework/common/logging.h +++ b/components/core/include/core/util/logging.hpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2023, Arm Limited and Contributors +/* Copyright (c) 2018-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -17,20 +17,21 @@ #pragma once -#include +#include #include #define LOGGER_FORMAT "[%^%l%$] %v" #define PROJECT_NAME "VulkanSamples" -// Mainly for IDEs -#ifndef ROOT_PATH_SIZE -# define ROOT_PATH_SIZE 0 -#endif - -#define __FILENAME__ (static_cast(__FILE__) + ROOT_PATH_SIZE) - #define LOGI(...) spdlog::info(__VA_ARGS__); #define LOGW(...) spdlog::warn(__VA_ARGS__); -#define LOGE(...) spdlog::error("[{}:{}] {}", __FILENAME__, __LINE__, fmt::format(__VA_ARGS__)); +#define LOGE(...) spdlog::error("{}", fmt::format(__VA_ARGS__)); #define LOGD(...) spdlog::debug(__VA_ARGS__); + +namespace vkb +{ +namespace logging +{ +void init(); +} +} // namespace vkb \ No newline at end of file diff --git a/components/core/src/logging.cpp b/components/core/src/logging.cpp new file mode 100644 index 000000000..c6ac1b9c9 --- /dev/null +++ b/components/core/src/logging.cpp @@ -0,0 +1,52 @@ +/* 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 "core/util/logging.hpp" + +#include "spdlog/cfg/env.h" + +#ifdef PLATFORM__ANDROID +# include "spdlog/sinks/android_sink.h" +#else +# include "spdlog/sinks/stdout_color_sinks.h" +#endif + +namespace vkb +{ +namespace logging +{ +void init() +{ + // Taken from "spdlog/cfg/env.h" and renamed SPDLOG_LEVEL to VKB_LOG_LEVEL + auto env_val = spdlog::details::os::getenv("VKB_LOG_LEVEL"); + if (!env_val.empty()) + { + spdlog::cfg::helpers::load_levels(env_val); + } + +#ifdef PLATFORM__ANDROID + auto logger = spdlog::android_logger_mt("vkb", "VulkanSamples"); +#else + auto logger = spdlog::stdout_color_mt("vkb"); +#endif + + logger->set_pattern(LOGGER_FORMAT); + logger->set_level(spdlog::level::trace); + spdlog::set_default_logger(logger); +} +} // namespace logging +} // namespace vkb \ No newline at end of file diff --git a/components/filesystem/CMakeLists.txt b/components/filesystem/CMakeLists.txt new file mode 100644 index 000000000..65984f288 --- /dev/null +++ b/components/filesystem/CMakeLists.txt @@ -0,0 +1,46 @@ +# 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. + +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() + +vkb__register_tests( + COMPONENT filesystem + NAME filesystem + SRC + tests/filesystem.test.cpp + LINK_LIBS + vkb__filesystem +) diff --git a/components/filesystem/README.adoc b/components/filesystem/README.adoc new file mode 100644 index 000000000..3da4f8d4d --- /dev/null +++ b/components/filesystem/README.adoc @@ -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 \ No newline at end of file diff --git a/components/filesystem/include/filesystem/filesystem.hpp b/components/filesystem/include/filesystem/filesystem.hpp new file mode 100644 index 000000000..d316a8b37 --- /dev/null +++ b/components/filesystem/include/filesystem/filesystem.hpp @@ -0,0 +1,84 @@ +/* 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 +#include +#include +#include + +#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 read_chunk(const Path &path, size_t offset, size_t count) = 0; + virtual void write_file(const Path &path, const std::vector &data) = 0; + virtual void remove(const Path &path) = 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 read_file_binary(const Path &path); +}; + +using FileSystemPtr = std::shared_ptr; + +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 \ No newline at end of file diff --git a/framework/platform/filesystem.h b/components/filesystem/include/filesystem/legacy.h similarity index 86% rename from framework/platform/filesystem.h rename to components/filesystem/include/filesystem/legacy.h index 8ddc197f0..63192beef 100644 --- a/framework/platform/filesystem.h +++ b/components/filesystem/include/filesystem/legacy.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -25,8 +25,6 @@ #include #include -#include - namespace vkb { namespace fs @@ -46,7 +44,6 @@ enum Type // Special paths ExternalStorage, - WorkingDir = ExternalStorage, Temp }; @@ -93,11 +90,9 @@ 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) - * @param count (optional) How many bytes to read. If 0 or not specified, the size - * of the file will be used. * @return A vector filled with data read from the file */ -std::vector read_asset(const std::string &filename, const uint32_t count = 0); +std::vector read_asset(const std::string &filename); /** * @brief Helper to read a shader file into a single string @@ -119,22 +114,18 @@ std::vector read_shader_binary(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) - * @param count (optional) How many bytes to read. If 0 or not specified, the size - * of the file will be used. * @return A vector filled with data read from the file */ -std::vector read_temp(const std::string &filename, const uint32_t count = 0); +std::vector 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) - * @param count (optional) How many bytes to write. If 0 or not specified, the size * of data will be used. */ -void write_temp(const std::vector &data, const std::string &filename, const uint32_t count = 0); - +void write_temp(const std::vector &data, const std::string &filename); /** * @brief Helper to write to a png image in permanent storage * diff --git a/components/filesystem/src/filesystem.cpp b/components/filesystem/src/filesystem.cpp new file mode 100644 index 000000000..ad915fc21 --- /dev/null +++ b/components/filesystem/src/filesystem.cpp @@ -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(); +} + +void init_with_context(const PlatformContext &context) +{ + fs = std::make_shared( + 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(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 FileSystem::read_file_binary(const Path &path) +{ + auto stat = stat_file(path); + return read_chunk(path, 0, stat.size); +} + +} // namespace filesystem +} // namespace vkb \ No newline at end of file diff --git a/components/filesystem/src/legacy.cpp b/components/filesystem/src/legacy.cpp new file mode 100644 index 000000000..728aed930 --- /dev/null +++ b/components/filesystem/src/legacy.cpp @@ -0,0 +1,137 @@ +/* Copyright (c) 2019-2024, 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 +VKBP_ENABLE_WARNINGS() + +#include "filesystem/filesystem.hpp" + +namespace vkb +{ +namespace fs +{ +namespace path +{ +const std::unordered_map 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) +{ + for (auto it = path.begin(); it != path.end(); ++it) + { + it = std::find(it, path.end(), '/'); + create_directory(root + std::string(path.begin(), it)); + } +} + +std::vector read_asset(const std::string &filename) +{ + return vkb::filesystem::get()->read_file_binary(path::get(path::Type::Assets) + filename); +} + +std::string read_shader(const std::string &filename) +{ + return vkb::filesystem::get()->read_file_string(path::get(path::Type::Shaders) + filename); +} + +std::vector read_shader_binary(const std::string &filename) +{ + return vkb::filesystem::get()->read_file_binary(path::get(path::Type::Shaders) + filename); +} + +std::vector 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 &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 diff --git a/components/filesystem/src/std_filesystem.cpp b/components/filesystem/src/std_filesystem.cpp new file mode 100644 index 000000000..6be33a533 --- /dev/null +++ b/components/filesystem/src/std_filesystem.cpp @@ -0,0 +1,154 @@ +/* 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 + +#include +#include + +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_directory(path, ec); + + if (ec) + { + throw std::runtime_error("Failed to create directory"); + } + + return !ec; +} + +std::vector 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"); + } + + auto size = stat_file(path).size; + + if (offset + count > size) + { + return {}; + } + + // read file contents + file.seekg(offset, std::ios::beg); + std::vector data(count); + file.read(reinterpret_cast(data.data()), count); + + return data; +} + +void StdFileSystem::write_file(const Path &path, const std::vector &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"); + } + + file.write(reinterpret_cast(data.data()), data.size()); +} + +void StdFileSystem::remove(const Path &path) +{ + std::error_code ec; + + std::filesystem::remove(path, ec); + + if (ec) + { + throw std::runtime_error("Failed to remove file"); + } +} + +const Path &StdFileSystem::external_storage_directory() const +{ + return _external_storage_directory; +} + +const Path &StdFileSystem::temp_directory() const +{ + return _temp_directory; +} + +} // namespace filesystem +} // namespace vkb \ No newline at end of file diff --git a/components/filesystem/src/std_filesystem.hpp b/components/filesystem/src/std_filesystem.hpp new file mode 100644 index 000000000..df207c495 --- /dev/null +++ b/components/filesystem/src/std_filesystem.hpp @@ -0,0 +1,61 @@ +/* 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 + +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 read_chunk(const Path &path, size_t offset, size_t count) override; + + void write_file(const Path &path, const std::vector &data) override; + + virtual void remove(const Path &path) 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 \ No newline at end of file diff --git a/components/filesystem/tests/filesystem.test.cpp b/components/filesystem/tests/filesystem.test.cpp new file mode 100644 index 000000000..17d8c0d3c --- /dev/null +++ b/components/filesystem/tests/filesystem.test.cpp @@ -0,0 +1,126 @@ +/* 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. + */ + +#include + +#include "filesystem/filesystem.hpp" + +using namespace vkb::filesystem; + +void create_test_file(FileSystemPtr fs, const Path &path, const std::string &data) +{ + REQUIRE(fs); + REQUIRE_NOTHROW(fs->write_file(path, data)); + REQUIRE(fs->exists(path)); + REQUIRE(fs->is_file(path)); + + const auto written_data = fs->read_file_string(path); + REQUIRE(data == written_data); +} + +void delete_test_file(FileSystemPtr fs, const Path &path) +{ + REQUIRE(fs); + REQUIRE(fs->exists(path)); + REQUIRE(fs->is_file(path)); + REQUIRE_NOTHROW(fs->remove(path)); + REQUIRE_FALSE(fs->exists(path)); +} + +TEST_CASE("File read and write", "[filesystem]") +{ + vkb::filesystem::init(); + + auto fs = vkb::filesystem::get(); + + const auto test_file = fs->temp_directory() / "vulkan_samples" / "test.txt"; + const std::string test_data = "Hello, World!"; + + create_test_file(fs, test_file, test_data); + delete_test_file(fs, test_file); +} + +TEST_CASE("Read file chunk", "[filesystem]") +{ + vkb::filesystem::init(); + + auto fs = vkb::filesystem::get(); + + const auto test_file = fs->temp_directory() / "vulkan_samples" / "chunk_test.txt"; + const std::string test_data = "Hello, World!"; + + create_test_file(fs, test_file, test_data); + + const auto chunk = fs->read_chunk(test_file, 0, 5); + std::string chunk_str(chunk.begin(), chunk.end()); + REQUIRE(chunk_str == "Hello"); + + delete_test_file(fs, test_file); +} + +TEST_CASE("Read file chunk out of bounds", "[filesystem]") +{ + vkb::filesystem::init(); + + auto fs = vkb::filesystem::get(); + + const auto test_file = fs->temp_directory() / "vulkan_samples" / "chunk_oob_test.txt"; + const std::string test_data = "Hello, World!"; + + create_test_file(fs, test_file, test_data); + + const auto chunk = fs->read_chunk(test_file, 0, 100); + REQUIRE(chunk.empty()); + + delete_test_file(fs, test_file); +} + +TEST_CASE("Read file chunk with offset", "[filesystem]") +{ + vkb::filesystem::init(); + + auto fs = vkb::filesystem::get(); + + const auto test_file = fs->temp_directory() / "vulkan_samples" / "chunk_offset_test.txt"; + const std::string test_data = "Hello, World!"; + + create_test_file(fs, test_file, test_data); + + const auto chunk = fs->read_chunk(test_file, 7, 5); + std::string chunk_str(chunk.begin(), chunk.end()); + REQUIRE(chunk_str == "World"); + + delete_test_file(fs, test_file); +} + +TEST_CASE("Read binary file", "[filesystem]") +{ + vkb::filesystem::init(); + + auto fs = vkb::filesystem::get(); + + const auto test_file = fs->temp_directory() / "vulkan_samples" / "binary_test.txt"; + const std::string test_data = "Hello, World!"; + + create_test_file(fs, test_file, test_data); + + const auto binary = fs->read_file_binary(test_file); + std::string binary_str(binary.begin(), binary.end()); + REQUIRE(binary_str == test_data); + + delete_test_file(fs, test_file); +} \ No newline at end of file diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index 9dc0cc551..755e4b716 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -82,7 +82,6 @@ set(COMMON_FILES common/vk_initializers.h common/glm_common.h common/resource_caching.h - common/logging.h common/helpers.h common/error.h common/utils.h @@ -326,7 +325,6 @@ set(PLATFORM_FILES platform/application.h platform/platform.h platform/window.h - platform/filesystem.h platform/input_events.h platform/configuration.h platform/parser.h @@ -339,7 +337,6 @@ set(PLATFORM_FILES platform/application.cpp platform/platform.cpp platform/window.cpp - platform/filesystem.cpp platform/input_events.cpp platform/configuration.cpp platform/parser.cpp @@ -513,6 +510,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC $ -#include "common/logging.h" #include "core/device.h" +#include "core/util/logging.hpp" namespace vkb { diff --git a/framework/common/error.h b/framework/common/error.h index 81180f744..b1549bba3 100644 --- a/framework/common/error.h +++ b/framework/common/error.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2023, Arm Limited and Contributors +/* Copyright (c) 2018-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -22,7 +22,7 @@ #include #include "common/strings.h" -#include "logging.h" +#include "core/util/logging.hpp" #include "vk_common.h" #if defined(__clang__) diff --git a/framework/common/hpp_vk_common.h b/framework/common/hpp_vk_common.h index 489f15dd6..a76a7ccd2 100644 --- a/framework/common/hpp_vk_common.h +++ b/framework/common/hpp_vk_common.h @@ -19,7 +19,7 @@ #include "common/vk_common.h" -#include "common/logging.h" +#include "core/util/logging.hpp" #include "vulkan/vulkan.hpp" #include "vulkan/vulkan_format_traits.hpp" diff --git a/framework/common/utils.h b/framework/common/utils.h index 8ca4fef1b..a1219cfab 100644 --- a/framework/common/utils.h +++ b/framework/common/utils.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2023, Arm Limited and Contributors +/* Copyright (c) 2018-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -24,7 +24,7 @@ VKBP_DISABLE_WARNINGS() #include "glm/gtx/quaternion.hpp" VKBP_ENABLE_WARNINGS() -#include "platform/filesystem.h" +#include "filesystem/legacy.h" #include "rendering/pipeline_state.h" #include "rendering/render_context.h" #include "scene_graph/components/sub_mesh.h" diff --git a/framework/common/vk_common.cpp b/framework/common/vk_common.cpp index cb3d8d921..905e909f6 100644 --- a/framework/common/vk_common.cpp +++ b/framework/common/vk_common.cpp @@ -20,8 +20,8 @@ #include +#include "filesystem/legacy.h" #include "glsl_compiler.h" -#include "platform/filesystem.h" std::ostream &operator<<(std::ostream &os, const VkResult result) { diff --git a/framework/core/descriptor_set.cpp b/framework/core/descriptor_set.cpp index ebda0c92d..5285c0ed8 100644 --- a/framework/core/descriptor_set.cpp +++ b/framework/core/descriptor_set.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2022, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -17,19 +17,19 @@ #include "descriptor_set.h" -#include "common/logging.h" #include "common/resource_caching.h" +#include "core/util/logging.hpp" #include "descriptor_pool.h" #include "descriptor_set_layout.h" #include "device.h" namespace vkb { -DescriptorSet::DescriptorSet(Device & device, - const DescriptorSetLayout & descriptor_set_layout, - DescriptorPool & descriptor_pool, +DescriptorSet::DescriptorSet(Device &device, + const DescriptorSetLayout &descriptor_set_layout, + DescriptorPool &descriptor_pool, const BindingMap &buffer_infos, - const BindingMap & image_infos) : + const BindingMap &image_infos) : device{device}, descriptor_set_layout{descriptor_set_layout}, descriptor_pool{descriptor_pool}, diff --git a/framework/core/device.h b/framework/core/device.h index d4bb7b590..097c007ed 100644 --- a/framework/core/device.h +++ b/framework/core/device.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors - * Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2019-2024, Arm Limited and Contributors + * Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -19,7 +19,6 @@ #pragma once #include "common/helpers.h" -#include "common/logging.h" #include "common/vk_common.h" #include "core/command_buffer.h" #include "core/command_pool.h" @@ -35,6 +34,7 @@ #include "core/render_pass.h" #include "core/shader_module.h" #include "core/swapchain.h" +#include "core/util/logging.hpp" #include "core/vulkan_resource.h" #include "fence_pool.h" #include "rendering/pipeline_state.h" diff --git a/framework/core/hpp_instance.cpp b/framework/core/hpp_instance.cpp index 916145cfc..60ef351fb 100644 --- a/framework/core/hpp_instance.cpp +++ b/framework/core/hpp_instance.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -17,8 +17,8 @@ #include -#include #include +#include #include #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS) diff --git a/framework/core/hpp_physical_device.cpp b/framework/core/hpp_physical_device.cpp index 1d9ceb7b9..695c6c639 100644 --- a/framework/core/hpp_physical_device.cpp +++ b/framework/core/hpp_physical_device.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -17,7 +17,7 @@ #include -#include +#include namespace vkb { diff --git a/framework/core/hpp_swapchain.cpp b/framework/core/hpp_swapchain.cpp index 7024f7ace..e8671d4d1 100644 --- a/framework/core/hpp_swapchain.cpp +++ b/framework/core/hpp_swapchain.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -17,8 +17,8 @@ #include "core/hpp_swapchain.h" -#include "common/logging.h" #include "core/hpp_device.h" +#include "core/util/logging.hpp" namespace vkb { diff --git a/framework/core/shader_module.cpp b/framework/core/shader_module.cpp index a3ae6634a..e6243a83e 100644 --- a/framework/core/shader_module.cpp +++ b/framework/core/shader_module.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -17,10 +17,10 @@ #include "shader_module.h" -#include "common/logging.h" +#include "core/util/logging.hpp" #include "device.h" +#include "filesystem/legacy.h" #include "glsl_compiler.h" -#include "platform/filesystem.h" #include "spirv_reflection.h" namespace vkb diff --git a/framework/core/swapchain.cpp b/framework/core/swapchain.cpp index 4b6e88782..b4e5fec84 100644 --- a/framework/core/swapchain.cpp +++ b/framework/core/swapchain.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -17,7 +17,7 @@ #include "core/swapchain.h" -#include "common/logging.h" +#include "core/util/logging.hpp" #include "device.h" namespace vkb diff --git a/framework/gltf_loader.cpp b/framework/gltf_loader.cpp index 6e6eddc27..db5961359 100644 --- a/framework/gltf_loader.cpp +++ b/framework/gltf_loader.cpp @@ -1,5 +1,5 @@ -/* Copyright (c) 2018-2023, Arm Limited and Contributors - * Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2018-2024, Arm Limited and Contributors + * Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -30,12 +30,12 @@ VKBP_DISABLE_WARNINGS() VKBP_ENABLE_WARNINGS() #include "api_vulkan_sample.h" -#include "common/logging.h" #include "common/utils.h" #include "common/vk_common.h" #include "core/device.h" #include "core/image.h" -#include "platform/filesystem.h" +#include "core/util/logging.hpp" +#include "filesystem/legacy.h" #include "scene_graph/components/camera.h" #include "scene_graph/components/image.h" #include "scene_graph/components/image/astc.h" diff --git a/framework/gui.cpp b/framework/gui.cpp index 5fce14ffe..259b095ad 100644 --- a/framework/gui.cpp +++ b/framework/gui.cpp @@ -29,7 +29,6 @@ VKBP_DISABLE_WARNINGS() VKBP_ENABLE_WARNINGS() #include "buffer_pool.h" -#include "common/logging.h" #include "common/utils.h" #include "common/vk_common.h" #include "common/vk_initializers.h" @@ -38,8 +37,9 @@ VKBP_ENABLE_WARNINGS() #include "core/pipeline.h" #include "core/pipeline_layout.h" #include "core/shader_module.h" +#include "core/util/logging.hpp" +#include "filesystem/legacy.h" #include "imgui_internal.h" -#include "platform/filesystem.h" #include "platform/window.h" #include "rendering/render_context.h" #include "timer.h" diff --git a/framework/gui.h b/framework/gui.h index 446f425e2..bb492b2e8 100644 --- a/framework/gui.h +++ b/framework/gui.h @@ -30,7 +30,7 @@ #include "core/sampler.h" #include "debug_info.h" #include "drawer.h" -#include "platform/filesystem.h" +#include "filesystem/legacy.h" #include "platform/input_events.h" #include "rendering/render_context.h" #include "stats/stats.h" diff --git a/framework/heightmap.cpp b/framework/heightmap.cpp index b2bb04946..e5b60fdac 100644 --- a/framework/heightmap.cpp +++ b/framework/heightmap.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -25,7 +25,7 @@ VKBP_DISABLE_WARNINGS() #include "common/glm_common.h" VKBP_ENABLE_WARNINGS() -#include "platform/filesystem.h" +#include "filesystem/legacy.h" namespace vkb { diff --git a/framework/hpp_gui.cpp b/framework/hpp_gui.cpp index 08afef98d..069112db4 100644 --- a/framework/hpp_gui.cpp +++ b/framework/hpp_gui.cpp @@ -22,6 +22,8 @@ #include #include +#include + namespace vkb { namespace @@ -392,7 +394,7 @@ bool HPPGui::update_buffers() void HPPGui::update_buffers(vkb::core::HPPCommandBuffer &command_buffer) const { - ImDrawData *draw_data = ImGui::GetDrawData(); + ImDrawData *draw_data = ImGui::GetDrawData(); vkb::rendering::HPPRenderFrame &render_frame = sample.get_render_context().get_active_frame(); if (!draw_data || (draw_data->TotalVtxCount == 0) || (draw_data->TotalIdxCount == 0)) diff --git a/framework/hpp_gui.h b/framework/hpp_gui.h index 74bfc64fd..c360a6bed 100644 --- a/framework/hpp_gui.h +++ b/framework/hpp_gui.h @@ -24,7 +24,7 @@ #include "core/hpp_pipeline_layout.h" #include "debug_info.h" #include "drawer.h" -#include "platform/filesystem.h" +#include "filesystem/legacy.h" #include "platform/input_events.h" #include "stats/hpp_stats.h" @@ -59,7 +59,7 @@ struct HPPFont } std::vector data; - ImFont *handle = nullptr; + ImFont *handle = nullptr; std::string name; float size = 0.0f; }; @@ -257,7 +257,7 @@ class HPPGui private: PushConstBlock push_const_block; - HPPVulkanSample &sample; + HPPVulkanSample &sample; std::unique_ptr vertex_buffer; std::unique_ptr index_buffer; size_t last_vertex_buffer_size = 0; diff --git a/framework/platform/android/android_platform.cpp b/framework/platform/android/android_platform.cpp index a71b20a94..8cf0290d1 100644 --- a/framework/platform/android/android_platform.cpp +++ b/framework/platform/android/android_platform.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -34,8 +34,8 @@ VKBP_DISABLE_WARNINGS() VKBP_ENABLE_WARNINGS() #include "apps.h" -#include "common/logging.h" #include "common/strings.h" +#include "core/util/logging.hpp" #include "platform/android/android_window.h" #include "platform/input_events.h" @@ -335,17 +335,6 @@ bool motion_event_filter(const GameActivityMotionEvent *event) } } // namespace -namespace fs -{ -void create_directory(const std::string &path) -{ - if (!is_directory(path)) - { - mkdir(path.c_str(), 0777); - } -} -} // namespace fs - AndroidPlatform::AndroidPlatform(const PlatformContext &context) : Platform{context} { diff --git a/framework/platform/application.cpp b/framework/platform/application.cpp index 9948cc77d..03dff8ec8 100644 --- a/framework/platform/application.cpp +++ b/framework/platform/application.cpp @@ -17,7 +17,7 @@ #include "application.h" -#include "common/logging.h" +#include "core/util/logging.hpp" #include "platform/window.h" namespace vkb diff --git a/framework/platform/filesystem.cpp b/framework/platform/filesystem.cpp deleted file mode 100644 index aac770b16..000000000 --- a/framework/platform/filesystem.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright (c) 2019-2023, 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 "platform/filesystem.h" - -#include "common/error.h" - -VKBP_DISABLE_WARNINGS() -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include -VKBP_ENABLE_WARNINGS() - -#include "platform/platform.h" - -namespace vkb -{ -namespace fs -{ -namespace path -{ -const std::unordered_map 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::WorkingDir) - { - return Platform::get_external_storage_directory(); - } - else if (type == Type::Temp) - { - return Platform::get_temp_directory(); - } - - // 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 path = Platform::get_external_storage_directory() + it->second; - - if (!is_directory(path)) - { - create_path(Platform::get_external_storage_directory(), it->second); - } - - return path + file; -} -} // namespace path - -bool is_directory(const std::string &path) -{ - struct stat info; - if (stat(path.c_str(), &info) != 0) - { - return false; - } - else if (info.st_mode & S_IFDIR) - { - return true; - } - else - { - return false; - } -} - -bool is_file(const std::string &filename) -{ - std::ifstream f(filename.c_str()); - return !f.fail(); -} - -void create_path(const std::string &root, const std::string &path) -{ - for (auto it = path.begin(); it != path.end(); ++it) - { - it = std::find(it, path.end(), '/'); - create_directory(root + std::string(path.begin(), it)); - } -} - -std::string read_text_file(const std::string &filename) -{ - std::vector data; - - std::ifstream file; - - file.open(filename, std::ios::in); - - if (!file.is_open()) - { - throw std::runtime_error("Failed to open file: " + filename); - } - - return std::string{(std::istreambuf_iterator(file)), - (std::istreambuf_iterator())}; -} - -std::vector read_binary_file(const std::string &filename, const uint32_t count) -{ - std::vector data; - - std::ifstream file; - - file.open(filename, std::ios::in | std::ios::binary); - - if (!file.is_open()) - { - throw std::runtime_error("Failed to open file: " + filename); - } - - uint64_t read_count = count; - if (count == 0) - { - file.seekg(0, std::ios::end); - read_count = static_cast(file.tellg()); - file.seekg(0, std::ios::beg); - } - - data.resize(static_cast(read_count)); - file.read(reinterpret_cast(data.data()), read_count); - file.close(); - - return data; -} - -static void write_binary_file(const std::vector &data, const std::string &filename, const uint32_t count) -{ - std::ofstream file; - - file.open(filename, std::ios::out | std::ios::binary | std::ios::trunc); - - if (!file.is_open()) - { - throw std::runtime_error("Failed to open file: " + filename); - } - - uint64_t write_count = count; - if (count == 0) - { - write_count = data.size(); - } - - file.write(reinterpret_cast(data.data()), write_count); - file.close(); -} - -std::vector read_asset(const std::string &filename, const uint32_t count) -{ - return read_binary_file(path::get(path::Type::Assets) + filename, count); -} - -std::string read_shader(const std::string &filename) -{ - return read_text_file(path::get(path::Type::Shaders) + filename); -} - -std::vector read_shader_binary(const std::string &filename) -{ - return read_binary_file(path::get(path::Type::Shaders) + filename, 0); -} - -std::vector read_temp(const std::string &filename, const uint32_t count) -{ - return read_binary_file(path::get(path::Type::Temp) + filename, count); -} - -void write_temp(const std::vector &data, const std::string &filename, const uint32_t count) -{ - write_binary_file(data, path::get(path::Type::Temp) + filename, count); -} - -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 diff --git a/framework/platform/glfw_window.cpp b/framework/platform/glfw_window.cpp index 07183b951..ec5df8d96 100644 --- a/framework/platform/glfw_window.cpp +++ b/framework/platform/glfw_window.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -29,7 +29,7 @@ VKBP_DISABLE_WARNINGS() #include VKBP_ENABLE_WARNINGS() -#include "common/logging.h" +#include "core/util/logging.hpp" #include "platform/platform.h" namespace vkb diff --git a/framework/platform/parsers/CLI11.cpp b/framework/platform/parsers/CLI11.cpp index 9bfd187e7..2a1c66505 100644 --- a/framework/platform/parsers/CLI11.cpp +++ b/framework/platform/parsers/CLI11.cpp @@ -19,8 +19,8 @@ #include -#include "common/logging.h" #include "common/strings.h" +#include "core/util/logging.hpp" namespace vkb { diff --git a/framework/platform/platform.cpp b/framework/platform/platform.cpp index a9283deaf..50f1303bb 100644 --- a/framework/platform/platform.cpp +++ b/framework/platform/platform.cpp @@ -28,10 +28,10 @@ #include #include -#include "common/logging.h" +#include "core/util/logging.hpp" +#include "filesystem/legacy.h" #include "force_close/force_close.h" #include "hpp_vulkan_sample.h" -#include "platform/filesystem.h" #include "platform/parsers/CLI11.h" #include "platform/plugins/plugin.h" #include "vulkan_sample.h" diff --git a/framework/platform/platform.h b/framework/platform/platform.h index 176465e56..3d0284ca7 100644 --- a/framework/platform/platform.h +++ b/framework/platform/platform.h @@ -28,8 +28,8 @@ #include "common/optional.h" #include "common/utils.h" #include "common/vk_common.h" +#include "filesystem/legacy.h" #include "platform/application.h" -#include "platform/filesystem.h" #include "platform/parser.h" #include "platform/plugins/plugin.h" #include "platform/window.h" diff --git a/framework/platform/unix/unix_d2d_platform.cpp b/framework/platform/unix/unix_d2d_platform.cpp index f4bc5761a..88e0f2463 100644 --- a/framework/platform/unix/unix_d2d_platform.cpp +++ b/framework/platform/unix/unix_d2d_platform.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -22,32 +22,6 @@ namespace vkb { -namespace -{ -inline const std::string get_temp_path_from_environment() -{ - std::string temp_path = "/tmp/"; - - if (const char *env_ptr = std::getenv("TMPDIR")) - { - temp_path = std::string(env_ptr) + "/"; - } - - return temp_path; -} -} // namespace - -namespace fs -{ -void create_directory(const std::string &path) -{ - if (!is_directory(path)) - { - mkdir(path.c_str(), 0777); - } -} -} // namespace fs - UnixD2DPlatform::UnixD2DPlatform(const PlatformContext &context) : Platform{context} { diff --git a/framework/platform/unix/unix_platform.cpp b/framework/platform/unix/unix_platform.cpp index f44df918f..9fd7fda3e 100644 --- a/framework/platform/unix/unix_platform.cpp +++ b/framework/platform/unix/unix_platform.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -43,17 +43,6 @@ namespace vkb { -namespace fs -{ -void create_directory(const std::string &path) -{ - if (!is_directory(path)) - { - mkdir(path.c_str(), 0777); - } -} -} // namespace fs - UnixPlatform::UnixPlatform(const PlatformContext &context, const UnixType &type) : Platform{context}, type{type} { diff --git a/framework/platform/windows/windows_platform.cpp b/framework/platform/windows/windows_platform.cpp index 724afd405..eaaa37b93 100644 --- a/framework/platform/windows/windows_platform.cpp +++ b/framework/platform/windows/windows_platform.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -27,76 +27,6 @@ namespace vkb { -namespace -{ -inline const std::string get_temp_path_from_environment() -{ - std::string temp_path = "temp/"; - - TCHAR temp_buffer[MAX_PATH]; - DWORD temp_path_ret = GetTempPath(MAX_PATH, temp_buffer); - if (temp_path_ret > MAX_PATH || temp_path_ret == 0) - { - temp_path = "temp/"; - } - else - { - temp_path = std::string(temp_buffer) + "/"; - } - - return temp_path; -} - -/// @brief Converts wstring to string using Windows specific function -/// @param wstr Wide string to convert -/// @return A converted utf8 string -std::string wstr_to_str(const std::wstring &wstr) -{ - if (wstr.empty()) - { - return {}; - } - - auto wstr_len = static_cast(wstr.size()); - auto str_len = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], wstr_len, NULL, 0, NULL, NULL); - - std::string str(str_len, 0); - WideCharToMultiByte(CP_UTF8, 0, &wstr[0], wstr_len, &str[0], str_len, NULL, NULL); - - return str; -} - -inline std::vector get_args() -{ - LPWSTR *argv; - int argc; - - argv = CommandLineToArgvW(GetCommandLineW(), &argc); - - // Ignore the first argument containing the application full path - std::vector arg_strings(argv + 1, argv + argc); - std::vector args; - - for (auto &arg : arg_strings) - { - args.push_back(wstr_to_str(arg)); - } - - return args; -} -} // namespace - -namespace fs -{ -void create_directory(const std::string &path) -{ - if (!is_directory(path)) - { - CreateDirectory(path.c_str(), NULL); - } -} -} // namespace fs - WindowsPlatform::WindowsPlatform(const PlatformContext &context) : Platform(context) { diff --git a/framework/rendering/render_frame.cpp b/framework/rendering/render_frame.cpp index e0e6436e1..2d618f04a 100644 --- a/framework/rendering/render_frame.cpp +++ b/framework/rendering/render_frame.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -17,8 +17,8 @@ #include "render_frame.h" -#include "common/logging.h" #include "common/utils.h" +#include "core/util/logging.hpp" namespace vkb { diff --git a/framework/resource_replay.cpp b/framework/resource_replay.cpp index 2d727fc72..5d13fffed 100644 --- a/framework/resource_replay.cpp +++ b/framework/resource_replay.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -17,8 +17,8 @@ #include "resource_replay.h" -#include "common/logging.h" #include "common/vk_common.h" +#include "core/util/logging.hpp" #include "rendering/pipeline_state.h" #include "resource_cache.h" diff --git a/framework/scene_graph/components/aabb.cpp b/framework/scene_graph/components/aabb.cpp index 22af89d65..45420833d 100644 --- a/framework/scene_graph/components/aabb.cpp +++ b/framework/scene_graph/components/aabb.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, Arm Limited and Contributors +/* Copyright (c) 2018-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -17,7 +17,7 @@ #include "aabb.h" -#include "common/logging.h" +#include "core/util/logging.hpp" namespace vkb { diff --git a/framework/scene_graph/components/hpp_image.cpp b/framework/scene_graph/components/hpp_image.cpp index 78fa003b1..e010a80af 100644 --- a/framework/scene_graph/components/hpp_image.cpp +++ b/framework/scene_graph/components/hpp_image.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -18,7 +18,7 @@ #include "hpp_image.h" #include "common/hpp_utils.h" -#include "platform/filesystem.h" +#include "filesystem/legacy.h" #include "scene_graph/components/image/astc.h" #include "scene_graph/components/image/ktx.h" #include "scene_graph/components/image/stb.h" diff --git a/framework/scene_graph/components/image.cpp b/framework/scene_graph/components/image.cpp index 4c2a037e1..380fa4a06 100644 --- a/framework/scene_graph/components/image.cpp +++ b/framework/scene_graph/components/image.cpp @@ -27,7 +27,7 @@ VKBP_DISABLE_WARNINGS() VKBP_ENABLE_WARNINGS() #include "common/utils.h" -#include "platform/filesystem.h" +#include "filesystem/legacy.h" #include "scene_graph/components/image/astc.h" #include "scene_graph/components/image/ktx.h" #include "scene_graph/components/image/stb.h" diff --git a/framework/vulkan_sample.cpp b/framework/vulkan_sample.cpp index 2743af716..302e7c359 100644 --- a/framework/vulkan_sample.cpp +++ b/framework/vulkan_sample.cpp @@ -26,10 +26,10 @@ VKBP_ENABLE_WARNINGS() #include "api_vulkan_sample.h" #include "common/helpers.h" -#include "common/logging.h" #include "common/strings.h" #include "common/utils.h" #include "common/vk_common.h" +#include "core/util/logging.hpp" #include "gltf_loader.h" #include "platform/platform.h" #include "platform/window.h" diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp index 9c97e091a..ea27053e6 100644 --- a/samples/api/hello_triangle/hello_triangle.cpp +++ b/samples/api/hello_triangle/hello_triangle.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2023, Arm Limited and Contributors +/* Copyright (c) 2018-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -17,10 +17,10 @@ #include "hello_triangle.h" -#include "common/logging.h" #include "common/vk_common.h" +#include "core/util/logging.hpp" +#include "filesystem/legacy.h" #include "glsl_compiler.h" -#include "platform/filesystem.h" #include "platform/window.h" #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS) diff --git a/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp b/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp index 0d8c73042..3ea04674d 100644 --- a/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp +++ b/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -19,9 +19,9 @@ #include #include -#include +#include +#include #include -#include #include // Note: the default dispatcher is instantiated in hpp_api_vulkan_sample.cpp. diff --git a/samples/api/swapchain_recreation/swapchain_recreation.cpp b/samples/api/swapchain_recreation/swapchain_recreation.cpp index 36f6091ea..25c6a61b7 100644 --- a/samples/api/swapchain_recreation/swapchain_recreation.cpp +++ b/samples/api/swapchain_recreation/swapchain_recreation.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, Google +/* Copyright (c) 2023-2024, Google * * SPDX-License-Identifier: Apache-2.0 * @@ -17,10 +17,10 @@ #include "swapchain_recreation.h" -#include "common/logging.h" #include "common/vk_common.h" +#include "core/util/logging.hpp" +#include "filesystem/legacy.h" #include "glsl_compiler.h" -#include "platform/filesystem.h" static constexpr uint32_t INVALID_IMAGE_INDEX = std::numeric_limits::max(); diff --git a/samples/extensions/full_screen_exclusive/full_screen_exclusive.cpp b/samples/extensions/full_screen_exclusive/full_screen_exclusive.cpp index c58dd641b..6d92b7ab0 100644 --- a/samples/extensions/full_screen_exclusive/full_screen_exclusive.cpp +++ b/samples/extensions/full_screen_exclusive/full_screen_exclusive.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, Holochip Corporation +/* Copyright (c) 2023-2024, Holochip Corporation * * SPDX-License-Identifier: Apache-2.0 * @@ -17,8 +17,8 @@ #include "full_screen_exclusive.h" +#include "filesystem/legacy.h" #include "glsl_compiler.h" -#include "platform/filesystem.h" #include "platform/window.h" #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS) diff --git a/samples/extensions/open_cl_interop_arm/open_cl_interop_arm.cpp b/samples/extensions/open_cl_interop_arm/open_cl_interop_arm.cpp index d610c2bbc..b88e74e19 100644 --- a/samples/extensions/open_cl_interop_arm/open_cl_interop_arm.cpp +++ b/samples/extensions/open_cl_interop_arm/open_cl_interop_arm.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023, Arm Limited and Contributors +/* Copyright (c) 2021-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -18,8 +18,8 @@ #include "open_cl_interop_arm.h" #include "common/vk_common.h" +#include "filesystem/legacy.h" #include "gui.h" -#include "platform/filesystem.h" #define CL_FUNCTION_DEFINITIONS #include "../open_cl_common/open_cl_utils.h" @@ -384,7 +384,7 @@ void OpenCLInteropArm::prepare_pipelines() vertex_input_state.vertexBindingDescriptionCount = vkb::to_u32(vertex_input_bindings.size()); vertex_input_state.pVertexBindingDescriptions = vertex_input_bindings.data(); vertex_input_state.vertexAttributeDescriptionCount = vkb::to_u32( - vertex_input_attributes.size()); + vertex_input_attributes.size()); vertex_input_state.pVertexAttributeDescriptions = vertex_input_attributes.data(); VkGraphicsPipelineCreateInfo pipeline_create_info = diff --git a/samples/extensions/open_gl_interop/offscreen_context.cpp b/samples/extensions/open_gl_interop/offscreen_context.cpp index 9f3772f7f..2f9b8133b 100644 --- a/samples/extensions/open_gl_interop/offscreen_context.cpp +++ b/samples/extensions/open_gl_interop/offscreen_context.cpp @@ -1,6 +1,6 @@ -/* Copyright (c) 2020-2021, Arm Limited - * Copyright (c) 2020-2021, Bradley Austin Davis - * +/* Copyright (c) 2020-2024, Arm Limited + * Copyright (c) 2020-2024, Bradley Austin Davis + * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 the "License"; @@ -21,7 +21,7 @@ #include #include -#include "common/logging.h" +#include "core/util/logging.hpp" void APIENTRY debug_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *user_param) { diff --git a/samples/extensions/open_gl_interop/open_gl_interop.cpp b/samples/extensions/open_gl_interop/open_gl_interop.cpp index 46fb00cbf..901f9c9c6 100644 --- a/samples/extensions/open_gl_interop/open_gl_interop.cpp +++ b/samples/extensions/open_gl_interop/open_gl_interop.cpp @@ -1,5 +1,5 @@ -/* Copyright (c) 2020-2023, Bradley Austin Davis - * Copyright (c) 2020-2023, Arm Limited +/* Copyright (c) 2020-2024, Bradley Austin Davis + * Copyright (c) 2020-2024, Arm Limited * * SPDX-License-Identifier: Apache-2.0 * @@ -19,9 +19,9 @@ #include "open_gl_interop.h" #include "common/vk_common.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "rendering/subpasses/forward_subpass.h" @@ -467,7 +467,7 @@ void OpenGLInterop::prepare_pipelines() vertex_input_state.vertexBindingDescriptionCount = vkb::to_u32(vertex_input_bindings.size()); vertex_input_state.pVertexBindingDescriptions = vertex_input_bindings.data(); vertex_input_state.vertexAttributeDescriptionCount = vkb::to_u32( - vertex_input_attributes.size()); + vertex_input_attributes.size()); vertex_input_state.pVertexAttributeDescriptions = vertex_input_attributes.data(); VkGraphicsPipelineCreateInfo pipeline_create_info = diff --git a/samples/extensions/ray_queries/ray_queries.cpp b/samples/extensions/ray_queries/ray_queries.cpp index 1fc1430bd..55fcafa09 100644 --- a/samples/extensions/ray_queries/ray_queries.cpp +++ b/samples/extensions/ray_queries/ray_queries.cpp @@ -17,8 +17,8 @@ */ #include "ray_queries.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" -#include "platform/filesystem.h" #include "rendering/subpasses/forward_subpass.h" #include "scene_graph/components/material.h" diff --git a/samples/extensions/shader_object/shader_object.cpp b/samples/extensions/shader_object/shader_object.cpp index 1144d1e59..05e2f6ae2 100644 --- a/samples/extensions/shader_object/shader_object.cpp +++ b/samples/extensions/shader_object/shader_object.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2023 Nintendo - * Copyright 2023, Sascha Willems + * Copyright 2023-2024-2024 Nintendo + * Copyright 2023-2024-2024, Sascha Willems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,8 @@ #include #include +#include + ShaderObject::ShaderObject() { title = "Shader Object"; diff --git a/samples/general/mobile_nerf/mobile_nerf.cpp b/samples/general/mobile_nerf/mobile_nerf.cpp index 080104cd4..cfbe4b9e9 100644 --- a/samples/general/mobile_nerf/mobile_nerf.cpp +++ b/samples/general/mobile_nerf/mobile_nerf.cpp @@ -16,9 +16,9 @@ */ #include "mobile_nerf.h" +#include "filesystem/legacy.h" #include "glm/gtx/matrix_decompose.hpp" #include "gltf_loader.h" -#include "platform/filesystem.h" #include "platform/platform.h" #include "rendering/subpasses/forward_subpass.h" #include "scene_graph/components/material.h" diff --git a/samples/general/mobile_nerf/mobile_nerf.h b/samples/general/mobile_nerf/mobile_nerf.h index f9068cc31..59a362f24 100644 --- a/samples/general/mobile_nerf/mobile_nerf.h +++ b/samples/general/mobile_nerf/mobile_nerf.h @@ -21,6 +21,8 @@ #include "glsl_compiler.h" #include +#include + using json = nlohmann::json; namespace vkb diff --git a/samples/performance/afbc/afbc.cpp b/samples/performance/afbc/afbc.cpp index c805c76ac..b236fc8ea 100644 --- a/samples/performance/afbc/afbc.cpp +++ b/samples/performance/afbc/afbc.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -18,9 +18,9 @@ #include "afbc.h" #include "common/vk_common.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "rendering/subpasses/forward_subpass.h" #include "stats/stats.h" diff --git a/samples/performance/async_compute/async_compute.cpp b/samples/performance/async_compute/async_compute.cpp index e7ae279b9..8db47f5a6 100644 --- a/samples/performance/async_compute/async_compute.cpp +++ b/samples/performance/async_compute/async_compute.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023, Arm Limited and Contributors +/* Copyright (c) 2021-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -19,9 +19,9 @@ #include "api_vulkan_sample.h" #include "common/vk_common.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "scene_graph/components/orthographic_camera.h" #include "stats/stats.h" diff --git a/samples/performance/command_buffer_usage/command_buffer_usage.cpp b/samples/performance/command_buffer_usage/command_buffer_usage.cpp index 2bc54af15..4867b4572 100644 --- a/samples/performance/command_buffer_usage/command_buffer_usage.cpp +++ b/samples/performance/command_buffer_usage/command_buffer_usage.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -23,9 +23,9 @@ #include "core/device.h" #include "core/pipeline_layout.h" #include "core/shader_module.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "stats/stats.h" diff --git a/samples/performance/constant_data/constant_data.cpp b/samples/performance/constant_data/constant_data.cpp index 8718c128b..3c9d9124b 100644 --- a/samples/performance/constant_data/constant_data.cpp +++ b/samples/performance/constant_data/constant_data.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: MIT * @@ -21,9 +21,9 @@ #include "constant_data.h" #include "common/vk_common.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "rendering/pipeline_state.h" #include "rendering/render_context.h" diff --git a/samples/performance/descriptor_management/descriptor_management.cpp b/samples/performance/descriptor_management/descriptor_management.cpp index 41e478e29..fd8292ac6 100644 --- a/samples/performance/descriptor_management/descriptor_management.cpp +++ b/samples/performance/descriptor_management/descriptor_management.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -18,9 +18,9 @@ #include "descriptor_management.h" #include "common/vk_common.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "rendering/subpasses/forward_subpass.h" #include "stats/stats.h" diff --git a/samples/performance/layout_transitions/layout_transitions.cpp b/samples/performance/layout_transitions/layout_transitions.cpp index dea6ec4b7..7d6144cde 100644 --- a/samples/performance/layout_transitions/layout_transitions.cpp +++ b/samples/performance/layout_transitions/layout_transitions.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -20,9 +20,9 @@ #include "core/device.h" #include "core/pipeline_layout.h" #include "core/shader_module.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "rendering/subpasses/forward_subpass.h" #include "rendering/subpasses/lighting_subpass.h" diff --git a/samples/performance/msaa/msaa.cpp b/samples/performance/msaa/msaa.cpp index c257b4127..ae7e8bb66 100644 --- a/samples/performance/msaa/msaa.cpp +++ b/samples/performance/msaa/msaa.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2021-2023, Arm Limited and Contributors +/* Copyright (c) 2021-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -18,9 +18,9 @@ #include "msaa.h" #include "common/vk_common.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "rendering/postprocessing_renderpass.h" #include "rendering/subpasses/forward_subpass.h" diff --git a/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp b/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp index 22e989281..c1b45f09b 100644 --- a/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp +++ b/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp @@ -1,542 +1,542 @@ -/* Copyright (c) 2020-2023, 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 "multithreading_render_passes.h" - -#include "common/vk_common.h" -#include "gltf_loader.h" -#include "gui.h" -#include "platform/filesystem.h" - -#include "scene_graph/components/material.h" -#include "scene_graph/components/mesh.h" -#include "scene_graph/components/orthographic_camera.h" -#include "scene_graph/components/perspective_camera.h" -#include "stats/stats.h" - -MultithreadingRenderPasses::MultithreadingRenderPasses() -{ - auto &config = get_configuration(); - - config.insert(0, multithreading_mode, 0); - - config.insert(1, multithreading_mode, 1); - - config.insert(2, multithreading_mode, 2); -} - -bool MultithreadingRenderPasses::prepare(const vkb::ApplicationOptions &options) -{ - if (!VulkanSample::prepare(options)) - { - return false; - } - - shadow_render_targets.resize(get_render_context().get_render_frames().size()); - for (uint32_t i = 0; i < shadow_render_targets.size(); i++) - { - shadow_render_targets[i] = create_shadow_render_target(SHADOWMAP_RESOLUTION); - } - - load_scene("scenes/bonza/Bonza4X.gltf"); - - scene->clear_components(); - auto &light = vkb::add_directional_light(*scene, glm::quat({glm::radians(-30.0f), glm::radians(175.0f), glm::radians(0.0f)})); - auto &light_transform = light.get_node()->get_transform(); - light_transform.set_translation(glm::vec3(-50, 0, 0)); - - // Attach a camera component to the light node - auto shadowmap_camera_ptr = std::make_unique("shadowmap_camera", -100.0f, 100.0f, -100.0f, 100.0f, -139.0f, 120.0f); - shadowmap_camera_ptr->set_node(*light.get_node()); - shadowmap_camera = shadowmap_camera_ptr.get(); - light.get_node()->set_component(*shadowmap_camera_ptr); - scene->add_component(std::move(shadowmap_camera_ptr)); - - // Attach a move script to the camera component in the scene - auto &camera_node = vkb::add_free_camera(*scene, "main_camera", get_render_context().get_surface_extent()); - camera = &camera_node.get_component(); - - shadow_render_pipeline = create_shadow_renderpass(); - main_render_pipeline = create_main_renderpass(); - - // Add a GUI with the stats you want to monitor - stats->request_stats({vkb::StatIndex::frame_times, vkb::StatIndex::cpu_cycles}); - gui = std::make_unique(*this, *window, stats.get()); - - return true; -} - -void MultithreadingRenderPasses::prepare_render_context() -{ - get_render_context().prepare(2); -} - -std::unique_ptr MultithreadingRenderPasses::create_shadow_render_target(uint32_t size) -{ - VkExtent3D extent{size, size, 1}; - - vkb::core::Image depth_image{*device, - extent, - vkb::get_suitable_depth_format(device->get_gpu().get_handle()), - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - VMA_MEMORY_USAGE_GPU_ONLY}; - - std::vector images; - - images.push_back(std::move(depth_image)); - - return std::make_unique(std::move(images)); -} - -std::unique_ptr MultithreadingRenderPasses::create_shadow_renderpass() -{ - // Shadowmap subpass - auto shadowmap_vs = vkb::ShaderSource{"shadows/shadowmap.vert"}; - auto shadowmap_fs = vkb::ShaderSource{"shadows/shadowmap.frag"}; - auto scene_subpass = std::make_unique(get_render_context(), std::move(shadowmap_vs), std::move(shadowmap_fs), *scene, *shadowmap_camera); - - shadow_subpass = scene_subpass.get(); - - // Shadowmap pipeline - auto shadowmap_render_pipeline = std::make_unique(); - shadowmap_render_pipeline->add_subpass(std::move(scene_subpass)); - - return shadowmap_render_pipeline; -} - -std::unique_ptr MultithreadingRenderPasses::create_main_renderpass() -{ - // Main subpass - auto main_vs = vkb::ShaderSource{"shadows/main.vert"}; - auto main_fs = vkb::ShaderSource{"shadows/main.frag"}; - auto scene_subpass = std::make_unique(get_render_context(), std::move(main_vs), std::move(main_fs), *scene, *camera, *shadowmap_camera, shadow_render_targets); - - // Main pipeline - auto main_render_pipeline = std::make_unique(); - main_render_pipeline->add_subpass(std::move(scene_subpass)); - - return main_render_pipeline; -} - -void MultithreadingRenderPasses::update(float delta_time) -{ - update_scene(delta_time); - - update_stats(delta_time); - - update_gui(delta_time); - - auto &main_command_buffer = render_context->begin(); - - auto command_buffers = record_command_buffers(main_command_buffer); - - render_context->submit(command_buffers); -} - -void MultithreadingRenderPasses::draw_gui() -{ - const bool landscape = reinterpret_cast(camera)->get_aspect_ratio() > 1.0f; - uint32_t lines = landscape ? 2 : 4; - - gui->show_options_window( - [this, landscape]() { - ImGui::AlignTextToFramePadding(); - ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.4f); - - ImGui::Text("Multithreading mode: "); - ImGui::RadioButton("None", &multithreading_mode, static_cast(MultithreadingMode::None)); - if (landscape) - { - ImGui::SameLine(); - } - ImGui::RadioButton("Primary Buffers", &multithreading_mode, static_cast(MultithreadingMode::PrimaryCommandBuffers)); - if (landscape) - { - ImGui::SameLine(); - } - ImGui::RadioButton("Secondary Buffers", &multithreading_mode, static_cast(MultithreadingMode::SecondaryCommandBuffers)); - }, - lines); -} - -std::vector MultithreadingRenderPasses::record_command_buffers(vkb::CommandBuffer &main_command_buffer) -{ - auto reset_mode = vkb::CommandBuffer::ResetMode::ResetPool; - const auto &queue = device->get_queue_by_flags(VK_QUEUE_GRAPHICS_BIT, 0); - - std::vector command_buffers; - - // Resources are requested from pools for thread #1 in shadow pass if multithreading is used - auto use_multithreading = multithreading_mode != static_cast(MultithreadingMode::None); - shadow_subpass->set_thread_index(use_multithreading ? 1 : 0); - - if (use_multithreading && thread_pool.size() < 1) - { - thread_pool.resize(1); - } - - switch (multithreading_mode) - { - case static_cast(MultithreadingMode::PrimaryCommandBuffers): - record_separate_primary_command_buffers(command_buffers, main_command_buffer); - break; - case static_cast(MultithreadingMode::SecondaryCommandBuffers): - record_separate_secondary_command_buffers(command_buffers, main_command_buffer); - break; - default: - main_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - draw_shadow_pass(main_command_buffer); - draw_main_pass(main_command_buffer); - main_command_buffer.end(); - command_buffers.push_back(&main_command_buffer); - break; - } - - return command_buffers; -} - -void MultithreadingRenderPasses::record_separate_primary_command_buffers(std::vector &command_buffers, vkb::CommandBuffer &main_command_buffer) -{ - auto reset_mode = vkb::CommandBuffer::ResetMode::ResetPool; - const auto &queue = device->get_queue_by_flags(VK_QUEUE_GRAPHICS_BIT, 0); - - // Shadow pass will be recorded in thread with id 1 - auto &shadow_command_buffer = render_context->get_active_frame().request_command_buffer(queue, - reset_mode, - VK_COMMAND_BUFFER_LEVEL_PRIMARY, - 1); - - // Recording shadow command buffer - auto shadow_buffer_future = thread_pool.push( - [this, &shadow_command_buffer](size_t thread_id) { - shadow_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - draw_shadow_pass(shadow_command_buffer); - shadow_command_buffer.end(); - }); - - // Recording scene command buffer - main_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - draw_main_pass(main_command_buffer); - main_command_buffer.end(); - - command_buffers.push_back(&shadow_command_buffer); - command_buffers.push_back(&main_command_buffer); - - // Wait for recording - shadow_buffer_future.get(); -} - -void MultithreadingRenderPasses::record_separate_secondary_command_buffers(std::vector &command_buffers, vkb::CommandBuffer &main_command_buffer) -{ - auto reset_mode = vkb::CommandBuffer::ResetMode::ResetPool; - const auto &queue = device->get_queue_by_flags(VK_QUEUE_GRAPHICS_BIT, 0); - - // Main pass will be recorded in thread with id 0 - auto &scene_command_buffer = render_context->get_active_frame().request_command_buffer(queue, - reset_mode, - VK_COMMAND_BUFFER_LEVEL_SECONDARY, - 0); - - // Shadow pass will be recorded in thread with id 1 - auto &shadow_command_buffer = render_context->get_active_frame().request_command_buffer(queue, - reset_mode, - VK_COMMAND_BUFFER_LEVEL_SECONDARY, - 1); - - // Same framebuffer and render pass should be specified in the inheritance info for secondary command buffers - // and vkCmdBeginRenderPass for primary command buffers - auto &shadow_render_target = *shadow_render_targets[render_context->get_active_frame_index()]; - auto &shadow_render_pass = main_command_buffer.get_render_pass(shadow_render_target, shadow_render_pipeline->get_load_store(), shadow_render_pipeline->get_subpasses()); - auto &shadow_framebuffer = get_device().get_resource_cache().request_framebuffer(shadow_render_target, shadow_render_pass); - - auto &scene_render_target = render_context->get_active_frame().get_render_target(); - auto &scene_render_pass = main_command_buffer.get_render_pass(scene_render_target, main_render_pipeline->get_load_store(), main_render_pipeline->get_subpasses()); - auto &scene_framebuffer = get_device().get_resource_cache().request_framebuffer(scene_render_target, scene_render_pass); - - // Recording shadow command buffer - auto shadow_buffer_future = thread_pool.push( - [this, &shadow_command_buffer, &shadow_render_pass, &shadow_framebuffer](size_t thread_id) { - shadow_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &shadow_render_pass, &shadow_framebuffer, 0); - draw_shadow_pass(shadow_command_buffer); - shadow_command_buffer.end(); - }); - - // Recording scene command buffer - vkb::ColorBlendState scene_color_blend_state; - scene_color_blend_state.attachments.resize(scene_render_pass.get_color_output_count(0)); - - scene_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &scene_render_pass, &scene_framebuffer, 0); - scene_command_buffer.set_color_blend_state(scene_color_blend_state); - draw_main_pass(scene_command_buffer); - scene_command_buffer.end(); - - // Wait for recording - shadow_buffer_future.get(); - - // Recording main command buffer - main_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - - record_shadow_pass_image_memory_barrier(main_command_buffer); - - main_command_buffer.begin_render_pass(shadow_render_target, shadow_render_pass, shadow_framebuffer, shadow_render_pipeline->get_clear_value(), VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); - main_command_buffer.execute_commands(shadow_command_buffer); - main_command_buffer.end_render_pass(); - - record_main_pass_image_memory_barriers(main_command_buffer); - - main_command_buffer.begin_render_pass(scene_render_target, scene_render_pass, scene_framebuffer, main_render_pipeline->get_clear_value(), VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); - main_command_buffer.execute_commands(scene_command_buffer); - main_command_buffer.end_render_pass(); - - record_present_image_memory_barrier(main_command_buffer); - - main_command_buffer.end(); - - command_buffers.push_back(&main_command_buffer); -} - -void MultithreadingRenderPasses::record_main_pass_image_memory_barriers(vkb::CommandBuffer &command_buffer) -{ - auto &views = render_context->get_active_frame().get_render_target().get_views(); - - { - vkb::ImageMemoryBarrier memory_barrier{}; - memory_barrier.old_layout = VK_IMAGE_LAYOUT_UNDEFINED; - memory_barrier.new_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - memory_barrier.src_access_mask = 0; - memory_barrier.dst_access_mask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - - assert(swapchain_attachment_index < views.size()); - command_buffer.image_memory_barrier(views[swapchain_attachment_index], memory_barrier); - } - - { - vkb::ImageMemoryBarrier memory_barrier{}; - memory_barrier.old_layout = VK_IMAGE_LAYOUT_UNDEFINED; - memory_barrier.new_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - memory_barrier.src_access_mask = 0; - memory_barrier.dst_access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - - assert(depth_attachment_index < views.size()); - command_buffer.image_memory_barrier(views[depth_attachment_index], memory_barrier); - } - - { - assert(shadowmap_attachment_index < shadow_render_targets[render_context->get_active_frame_index()]->get_views().size()); - auto &shadowmap = shadow_render_targets[render_context->get_active_frame_index()]->get_views()[shadowmap_attachment_index]; - - vkb::ImageMemoryBarrier memory_barrier{}; - memory_barrier.old_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - memory_barrier.new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - memory_barrier.src_access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - memory_barrier.dst_access_mask = VK_ACCESS_SHADER_READ_BIT; - memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - - command_buffer.image_memory_barrier(shadowmap, memory_barrier); - } -} - -void MultithreadingRenderPasses::record_shadow_pass_image_memory_barrier(vkb::CommandBuffer &command_buffer) -{ - assert(shadowmap_attachment_index < shadow_render_targets[render_context->get_active_frame_index()]->get_views().size()); - auto &shadowmap = shadow_render_targets[render_context->get_active_frame_index()]->get_views()[shadowmap_attachment_index]; - - vkb::ImageMemoryBarrier memory_barrier{}; - memory_barrier.old_layout = VK_IMAGE_LAYOUT_UNDEFINED; - memory_barrier.new_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - memory_barrier.src_access_mask = 0; - memory_barrier.dst_access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - - command_buffer.image_memory_barrier(shadowmap, memory_barrier); -} - -void MultithreadingRenderPasses::record_present_image_memory_barrier(vkb::CommandBuffer &command_buffer) -{ - auto &views = render_context->get_active_frame().get_render_target().get_views(); - - vkb::ImageMemoryBarrier memory_barrier{}; - memory_barrier.old_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - memory_barrier.new_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - memory_barrier.src_access_mask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - - assert(swapchain_attachment_index < views.size()); - command_buffer.image_memory_barrier(views[swapchain_attachment_index], memory_barrier); -} - -void MultithreadingRenderPasses::draw_shadow_pass(vkb::CommandBuffer &command_buffer) -{ - auto &shadow_render_target = *shadow_render_targets[get_render_context().get_active_frame_index()]; - auto &shadowmap_extent = shadow_render_target.get_extent(); - - set_viewport_and_scissor(command_buffer, shadowmap_extent); - - if (command_buffer.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) - { - shadow_render_pipeline->get_active_subpass()->draw(command_buffer); - } - else - { - record_shadow_pass_image_memory_barrier(command_buffer); - shadow_render_pipeline->draw(command_buffer, shadow_render_target); - command_buffer.end_render_pass(); - } -} - -void MultithreadingRenderPasses::draw_main_pass(vkb::CommandBuffer &command_buffer) -{ - auto &render_target = render_context->get_active_frame().get_render_target(); - auto &extent = render_target.get_extent(); - - set_viewport_and_scissor(command_buffer, extent); - - bool is_secondary_command_buffer = command_buffer.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY; - - if (is_secondary_command_buffer) - { - main_render_pipeline->get_active_subpass()->draw(command_buffer); - } - else - { - record_main_pass_image_memory_barriers(command_buffer); - main_render_pipeline->draw(command_buffer, render_target); - } - - if (gui) - { - gui->draw(command_buffer); - } - - if (!is_secondary_command_buffer) - { - command_buffer.end_render_pass(); - record_present_image_memory_barrier(command_buffer); - } -} - -MultithreadingRenderPasses::MainSubpass::MainSubpass(vkb::RenderContext &render_context, - vkb::ShaderSource &&vertex_source, - vkb::ShaderSource &&fragment_source, - vkb::sg::Scene &scene, - vkb::sg::Camera &camera, - vkb::sg::Camera &shadowmap_camera, - std::vector> &shadow_render_targets) : - shadowmap_camera{shadowmap_camera}, - shadow_render_targets{shadow_render_targets}, - vkb::ForwardSubpass{render_context, std::move(vertex_source), std::move(fragment_source), scene, camera} -{ -} - -void MultithreadingRenderPasses::MainSubpass::prepare() -{ - ForwardSubpass::prepare(); - - // Create a sampler for sampling the shadowmap during the lighting process - // Address mode and border color are used to put everything outside of the shadow camera frustum into shadow - // Depth is closer to 1 for near objects and closer to 0 for distant objects - // If we sample outside the shadowmap range [0,0]-[1,1], sampler clamps to border and returns 1 (opaque white) - VkSamplerCreateInfo shadowmap_sampler_create_info{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; - shadowmap_sampler_create_info.minFilter = VK_FILTER_LINEAR; - shadowmap_sampler_create_info.magFilter = VK_FILTER_LINEAR; - shadowmap_sampler_create_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - shadowmap_sampler_create_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - shadowmap_sampler_create_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - shadowmap_sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - shadowmap_sampler_create_info.compareEnable = VK_TRUE; - shadowmap_sampler_create_info.compareOp = VK_COMPARE_OP_GREATER_OR_EQUAL; - shadowmap_sampler = std::make_unique(get_render_context().get_device(), shadowmap_sampler_create_info); -} - -void MultithreadingRenderPasses::MainSubpass::draw(vkb::CommandBuffer &command_buffer) -{ - ShadowUniform shadow_uniform; - shadow_uniform.shadowmap_projection_matrix = vkb::vulkan_style_projection(shadowmap_camera.get_projection()) * shadowmap_camera.get_view(); - - auto &shadow_render_target = *shadow_render_targets[get_render_context().get_active_frame_index()]; - // Bind the shadowmap texture to the proper set nd binding in shader - assert(!shadow_render_target.get_views().empty()); - command_buffer.bind_image(shadow_render_target.get_views()[0], *shadowmap_sampler, 0, 5, 0); - - auto &render_frame = get_render_context().get_active_frame(); - vkb::BufferAllocation shadow_buffer = render_frame.allocate_buffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, sizeof(glm::mat4)); - shadow_buffer.update(shadow_uniform); - // Bind the shadowmap uniform to the proper set nd binding in shader - command_buffer.bind_buffer(shadow_buffer.get_buffer(), shadow_buffer.get_offset(), shadow_buffer.get_size(), 0, 6, 0); - - ForwardSubpass::draw(command_buffer); -} - -MultithreadingRenderPasses::ShadowSubpass::ShadowSubpass(vkb::RenderContext &render_context, - vkb::ShaderSource &&vertex_source, - vkb::ShaderSource &&fragment_source, - vkb::sg::Scene &scene, - vkb::sg::Camera &camera) : - vkb::GeometrySubpass{render_context, std::move(vertex_source), std::move(fragment_source), scene, camera} -{ -} - -void MultithreadingRenderPasses::ShadowSubpass::prepare_pipeline_state(vkb::CommandBuffer &command_buffer, VkFrontFace front_face, bool double_sided_material) -{ - // Enabling depth bias to get rid of self-shadowing artifacts - // Depth bias literally "pushes" slightly all the primitives further away from the camera taking their slope into account - // It helps to avoid precision related problems while doing depth comparisons in the final pass - vkb::RasterizationState rasterization_state{}; - rasterization_state.front_face = front_face; - rasterization_state.depth_bias_enable = VK_TRUE; - - if (double_sided_material) - { - rasterization_state.cull_mode = VK_CULL_MODE_NONE; - } - - command_buffer.set_rasterization_state(rasterization_state); - command_buffer.set_depth_bias(-1.4f, 0.0f, -1.7f); - - vkb::MultisampleState multisample_state{}; - multisample_state.rasterization_samples = sample_count; - command_buffer.set_multisample_state(multisample_state); -} - -vkb::PipelineLayout &MultithreadingRenderPasses::ShadowSubpass::prepare_pipeline_layout(vkb::CommandBuffer &command_buffer, const std::vector &shader_modules) -{ - // Only vertex shader is needed in the shadow subpass - assert(!shader_modules.empty()); - auto vertex_shader_module = shader_modules[0]; - - vertex_shader_module->set_resource_mode("GlobalUniform", vkb::ShaderResourceMode::Dynamic); - - return command_buffer.get_device().get_resource_cache().request_pipeline_layout({vertex_shader_module}); -} - -void MultithreadingRenderPasses::ShadowSubpass::prepare_push_constants(vkb::CommandBuffer &command_buffer, vkb::sg::SubMesh &sub_mesh) -{ - // No push constants are used the in shadow pass - return; -} - -std::unique_ptr create_multithreading_render_passes() -{ - return std::make_unique(); +/* Copyright (c) 2020-2024, 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 "multithreading_render_passes.h" + +#include "common/vk_common.h" +#include "filesystem/legacy.h" +#include "gltf_loader.h" +#include "gui.h" + +#include "scene_graph/components/material.h" +#include "scene_graph/components/mesh.h" +#include "scene_graph/components/orthographic_camera.h" +#include "scene_graph/components/perspective_camera.h" +#include "stats/stats.h" + +MultithreadingRenderPasses::MultithreadingRenderPasses() +{ + auto &config = get_configuration(); + + config.insert(0, multithreading_mode, 0); + + config.insert(1, multithreading_mode, 1); + + config.insert(2, multithreading_mode, 2); +} + +bool MultithreadingRenderPasses::prepare(const vkb::ApplicationOptions &options) +{ + if (!VulkanSample::prepare(options)) + { + return false; + } + + shadow_render_targets.resize(get_render_context().get_render_frames().size()); + for (uint32_t i = 0; i < shadow_render_targets.size(); i++) + { + shadow_render_targets[i] = create_shadow_render_target(SHADOWMAP_RESOLUTION); + } + + load_scene("scenes/bonza/Bonza4X.gltf"); + + scene->clear_components(); + auto &light = vkb::add_directional_light(*scene, glm::quat({glm::radians(-30.0f), glm::radians(175.0f), glm::radians(0.0f)})); + auto &light_transform = light.get_node()->get_transform(); + light_transform.set_translation(glm::vec3(-50, 0, 0)); + + // Attach a camera component to the light node + auto shadowmap_camera_ptr = std::make_unique("shadowmap_camera", -100.0f, 100.0f, -100.0f, 100.0f, -139.0f, 120.0f); + shadowmap_camera_ptr->set_node(*light.get_node()); + shadowmap_camera = shadowmap_camera_ptr.get(); + light.get_node()->set_component(*shadowmap_camera_ptr); + scene->add_component(std::move(shadowmap_camera_ptr)); + + // Attach a move script to the camera component in the scene + auto &camera_node = vkb::add_free_camera(*scene, "main_camera", get_render_context().get_surface_extent()); + camera = &camera_node.get_component(); + + shadow_render_pipeline = create_shadow_renderpass(); + main_render_pipeline = create_main_renderpass(); + + // Add a GUI with the stats you want to monitor + stats->request_stats({vkb::StatIndex::frame_times, vkb::StatIndex::cpu_cycles}); + gui = std::make_unique(*this, *window, stats.get()); + + return true; +} + +void MultithreadingRenderPasses::prepare_render_context() +{ + get_render_context().prepare(2); +} + +std::unique_ptr MultithreadingRenderPasses::create_shadow_render_target(uint32_t size) +{ + VkExtent3D extent{size, size, 1}; + + vkb::core::Image depth_image{*device, + extent, + vkb::get_suitable_depth_format(device->get_gpu().get_handle()), + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VMA_MEMORY_USAGE_GPU_ONLY}; + + std::vector images; + + images.push_back(std::move(depth_image)); + + return std::make_unique(std::move(images)); +} + +std::unique_ptr MultithreadingRenderPasses::create_shadow_renderpass() +{ + // Shadowmap subpass + auto shadowmap_vs = vkb::ShaderSource{"shadows/shadowmap.vert"}; + auto shadowmap_fs = vkb::ShaderSource{"shadows/shadowmap.frag"}; + auto scene_subpass = std::make_unique(get_render_context(), std::move(shadowmap_vs), std::move(shadowmap_fs), *scene, *shadowmap_camera); + + shadow_subpass = scene_subpass.get(); + + // Shadowmap pipeline + auto shadowmap_render_pipeline = std::make_unique(); + shadowmap_render_pipeline->add_subpass(std::move(scene_subpass)); + + return shadowmap_render_pipeline; +} + +std::unique_ptr MultithreadingRenderPasses::create_main_renderpass() +{ + // Main subpass + auto main_vs = vkb::ShaderSource{"shadows/main.vert"}; + auto main_fs = vkb::ShaderSource{"shadows/main.frag"}; + auto scene_subpass = std::make_unique(get_render_context(), std::move(main_vs), std::move(main_fs), *scene, *camera, *shadowmap_camera, shadow_render_targets); + + // Main pipeline + auto main_render_pipeline = std::make_unique(); + main_render_pipeline->add_subpass(std::move(scene_subpass)); + + return main_render_pipeline; +} + +void MultithreadingRenderPasses::update(float delta_time) +{ + update_scene(delta_time); + + update_stats(delta_time); + + update_gui(delta_time); + + auto &main_command_buffer = render_context->begin(); + + auto command_buffers = record_command_buffers(main_command_buffer); + + render_context->submit(command_buffers); +} + +void MultithreadingRenderPasses::draw_gui() +{ + const bool landscape = reinterpret_cast(camera)->get_aspect_ratio() > 1.0f; + uint32_t lines = landscape ? 2 : 4; + + gui->show_options_window( + [this, landscape]() { + ImGui::AlignTextToFramePadding(); + ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.4f); + + ImGui::Text("Multithreading mode: "); + ImGui::RadioButton("None", &multithreading_mode, static_cast(MultithreadingMode::None)); + if (landscape) + { + ImGui::SameLine(); + } + ImGui::RadioButton("Primary Buffers", &multithreading_mode, static_cast(MultithreadingMode::PrimaryCommandBuffers)); + if (landscape) + { + ImGui::SameLine(); + } + ImGui::RadioButton("Secondary Buffers", &multithreading_mode, static_cast(MultithreadingMode::SecondaryCommandBuffers)); + }, + lines); +} + +std::vector MultithreadingRenderPasses::record_command_buffers(vkb::CommandBuffer &main_command_buffer) +{ + auto reset_mode = vkb::CommandBuffer::ResetMode::ResetPool; + const auto &queue = device->get_queue_by_flags(VK_QUEUE_GRAPHICS_BIT, 0); + + std::vector command_buffers; + + // Resources are requested from pools for thread #1 in shadow pass if multithreading is used + auto use_multithreading = multithreading_mode != static_cast(MultithreadingMode::None); + shadow_subpass->set_thread_index(use_multithreading ? 1 : 0); + + if (use_multithreading && thread_pool.size() < 1) + { + thread_pool.resize(1); + } + + switch (multithreading_mode) + { + case static_cast(MultithreadingMode::PrimaryCommandBuffers): + record_separate_primary_command_buffers(command_buffers, main_command_buffer); + break; + case static_cast(MultithreadingMode::SecondaryCommandBuffers): + record_separate_secondary_command_buffers(command_buffers, main_command_buffer); + break; + default: + main_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + draw_shadow_pass(main_command_buffer); + draw_main_pass(main_command_buffer); + main_command_buffer.end(); + command_buffers.push_back(&main_command_buffer); + break; + } + + return command_buffers; +} + +void MultithreadingRenderPasses::record_separate_primary_command_buffers(std::vector &command_buffers, vkb::CommandBuffer &main_command_buffer) +{ + auto reset_mode = vkb::CommandBuffer::ResetMode::ResetPool; + const auto &queue = device->get_queue_by_flags(VK_QUEUE_GRAPHICS_BIT, 0); + + // Shadow pass will be recorded in thread with id 1 + auto &shadow_command_buffer = render_context->get_active_frame().request_command_buffer(queue, + reset_mode, + VK_COMMAND_BUFFER_LEVEL_PRIMARY, + 1); + + // Recording shadow command buffer + auto shadow_buffer_future = thread_pool.push( + [this, &shadow_command_buffer](size_t thread_id) { + shadow_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + draw_shadow_pass(shadow_command_buffer); + shadow_command_buffer.end(); + }); + + // Recording scene command buffer + main_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + draw_main_pass(main_command_buffer); + main_command_buffer.end(); + + command_buffers.push_back(&shadow_command_buffer); + command_buffers.push_back(&main_command_buffer); + + // Wait for recording + shadow_buffer_future.get(); +} + +void MultithreadingRenderPasses::record_separate_secondary_command_buffers(std::vector &command_buffers, vkb::CommandBuffer &main_command_buffer) +{ + auto reset_mode = vkb::CommandBuffer::ResetMode::ResetPool; + const auto &queue = device->get_queue_by_flags(VK_QUEUE_GRAPHICS_BIT, 0); + + // Main pass will be recorded in thread with id 0 + auto &scene_command_buffer = render_context->get_active_frame().request_command_buffer(queue, + reset_mode, + VK_COMMAND_BUFFER_LEVEL_SECONDARY, + 0); + + // Shadow pass will be recorded in thread with id 1 + auto &shadow_command_buffer = render_context->get_active_frame().request_command_buffer(queue, + reset_mode, + VK_COMMAND_BUFFER_LEVEL_SECONDARY, + 1); + + // Same framebuffer and render pass should be specified in the inheritance info for secondary command buffers + // and vkCmdBeginRenderPass for primary command buffers + auto &shadow_render_target = *shadow_render_targets[render_context->get_active_frame_index()]; + auto &shadow_render_pass = main_command_buffer.get_render_pass(shadow_render_target, shadow_render_pipeline->get_load_store(), shadow_render_pipeline->get_subpasses()); + auto &shadow_framebuffer = get_device().get_resource_cache().request_framebuffer(shadow_render_target, shadow_render_pass); + + auto &scene_render_target = render_context->get_active_frame().get_render_target(); + auto &scene_render_pass = main_command_buffer.get_render_pass(scene_render_target, main_render_pipeline->get_load_store(), main_render_pipeline->get_subpasses()); + auto &scene_framebuffer = get_device().get_resource_cache().request_framebuffer(scene_render_target, scene_render_pass); + + // Recording shadow command buffer + auto shadow_buffer_future = thread_pool.push( + [this, &shadow_command_buffer, &shadow_render_pass, &shadow_framebuffer](size_t thread_id) { + shadow_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &shadow_render_pass, &shadow_framebuffer, 0); + draw_shadow_pass(shadow_command_buffer); + shadow_command_buffer.end(); + }); + + // Recording scene command buffer + vkb::ColorBlendState scene_color_blend_state; + scene_color_blend_state.attachments.resize(scene_render_pass.get_color_output_count(0)); + + scene_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &scene_render_pass, &scene_framebuffer, 0); + scene_command_buffer.set_color_blend_state(scene_color_blend_state); + draw_main_pass(scene_command_buffer); + scene_command_buffer.end(); + + // Wait for recording + shadow_buffer_future.get(); + + // Recording main command buffer + main_command_buffer.begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + + record_shadow_pass_image_memory_barrier(main_command_buffer); + + main_command_buffer.begin_render_pass(shadow_render_target, shadow_render_pass, shadow_framebuffer, shadow_render_pipeline->get_clear_value(), VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + main_command_buffer.execute_commands(shadow_command_buffer); + main_command_buffer.end_render_pass(); + + record_main_pass_image_memory_barriers(main_command_buffer); + + main_command_buffer.begin_render_pass(scene_render_target, scene_render_pass, scene_framebuffer, main_render_pipeline->get_clear_value(), VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + main_command_buffer.execute_commands(scene_command_buffer); + main_command_buffer.end_render_pass(); + + record_present_image_memory_barrier(main_command_buffer); + + main_command_buffer.end(); + + command_buffers.push_back(&main_command_buffer); +} + +void MultithreadingRenderPasses::record_main_pass_image_memory_barriers(vkb::CommandBuffer &command_buffer) +{ + auto &views = render_context->get_active_frame().get_render_target().get_views(); + + { + vkb::ImageMemoryBarrier memory_barrier{}; + memory_barrier.old_layout = VK_IMAGE_LAYOUT_UNDEFINED; + memory_barrier.new_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + memory_barrier.src_access_mask = 0; + memory_barrier.dst_access_mask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + + assert(swapchain_attachment_index < views.size()); + command_buffer.image_memory_barrier(views[swapchain_attachment_index], memory_barrier); + } + + { + vkb::ImageMemoryBarrier memory_barrier{}; + memory_barrier.old_layout = VK_IMAGE_LAYOUT_UNDEFINED; + memory_barrier.new_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + memory_barrier.src_access_mask = 0; + memory_barrier.dst_access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + + assert(depth_attachment_index < views.size()); + command_buffer.image_memory_barrier(views[depth_attachment_index], memory_barrier); + } + + { + assert(shadowmap_attachment_index < shadow_render_targets[render_context->get_active_frame_index()]->get_views().size()); + auto &shadowmap = shadow_render_targets[render_context->get_active_frame_index()]->get_views()[shadowmap_attachment_index]; + + vkb::ImageMemoryBarrier memory_barrier{}; + memory_barrier.old_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + memory_barrier.new_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + memory_barrier.src_access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + memory_barrier.dst_access_mask = VK_ACCESS_SHADER_READ_BIT; + memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + + command_buffer.image_memory_barrier(shadowmap, memory_barrier); + } +} + +void MultithreadingRenderPasses::record_shadow_pass_image_memory_barrier(vkb::CommandBuffer &command_buffer) +{ + assert(shadowmap_attachment_index < shadow_render_targets[render_context->get_active_frame_index()]->get_views().size()); + auto &shadowmap = shadow_render_targets[render_context->get_active_frame_index()]->get_views()[shadowmap_attachment_index]; + + vkb::ImageMemoryBarrier memory_barrier{}; + memory_barrier.old_layout = VK_IMAGE_LAYOUT_UNDEFINED; + memory_barrier.new_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + memory_barrier.src_access_mask = 0; + memory_barrier.dst_access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + + command_buffer.image_memory_barrier(shadowmap, memory_barrier); +} + +void MultithreadingRenderPasses::record_present_image_memory_barrier(vkb::CommandBuffer &command_buffer) +{ + auto &views = render_context->get_active_frame().get_render_target().get_views(); + + vkb::ImageMemoryBarrier memory_barrier{}; + memory_barrier.old_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + memory_barrier.new_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + memory_barrier.src_access_mask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + + assert(swapchain_attachment_index < views.size()); + command_buffer.image_memory_barrier(views[swapchain_attachment_index], memory_barrier); +} + +void MultithreadingRenderPasses::draw_shadow_pass(vkb::CommandBuffer &command_buffer) +{ + auto &shadow_render_target = *shadow_render_targets[get_render_context().get_active_frame_index()]; + auto &shadowmap_extent = shadow_render_target.get_extent(); + + set_viewport_and_scissor(command_buffer, shadowmap_extent); + + if (command_buffer.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) + { + shadow_render_pipeline->get_active_subpass()->draw(command_buffer); + } + else + { + record_shadow_pass_image_memory_barrier(command_buffer); + shadow_render_pipeline->draw(command_buffer, shadow_render_target); + command_buffer.end_render_pass(); + } +} + +void MultithreadingRenderPasses::draw_main_pass(vkb::CommandBuffer &command_buffer) +{ + auto &render_target = render_context->get_active_frame().get_render_target(); + auto &extent = render_target.get_extent(); + + set_viewport_and_scissor(command_buffer, extent); + + bool is_secondary_command_buffer = command_buffer.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY; + + if (is_secondary_command_buffer) + { + main_render_pipeline->get_active_subpass()->draw(command_buffer); + } + else + { + record_main_pass_image_memory_barriers(command_buffer); + main_render_pipeline->draw(command_buffer, render_target); + } + + if (gui) + { + gui->draw(command_buffer); + } + + if (!is_secondary_command_buffer) + { + command_buffer.end_render_pass(); + record_present_image_memory_barrier(command_buffer); + } +} + +MultithreadingRenderPasses::MainSubpass::MainSubpass(vkb::RenderContext &render_context, + vkb::ShaderSource &&vertex_source, + vkb::ShaderSource &&fragment_source, + vkb::sg::Scene &scene, + vkb::sg::Camera &camera, + vkb::sg::Camera &shadowmap_camera, + std::vector> &shadow_render_targets) : + shadowmap_camera{shadowmap_camera}, + shadow_render_targets{shadow_render_targets}, + vkb::ForwardSubpass{render_context, std::move(vertex_source), std::move(fragment_source), scene, camera} +{ +} + +void MultithreadingRenderPasses::MainSubpass::prepare() +{ + ForwardSubpass::prepare(); + + // Create a sampler for sampling the shadowmap during the lighting process + // Address mode and border color are used to put everything outside of the shadow camera frustum into shadow + // Depth is closer to 1 for near objects and closer to 0 for distant objects + // If we sample outside the shadowmap range [0,0]-[1,1], sampler clamps to border and returns 1 (opaque white) + VkSamplerCreateInfo shadowmap_sampler_create_info{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + shadowmap_sampler_create_info.minFilter = VK_FILTER_LINEAR; + shadowmap_sampler_create_info.magFilter = VK_FILTER_LINEAR; + shadowmap_sampler_create_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + shadowmap_sampler_create_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + shadowmap_sampler_create_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + shadowmap_sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + shadowmap_sampler_create_info.compareEnable = VK_TRUE; + shadowmap_sampler_create_info.compareOp = VK_COMPARE_OP_GREATER_OR_EQUAL; + shadowmap_sampler = std::make_unique(get_render_context().get_device(), shadowmap_sampler_create_info); +} + +void MultithreadingRenderPasses::MainSubpass::draw(vkb::CommandBuffer &command_buffer) +{ + ShadowUniform shadow_uniform; + shadow_uniform.shadowmap_projection_matrix = vkb::vulkan_style_projection(shadowmap_camera.get_projection()) * shadowmap_camera.get_view(); + + auto &shadow_render_target = *shadow_render_targets[get_render_context().get_active_frame_index()]; + // Bind the shadowmap texture to the proper set nd binding in shader + assert(!shadow_render_target.get_views().empty()); + command_buffer.bind_image(shadow_render_target.get_views()[0], *shadowmap_sampler, 0, 5, 0); + + auto &render_frame = get_render_context().get_active_frame(); + vkb::BufferAllocation shadow_buffer = render_frame.allocate_buffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, sizeof(glm::mat4)); + shadow_buffer.update(shadow_uniform); + // Bind the shadowmap uniform to the proper set nd binding in shader + command_buffer.bind_buffer(shadow_buffer.get_buffer(), shadow_buffer.get_offset(), shadow_buffer.get_size(), 0, 6, 0); + + ForwardSubpass::draw(command_buffer); +} + +MultithreadingRenderPasses::ShadowSubpass::ShadowSubpass(vkb::RenderContext &render_context, + vkb::ShaderSource &&vertex_source, + vkb::ShaderSource &&fragment_source, + vkb::sg::Scene &scene, + vkb::sg::Camera &camera) : + vkb::GeometrySubpass{render_context, std::move(vertex_source), std::move(fragment_source), scene, camera} +{ +} + +void MultithreadingRenderPasses::ShadowSubpass::prepare_pipeline_state(vkb::CommandBuffer &command_buffer, VkFrontFace front_face, bool double_sided_material) +{ + // Enabling depth bias to get rid of self-shadowing artifacts + // Depth bias literally "pushes" slightly all the primitives further away from the camera taking their slope into account + // It helps to avoid precision related problems while doing depth comparisons in the final pass + vkb::RasterizationState rasterization_state{}; + rasterization_state.front_face = front_face; + rasterization_state.depth_bias_enable = VK_TRUE; + + if (double_sided_material) + { + rasterization_state.cull_mode = VK_CULL_MODE_NONE; + } + + command_buffer.set_rasterization_state(rasterization_state); + command_buffer.set_depth_bias(-1.4f, 0.0f, -1.7f); + + vkb::MultisampleState multisample_state{}; + multisample_state.rasterization_samples = sample_count; + command_buffer.set_multisample_state(multisample_state); +} + +vkb::PipelineLayout &MultithreadingRenderPasses::ShadowSubpass::prepare_pipeline_layout(vkb::CommandBuffer &command_buffer, const std::vector &shader_modules) +{ + // Only vertex shader is needed in the shadow subpass + assert(!shader_modules.empty()); + auto vertex_shader_module = shader_modules[0]; + + vertex_shader_module->set_resource_mode("GlobalUniform", vkb::ShaderResourceMode::Dynamic); + + return command_buffer.get_device().get_resource_cache().request_pipeline_layout({vertex_shader_module}); +} + +void MultithreadingRenderPasses::ShadowSubpass::prepare_push_constants(vkb::CommandBuffer &command_buffer, vkb::sg::SubMesh &sub_mesh) +{ + // No push constants are used the in shadow pass + return; +} + +std::unique_ptr create_multithreading_render_passes() +{ + return std::make_unique(); } \ No newline at end of file diff --git a/samples/performance/pipeline_barriers/pipeline_barriers.cpp b/samples/performance/pipeline_barriers/pipeline_barriers.cpp index 619ea90e8..825c7022d 100644 --- a/samples/performance/pipeline_barriers/pipeline_barriers.cpp +++ b/samples/performance/pipeline_barriers/pipeline_barriers.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -20,9 +20,9 @@ #include "core/device.h" #include "core/pipeline_layout.h" #include "core/shader_module.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "rendering/subpasses/forward_subpass.h" #include "rendering/subpasses/lighting_subpass.h" diff --git a/samples/performance/pipeline_cache/pipeline_cache.cpp b/samples/performance/pipeline_cache/pipeline_cache.cpp index 9df2b257b..a0d7aba95 100644 --- a/samples/performance/pipeline_cache/pipeline_cache.cpp +++ b/samples/performance/pipeline_cache/pipeline_cache.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -19,10 +19,10 @@ #include -#include "common/logging.h" #include "core/device.h" +#include "core/util/logging.hpp" +#include "filesystem/legacy.h" #include "gui.h" -#include "platform/filesystem.h" #include "platform/window.h" #include "rendering/subpasses/forward_subpass.h" diff --git a/samples/performance/render_passes/render_passes.cpp b/samples/performance/render_passes/render_passes.cpp index 414b34dfe..7a1f1067c 100644 --- a/samples/performance/render_passes/render_passes.cpp +++ b/samples/performance/render_passes/render_passes.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2023, Arm Limited and Contributors +/* Copyright (c) 2018-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -18,9 +18,9 @@ #include "render_passes.h" #include "common/vk_common.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "rendering/subpasses/forward_subpass.h" #include "stats/stats.h" diff --git a/samples/performance/specialization_constants/specialization_constants.cpp b/samples/performance/specialization_constants/specialization_constants.cpp index 794fac4aa..c4724d386 100644 --- a/samples/performance/specialization_constants/specialization_constants.cpp +++ b/samples/performance/specialization_constants/specialization_constants.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -20,9 +20,9 @@ #include #include +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "stats/stats.h" diff --git a/samples/performance/surface_rotation/surface_rotation.cpp b/samples/performance/surface_rotation/surface_rotation.cpp index 2a4c5c575..f62c2e3a6 100644 --- a/samples/performance/surface_rotation/surface_rotation.cpp +++ b/samples/performance/surface_rotation/surface_rotation.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -27,9 +27,9 @@ VKBP_ENABLE_WARNINGS() #include "core/device.h" #include "core/pipeline_layout.h" #include "core/shader_module.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "rendering/subpasses/forward_subpass.h" #include "scene_graph/components/material.h" diff --git a/samples/performance/swapchain_images/swapchain_images.cpp b/samples/performance/swapchain_images/swapchain_images.cpp index 53cba997b..b852f6c5c 100644 --- a/samples/performance/swapchain_images/swapchain_images.cpp +++ b/samples/performance/swapchain_images/swapchain_images.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -20,9 +20,9 @@ #include "core/device.h" #include "core/pipeline_layout.h" #include "core/shader_module.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "rendering/subpasses/forward_subpass.h" #include "scene_graph/components/material.h" diff --git a/samples/performance/wait_idle/wait_idle.cpp b/samples/performance/wait_idle/wait_idle.cpp index a88c7b82d..7aa276fb1 100644 --- a/samples/performance/wait_idle/wait_idle.cpp +++ b/samples/performance/wait_idle/wait_idle.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -18,9 +18,9 @@ #include "wait_idle.h" #include "common/vk_common.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "rendering/subpasses/forward_subpass.h" #include "stats/stats.h" diff --git a/tests/system_test/test_framework/gltf_loader_test.cpp b/tests/system_test/test_framework/gltf_loader_test.cpp index 1d48e9efa..5fc43c844 100644 --- a/tests/system_test/test_framework/gltf_loader_test.cpp +++ b/tests/system_test/test_framework/gltf_loader_test.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Arm Limited and Contributors +/* Copyright (c) 2019-2024, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -17,9 +17,9 @@ #include "gltf_loader_test.h" +#include "filesystem/legacy.h" #include "gltf_loader.h" #include "gui.h" -#include "platform/filesystem.h" #include "platform/platform.h" #include "rendering/subpasses/forward_subpass.h" #include "stats/stats.h"