Compare commits

..

No commits in common. "vk-hpp" and "main" have entirely different histories.
vk-hpp ... main

20 changed files with 2145 additions and 36068 deletions

View file

@ -20,7 +20,6 @@ IndentWidth: 2
NamespaceIndentation: All NamespaceIndentation: All
SpaceBeforeCpp11BracedList: true SpaceBeforeCpp11BracedList: true
SpacesBeforeTrailingComments: 1 SpacesBeforeTrailingComments: 1
Standard: Latest
IncludeBlocks: Regroup IncludeBlocks: Regroup
IncludeCategories: IncludeCategories:

View file

@ -1,3 +1,4 @@
# noinspection SpellCheckingInspection
Checks: > Checks: >
*, *,
-ctad-maybe-unsupported, -ctad-maybe-unsupported,
@ -7,7 +8,6 @@ Checks: >
-bugprone-implicit-widening-of-multiplication-result, -bugprone-implicit-widening-of-multiplication-result,
-cert-env33-c, -cert-env33-c,
-concurrency-mt-unsafe, -concurrency-mt-unsafe,
-cppcoreguidelines-avoid-const-or-ref-data-members,
-cppcoreguidelines-avoid-magic-numbers, -cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-owning-memory, -cppcoreguidelines-owning-memory,
-cppcoreguidelines-pro-type-member-init, -cppcoreguidelines-pro-type-member-init,

4
.clangd Normal file
View file

@ -0,0 +1,4 @@
Diagnostics:
Suppress: >
-Wmissing-template-arg-list-after-template-kw,
-Wctad-maybe-unsupported

3
.envrc
View file

@ -1 +1,2 @@
use_flake export NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1
use_flake . --impure

1
.gitignore vendored
View file

@ -2,4 +2,3 @@
.direnv/ .direnv/
.vscode/ .vscode/
build/ build/
imgui.ini

View file

@ -1,10 +1,6 @@
# This file was generated by nvfetcher, please do not modify it manually. # This file was generated by nvfetcher, please do not modify it manually.
{ fetchgit, fetchurl, fetchFromGitHub, dockerTools }:
{ {
fetchgit,
fetchurl,
fetchFromGitHub,
dockerTools,
}: {
fmt = { fmt = {
pname = "fmt"; pname = "fmt";
version = "11.0.2"; version = "11.0.2";

View file

@ -1,78 +1,27 @@
{ {
"nodes": { "nodes": {
"flake-compat": {
"locked": {
"lastModified": 1688025799,
"narHash": "sha256-ktpB4dRtnksm9F5WawoIkEneh1nrEvuxb5lJFt1iOyw=",
"owner": "nix-community",
"repo": "flake-compat",
"rev": "8bf105319d44f6b9f0d764efa4fdef9f1cc9ba1c",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "flake-compat",
"type": "github"
}
},
"nixos-asahi": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1729779640,
"narHash": "sha256-M9t4Ta9d76aVqd1mkLBl8zFSWYc8pv6AZTy1SU5bVp0=",
"owner": "zzywysm",
"repo": "nixos-asahi",
"rev": "5f8823f3543cbf9566d5af49b3a3c18539681eac",
"type": "github"
},
"original": {
"owner": "zzywysm",
"repo": "nixos-asahi",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1725103162, "lastModified": 1727065772,
"narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=", "narHash": "sha256-U9baiEXL2YsS67QKlBAPIUq+OB+eUPKv8n1vGNdhiec=",
"owner": "nixos", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b", "rev": "989dc4cbf6a95f2e5fefc8cd61d2198a8fb6834a",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nixos", "owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1730853263, "lastModified": 1726481836,
"narHash": "sha256-Cnp2zjzaA4bYUOhM/xo9GxhgOgTHn+qNbSGu4su8RaQ=", "narHash": "sha256-MWTBH4dd5zIz2iatDb8IkqSjIeFum9jAqkFxgHLdzO4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5d4d64e923ce570996c089d768710f61bde0b9d3",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1726871744,
"narHash": "sha256-V5LpfdHyQkUF7RfOaDPrZDP+oqz88lTJrMT1+stXNwo=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "a1d92660c6b3b7c26fb883500a80ea9d33321be2", "rev": "20f9370d5f588fb8c72e844c54511cab054b5f40",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -84,28 +33,11 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"nixos-asahi": "nixos-asahi", "nixpkgs": "nixpkgs",
"nixpkgs": "nixpkgs_2",
"treefmt-nix": "treefmt-nix", "treefmt-nix": "treefmt-nix",
"utils": "utils" "utils": "utils"
} }
}, },
"rust-overlay": {
"flake": false,
"locked": {
"lastModified": 1686795910,
"narHash": "sha256-jDa40qRZ0GRQtP9EMZdf+uCbvzuLnJglTUI2JoHfWDc=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "5c2b97c0a9bc5217fc3dfb1555aae0fb756d99f9",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": { "systems": {
"locked": { "locked": {
"lastModified": 1681028828, "lastModified": 1681028828,
@ -123,14 +55,14 @@
}, },
"treefmt-nix": { "treefmt-nix": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs_3" "nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1730321837, "lastModified": 1726734507,
"narHash": "sha256-vK+a09qq19QNu2MlLcvN4qcRctJbqWkX7ahgPZ/+maI=", "narHash": "sha256-VUH5O5AcOSxb0uL/m34dDkxFKP6WLQ6y4I1B4+N3L2w=",
"owner": "numtide", "owner": "numtide",
"repo": "treefmt-nix", "repo": "treefmt-nix",
"rev": "746901bb8dba96d154b66492a29f5db0693dbfcc", "rev": "ee41a466c2255a3abe6bc50fc6be927cdee57a9f",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -2,7 +2,6 @@
description = "C/C++ environment"; description = "C/C++ environment";
inputs = { inputs = {
nixos-asahi.url = "github:zzywysm/nixos-asahi";
nixpkgs.url = "github:NixOS/nixpkgs"; nixpkgs.url = "github:NixOS/nixpkgs";
treefmt-nix.url = "github:numtide/treefmt-nix"; treefmt-nix.url = "github:numtide/treefmt-nix";
utils.url = "github:numtide/flake-utils"; utils.url = "github:numtide/flake-utils";
@ -11,20 +10,13 @@
outputs = { outputs = {
self, self,
nixpkgs, nixpkgs,
nixos-asahi,
treefmt-nix, treefmt-nix,
utils, utils,
... ...
}: }:
utils.lib.eachDefaultSystem ( utils.lib.eachDefaultSystem (
system: let system: let
pkgs = import nixpkgs { pkgs = import nixpkgs {inherit system;};
inherit system;
config = {
allowUnfree = true;
allowUnsupportedSystem = true;
};
};
stdenv = stdenv =
if pkgs.hostPlatform.isLinux if pkgs.hostPlatform.isLinux
@ -42,21 +34,14 @@
fmt = mkPkg "fmt"; fmt = mkPkg "fmt";
imgui = pkgs.imgui.override {
IMGUI_BUILD_GLFW_BINDING = true;
IMGUI_BUILD_VULKAN_BINDING = true;
};
deps = with pkgs; [ deps = with pkgs; [
fmt fmt
glfw glfw
glm glm
imgui
shaderc.dev
shaderc.lib
vulkan-extension-layer vulkan-extension-layer
vulkan-memory-allocator vulkan-memory-allocator
vulkan-utility-libraries vulkan-utility-libraries
vulkan-headers
vulkan-loader vulkan-loader
vulkan-tools vulkan-tools
]; ];
@ -97,6 +82,7 @@
projectRootFile = "flake.nix"; projectRootFile = "flake.nix";
programs = { programs = {
alejandra.enable = true; alejandra.enable = true;
deadnix.enable = true;
clang-format = { clang-format = {
enable = true; enable = true;
@ -106,17 +92,15 @@
}; };
devShell = mkShell.override {inherit stdenv;} { devShell = mkShell.override {inherit stdenv;} {
buildInputs = packages =
[ [
alejandra alejandra
bear bear
cmake
(llvmPackages_18.clang-tools.override {enableLibcxx = true;}) (llvmPackages_18.clang-tools.override {enableLibcxx = true;})
lldb lldb
meson meson
nil
ninja ninja
#nvfetcher nvfetcher
pkg-config pkg-config
unzip unzip
@ -129,20 +113,6 @@
VULKAN_SDK = "${vulkan-headers}"; VULKAN_SDK = "${vulkan-headers}";
VK_LAYER_PATH = "${vulkan-validation-layers}/share/vulkan/explicit_layer.d"; VK_LAYER_PATH = "${vulkan-validation-layers}/share/vulkan/explicit_layer.d";
VK_ICD_FILENAMES =
if stdenv.isDarwin
then "${darwin.moltenvk}/share/vulkan/icd.d/MoltenVK_icd.json"
else let
vulkanDir =
if stdenv.hostPlatform.isx86_64
then "${mesa.drivers}/share/vulkan/icd.d"
else "${nixos-asahi.packages.aarch64-linux.mesa-asahi-edge.drivers}/share/vulkan/icd.d";
vulkanFiles = builtins.filter (file: builtins.match ".*\\.json$" file != null) (builtins.attrNames (builtins.readDir vulkanDir));
vulkanPaths = lib.concatStringsSep ":" (map (file: "${vulkanDir}/${file}") vulkanFiles);
in
if stdenv.hostPlatform.isx86_64
then "${linuxPackages_latest.nvidia_x11_beta}/share/vulkan/icd.d/nvidia_icd.x86_64.json:${vulkanPaths}"
else vulkanPaths;
shellHook = '' shellHook = ''
export PATH="${llvmPackages_18.clang-tools.override {enableLibcxx = true;}}/bin:$PATH" export PATH="${llvmPackages_18.clang-tools.override {enableLibcxx = true;}}/bin:$PATH"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@ project(
'graphics-test', 'graphics-test',
'cpp', 'cpp',
version: '0.1.0', version: '0.1.0',
default_options: ['cpp_std=c++26', 'warning_level=everything', 'buildtype=debugoptimized'], default_options: ['cpp_std=c++20', 'warning_level=everything', 'buildtype=debugoptimized'],
) )
cpp = meson.get_compiler('cpp') cpp = meson.get_compiler('cpp')
@ -12,32 +12,37 @@ common_cpp_args = [
'-Wno-c++20-extensions', '-Wno-c++20-extensions',
'-Wno-c++98-compat', '-Wno-c++98-compat',
'-Wno-c++98-compat-pedantic', '-Wno-c++98-compat-pedantic',
'-Wno-pre-c++20-compat-pedantic', '-Wno-disabled-macro-expansion',
'-Wno-missing-prototypes',
'-Wno-padded', '-Wno-padded',
'-mavx2' '-Wno-pre-c++20-compat-pedantic',
'-Wno-switch-default',
'-Wno-unsafe-buffer-usage',
'-Wunused-function',
'-fvisibility=hidden',
] ]
add_project_arguments(cpp.get_supported_arguments(common_cpp_args), language: 'cpp') add_project_arguments(cpp.get_supported_arguments(common_cpp_args), language: 'cpp')
deps = [ source_file_names = [
dependency('fmt', include_type: 'system'), 'src/main.cpp',
dependency('glfw3', include_type: 'system'),
dependency('glm', include_type: 'system'),
dependency('vulkan', include_type: 'system'),
dependency('shaderc', include_type: 'system'),
] ]
imgui_dep = dependency('imgui', required: false, include_type: 'system') sources = []
if not imgui_dep.found() foreach file : source_file_names
imgui_dep = cpp.find_library('imgui', required: true) sources += files(file)
endif endforeach
deps += imgui_dep deps = [
dependency('fmt', static: true),
dependency('glfw3'),
dependency('glm'),
dependency('vulkan'),
]
executable( executable(
'graphics-test', 'graphics-test',
sources: files('src/main.cpp'), sources,
include_directories: include_directories('include', is_system: true),
dependencies: deps, dependencies: deps,
) )

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

1709
src/util/magic_enum.hpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,166 +0,0 @@
#pragma once
#include <filesystem>
#include <fmt/format.h>
#include <fstream>
#include <shaderc/shaderc.hpp>
#include <string>
#include <vector>
#include "types.hpp"
class ShaderCompiler {
public:
ShaderCompiler() = default;
/**
* @brief Compiles or loads a cached SPIR-V shader from a file.
*
* @param shaderSource The source code of the shader.
* @param kind The type of shader being compiled (vertex, fragment, etc.).
* @param shaderName The name used for caching the compiled shader.
* @return std::vector<u32> A vector containing the compiled SPIR-V code.
* @throws std::runtime_error if shader compilation fails.
*
* This function attempts to load a shader from the cache. If the shader
* is not found in the cache, it compiles the shader from the source code
* and saves the result to the cache for future use.
*/
static fn getCompiledShader(
const char* shaderSource,
const shaderc_shader_kind& kind,
const string& shaderName
) -> std::vector<u32> {
using namespace std;
const filesystem::path cacheFile = getCacheFilePath(shaderName);
// Try loading from cache first
vector<u32> spirvCode = loadCachedShader(cacheFile);
if (!spirvCode.empty()) {
fmt::println("Loaded shader from cache: {}", cacheFile.string());
return spirvCode;
}
// Cache miss, compile the shader
spirvCode = compileShader(shaderSource, kind);
if (spirvCode.empty())
throw runtime_error("Shader compilation failed for: " + shaderName);
// Cache the compiled SPIR-V binary
saveCompiledShader(spirvCode, cacheFile.string());
return spirvCode;
}
private:
/**
* @brief Generates the cache file path based on the operating system.
*
* @param shaderName The name used for the shader file.
* @return string The full path to the cache file.
*
* This function determines the appropriate directory for caching shaders
* based on the operating system and returns the full path for the specified shader name.
*/
static fn getCacheFilePath(const string& shaderName) -> std::filesystem::path {
using namespace std::filesystem;
#ifdef _WIN32
path cacheDir = path(getenv("LOCALAPPDATA")) / "VulkanApp" / "Shaders";
#elif defined(__APPLE__)
path cacheDir = path(getenv("HOME")) / "Library" / "Application Support" / "VulkanApp" / "Shaders";
#else // Assume Linux or other UNIX-like systems
path cacheDir = path(getenv("HOME")) / ".local" / "share" / "VulkanApp" / "Shaders";
#endif
if (!exists(cacheDir))
create_directories(cacheDir); // Create the directory if it doesn't exist
return cacheDir / (shaderName + ".spv");
}
/**
* @brief Compiles GLSL code to SPIR-V.
*
* @param source The GLSL source code to compile.
* @param kind The type of shader being compiled.
* @return std::vector<u32> A vector containing the compiled SPIR-V code.
*
* This function uses the shaderc library to compile GLSL source code into
* SPIR-V binary format. If the compilation fails, an empty vector is returned.
*/
static fn compileShader(const char* source, const shaderc_shader_kind& kind) -> std::vector<u32> {
using namespace shaderc;
Compiler compiler;
CompileOptions options;
SpvCompilationResult result = compiler.CompileGlslToSpv(source, kind, "shader.glsl", "main", options);
if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
fmt::println(stderr, "Shader compilation failed: {}", result.GetErrorMessage());
return {};
}
return { result.cbegin(), result.cend() };
}
/**
* @brief Loads compiled SPIR-V shader code from a cache file.
*
* @param cacheFile The path to the cached SPIR-V file.
* @return std::vector<u32> A vector containing the loaded SPIR-V code.
* @throws std::runtime_error if the file cannot be read.
*
* This function checks if the specified cache file exists and reads its
* contents into a vector. If the file cannot be opened, an exception is thrown.
*/
static fn loadCachedShader(const std::filesystem::path& cacheFile) -> std::vector<u32> {
using namespace std;
if (!filesystem::exists(cacheFile))
return {}; // No cached file
ifstream file(cacheFile, ios::binary);
// Check if the file was successfully opened
if (!file)
throw runtime_error("Failed to open cached shader file: " + cacheFile.string());
usize fileSize = filesystem::file_size(cacheFile);
vector<u32> spirvCode(fileSize / sizeof(u32));
// Read entire file content into the vector
if (!file.read(bit_cast<char*>(spirvCode.data()), static_cast<streamsize>(fileSize)))
throw runtime_error("Failed to read cached shader file: " + cacheFile.string());
return spirvCode;
}
/**
* @brief Saves compiled SPIR-V binary to a cache file.
*
* @param spirvCode The SPIR-V code to save.
* @param cacheFile The path to the file where the SPIR-V code will be saved.
* @throws std::runtime_error if the file cannot be written.
*
* This function writes the compiled SPIR-V binary to the specified file.
* If the file cannot be opened or written, an exception is thrown.
*/
static fn saveCompiledShader(const std::vector<u32>& spirvCode, const string& cacheFile) -> void {
using namespace std;
ofstream file(cacheFile, ios::binary);
// Check if the file was successfully opened
if (!file)
throw runtime_error("Failed to open file for saving shader: " + cacheFile);
if (!file.write(
bit_cast<const char*>(spirvCode.data()), static_cast<streamsize>(spirvCode.size() * sizeof(u32))
))
throw runtime_error("Failed to save shader to cache: " + cacheFile);
}
};

View file

@ -1,121 +0,0 @@
#include <filesystem>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include "types.hpp"
namespace stb {
/**
* @brief A class that handles loading and managing image data.
*
* This class uses the stb_image library to load images from the filesystem
* and provides access to the image data, dimensions, and channel count.
*/
class UniqueImage {
public:
/**
* @brief Constructs a UniqueImage object and loads an image from the specified path.
*
* @param path The filesystem path to the image file to load.
*/
UniqueImage(const std::filesystem::path& path) { load(path.string().c_str()); }
// Deleted copy constructor to prevent copying.
UniqueImage(const UniqueImage&) = delete;
// Deleted copy assignment operator to prevent copying.
fn operator=(const UniqueImage&)->UniqueImage& = delete;
/**
* @brief Move constructor for UniqueImage.
*
* @param other The UniqueImage object from which to move resources.
*
* Transfers ownership of resources from another UniqueImage object.
*/
UniqueImage(UniqueImage&& other) noexcept
: mData(other.mData), mWidth(other.mWidth), mHeight(other.mHeight), mChannels(other.mChannels) {
other.mData = nullptr;
}
/**
* @brief Move assignment operator for UniqueImage.
*
* @param other The UniqueImage object from which to move resources.
* @return Reference to this object.
*
* Transfers ownership of resources from another UniqueImage object.
*/
fn operator=(UniqueImage&& other) noexcept -> UniqueImage& {
if (this != &other) {
if (mData)
stbi_image_free(mData);
mData = other.mData;
mWidth = other.mWidth;
mHeight = other.mHeight;
mChannels = other.mChannels;
other.mData = nullptr;
}
return *this;
}
/**
* @brief Destructor for UniqueImage.
*
* Frees the image data if it is allocated.
*/
~UniqueImage() {
if (mData)
stbi_image_free(mData);
}
/**
* @brief Retrieves the image data.
*
* @return Pointer to the image data in memory.
*/
[[nodiscard]] fn getData() const -> u8* { return mData; }
/**
* @brief Retrieves the width of the image.
*
* @return The width of the image in pixels.
*/
[[nodiscard]] fn getWidth() const -> i32 { return mWidth; }
/**
* @brief Retrieves the height of the image.
*
* @return The height of the image in pixels.
*/
[[nodiscard]] fn getHeight() const -> i32 { return mHeight; }
/**
* @brief Retrieves the number of channels in the image.
*
* @return The number of channels in the image (e.g., 3 for RGB, 4 for RGBA).
*/
[[nodiscard]] fn getChannels() const -> i32 { return mChannels; }
private:
u8* mData = nullptr; ///< Pointer to the image data.
i32 mWidth = 0; ///< Width of the image in pixels.
i32 mHeight = 0; ///< Height of the image in pixels.
i32 mChannels = 0; ///< Number of channels in the image.
/**
* @brief Loads an image from a file.
*
* @param filename The name of the file from which to load the image.
* @throws std::runtime_error If the image fails to load.
*/
fn load(const char* filename) -> void {
mData = stbi_load(filename, &mWidth, &mHeight, &mChannels, STBI_rgb_alpha);
if (!mData)
throw std::runtime_error("Failed to load image: " + string(stbi_failure_reason()));
}
};
}

View file

@ -1,52 +0,0 @@
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtx/hash.hpp>
#define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#include "types.hpp"
// Vertex data for the model
struct Vertex {
// Position of the vertex
glm::vec3 pos;
// Color of the vertex (in RGB)
glm::vec3 color;
// Texture coordinates of the vertex
glm::vec2 tex_coord;
// Returns the binding description for the vertex
static fn getBindingDescription() -> vk::VertexInputBindingDescription {
return { .binding = 0, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex };
}
// Returns the attribute descriptions for the vertex
static fn getAttributeDescriptions() -> std::array<vk::VertexInputAttributeDescription, 3> {
return {
// Position attribute
vk::VertexInputAttributeDescription { 0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, pos) },
// Color attribute
vk::VertexInputAttributeDescription { 1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, color) },
// Texture coordinate attribute
vk::VertexInputAttributeDescription { 2, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, tex_coord) }
};
}
// Overload the equality operator for the vertex
fn operator==(const Vertex& other) const->bool {
return pos == other.pos && color == other.color && tex_coord == other.tex_coord;
}
};
// Hash function for the vertex
namespace std {
template <>
struct hash<Vertex> {
fn operator()(Vertex const& vertex) const->size_t {
return ((hash<glm::vec3>()(vertex.pos) ^ (hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^
(hash<glm::vec2>()(vertex.tex_coord) << 1);
}
};
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 940 KiB