initial
This commit is contained in:
+45
@@ -0,0 +1,45 @@
|
||||
project(loft_base)
|
||||
|
||||
file(GLOB FILES
|
||||
./src/*.cpp
|
||||
./src/shaders/*.cpp
|
||||
./src/io/*.cpp
|
||||
./src/resources/*.cpp)
|
||||
|
||||
|
||||
file(GLOB HEADERS
|
||||
./include/*.h
|
||||
./include/*.hpp
|
||||
./include/shaders/*.h
|
||||
./include/shaders/*.hpp
|
||||
./include/resources/*.h
|
||||
./include/resources/*.hpp
|
||||
./include/io/*.h
|
||||
./include/io/*.hpp
|
||||
./include/debug/*.h
|
||||
./include/debug/*.hpp
|
||||
)
|
||||
|
||||
add_library(loft_base OBJECT ${FILES})
|
||||
add_library(loft::base ALIAS loft_base)
|
||||
target_sources(loft_base
|
||||
PUBLIC FILE_SET HEADERS
|
||||
BASE_DIRS include
|
||||
FILES ${HEADERS})
|
||||
|
||||
set_target_properties(loft_base PROPERTIES POSITION_INDEPENDENT_CODE 1)
|
||||
|
||||
find_package(Vulkan REQUIRED)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
GPUOpen::VulkanMemoryAllocator
|
||||
volk::volk
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
${PROJECT_SOURCE_DIR}/include/
|
||||
)
|
||||
|
||||
|
||||
Vendored
+560
@@ -0,0 +1,560 @@
|
||||
# CMAKE generated file: DO NOT EDIT!
|
||||
# Generated by "Unix Makefiles" Generator, CMake Version 3.30
|
||||
|
||||
# Default target executed when no arguments are given to make.
|
||||
default_target: all
|
||||
.PHONY : default_target
|
||||
|
||||
# Allow only one "make -f Makefile2" at a time, but pass parallelism.
|
||||
.NOTPARALLEL:
|
||||
|
||||
#=============================================================================
|
||||
# Special targets provided by cmake.
|
||||
|
||||
# Disable implicit rules so canonical targets will work.
|
||||
.SUFFIXES:
|
||||
|
||||
# Disable VCS-based implicit rules.
|
||||
% : %,v
|
||||
|
||||
# Disable VCS-based implicit rules.
|
||||
% : RCS/%
|
||||
|
||||
# Disable VCS-based implicit rules.
|
||||
% : RCS/%,v
|
||||
|
||||
# Disable VCS-based implicit rules.
|
||||
% : SCCS/s.%
|
||||
|
||||
# Disable VCS-based implicit rules.
|
||||
% : s.%
|
||||
|
||||
.SUFFIXES: .hpux_make_needs_suffix_list
|
||||
|
||||
# Command-line flag to silence nested $(MAKE).
|
||||
$(VERBOSE)MAKESILENT = -s
|
||||
|
||||
#Suppress display of executed commands.
|
||||
$(VERBOSE).SILENT:
|
||||
|
||||
# A target that is always out of date.
|
||||
cmake_force:
|
||||
.PHONY : cmake_force
|
||||
|
||||
#=============================================================================
|
||||
# Set environment variables for the build.
|
||||
|
||||
# The shell in which to execute make rules.
|
||||
SHELL = /bin/sh
|
||||
|
||||
# The CMake executable.
|
||||
CMAKE_COMMAND = /usr/bin/cmake
|
||||
|
||||
# The command to remove a file.
|
||||
RM = /usr/bin/cmake -E rm -f
|
||||
|
||||
# Escaping for special characters.
|
||||
EQUALS = =
|
||||
|
||||
# The top-level source directory on which CMake was run.
|
||||
CMAKE_SOURCE_DIR = /home/martin/projects/mmo
|
||||
|
||||
# The top-level build directory on which CMake was run.
|
||||
CMAKE_BINARY_DIR = /home/martin/projects/mmo
|
||||
|
||||
#=============================================================================
|
||||
# Targets provided globally by CMake.
|
||||
|
||||
# Special rule for the target edit_cache
|
||||
edit_cache:
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Running CMake cache editor..."
|
||||
/usr/bin/ccmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
|
||||
.PHONY : edit_cache
|
||||
|
||||
# Special rule for the target edit_cache
|
||||
edit_cache/fast: edit_cache
|
||||
.PHONY : edit_cache/fast
|
||||
|
||||
# Special rule for the target rebuild_cache
|
||||
rebuild_cache:
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Running CMake to regenerate build system..."
|
||||
/usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
|
||||
.PHONY : rebuild_cache
|
||||
|
||||
# Special rule for the target rebuild_cache
|
||||
rebuild_cache/fast: rebuild_cache
|
||||
.PHONY : rebuild_cache/fast
|
||||
|
||||
# The main all target
|
||||
all: cmake_check_build_system
|
||||
cd /home/martin/projects/mmo && $(CMAKE_COMMAND) -E cmake_progress_start /home/martin/projects/mmo/CMakeFiles /home/martin/projects/mmo/external/loft/modules/base//CMakeFiles/progress.marks
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 external/loft/modules/base/all
|
||||
$(CMAKE_COMMAND) -E cmake_progress_start /home/martin/projects/mmo/CMakeFiles 0
|
||||
.PHONY : all
|
||||
|
||||
# The main clean target
|
||||
clean:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 external/loft/modules/base/clean
|
||||
.PHONY : clean
|
||||
|
||||
# The main clean target
|
||||
clean/fast: clean
|
||||
.PHONY : clean/fast
|
||||
|
||||
# Prepare targets for installation.
|
||||
preinstall: all
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 external/loft/modules/base/preinstall
|
||||
.PHONY : preinstall
|
||||
|
||||
# Prepare targets for installation.
|
||||
preinstall/fast:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 external/loft/modules/base/preinstall
|
||||
.PHONY : preinstall/fast
|
||||
|
||||
# clear depends
|
||||
depend:
|
||||
cd /home/martin/projects/mmo && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
|
||||
.PHONY : depend
|
||||
|
||||
# Convenience name for target.
|
||||
external/loft/modules/base/CMakeFiles/loft_base.dir/rule:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 external/loft/modules/base/CMakeFiles/loft_base.dir/rule
|
||||
.PHONY : external/loft/modules/base/CMakeFiles/loft_base.dir/rule
|
||||
|
||||
# Convenience name for target.
|
||||
loft_base: external/loft/modules/base/CMakeFiles/loft_base.dir/rule
|
||||
.PHONY : loft_base
|
||||
|
||||
# fast build rule for target.
|
||||
loft_base/fast:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/build
|
||||
.PHONY : loft_base/fast
|
||||
|
||||
src/FramebufferBuilder.o: src/FramebufferBuilder.cpp.o
|
||||
.PHONY : src/FramebufferBuilder.o
|
||||
|
||||
# target to build an object file
|
||||
src/FramebufferBuilder.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/FramebufferBuilder.cpp.o
|
||||
.PHONY : src/FramebufferBuilder.cpp.o
|
||||
|
||||
src/FramebufferBuilder.i: src/FramebufferBuilder.cpp.i
|
||||
.PHONY : src/FramebufferBuilder.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/FramebufferBuilder.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/FramebufferBuilder.cpp.i
|
||||
.PHONY : src/FramebufferBuilder.cpp.i
|
||||
|
||||
src/FramebufferBuilder.s: src/FramebufferBuilder.cpp.s
|
||||
.PHONY : src/FramebufferBuilder.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/FramebufferBuilder.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/FramebufferBuilder.cpp.s
|
||||
.PHONY : src/FramebufferBuilder.cpp.s
|
||||
|
||||
src/Gpu.o: src/Gpu.cpp.o
|
||||
.PHONY : src/Gpu.o
|
||||
|
||||
# target to build an object file
|
||||
src/Gpu.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/Gpu.cpp.o
|
||||
.PHONY : src/Gpu.cpp.o
|
||||
|
||||
src/Gpu.i: src/Gpu.cpp.i
|
||||
.PHONY : src/Gpu.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/Gpu.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/Gpu.cpp.i
|
||||
.PHONY : src/Gpu.cpp.i
|
||||
|
||||
src/Gpu.s: src/Gpu.cpp.s
|
||||
.PHONY : src/Gpu.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/Gpu.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/Gpu.cpp.s
|
||||
.PHONY : src/Gpu.cpp.s
|
||||
|
||||
src/Instance.o: src/Instance.cpp.o
|
||||
.PHONY : src/Instance.o
|
||||
|
||||
# target to build an object file
|
||||
src/Instance.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/Instance.cpp.o
|
||||
.PHONY : src/Instance.cpp.o
|
||||
|
||||
src/Instance.i: src/Instance.cpp.i
|
||||
.PHONY : src/Instance.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/Instance.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/Instance.cpp.i
|
||||
.PHONY : src/Instance.cpp.i
|
||||
|
||||
src/Instance.s: src/Instance.cpp.s
|
||||
.PHONY : src/Instance.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/Instance.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/Instance.cpp.s
|
||||
.PHONY : src/Instance.cpp.s
|
||||
|
||||
src/io/file.o: src/io/file.cpp.o
|
||||
.PHONY : src/io/file.o
|
||||
|
||||
# target to build an object file
|
||||
src/io/file.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/io/file.cpp.o
|
||||
.PHONY : src/io/file.cpp.o
|
||||
|
||||
src/io/file.i: src/io/file.cpp.i
|
||||
.PHONY : src/io/file.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/io/file.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/io/file.cpp.i
|
||||
.PHONY : src/io/file.cpp.i
|
||||
|
||||
src/io/file.s: src/io/file.cpp.s
|
||||
.PHONY : src/io/file.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/io/file.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/io/file.cpp.s
|
||||
.PHONY : src/io/file.cpp.s
|
||||
|
||||
src/resources/Buffer.o: src/resources/Buffer.cpp.o
|
||||
.PHONY : src/resources/Buffer.o
|
||||
|
||||
# target to build an object file
|
||||
src/resources/Buffer.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/Buffer.cpp.o
|
||||
.PHONY : src/resources/Buffer.cpp.o
|
||||
|
||||
src/resources/Buffer.i: src/resources/Buffer.cpp.i
|
||||
.PHONY : src/resources/Buffer.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/resources/Buffer.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/Buffer.cpp.i
|
||||
.PHONY : src/resources/Buffer.cpp.i
|
||||
|
||||
src/resources/Buffer.s: src/resources/Buffer.cpp.s
|
||||
.PHONY : src/resources/Buffer.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/resources/Buffer.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/Buffer.cpp.s
|
||||
.PHONY : src/resources/Buffer.cpp.s
|
||||
|
||||
src/resources/BufferBusWriter.o: src/resources/BufferBusWriter.cpp.o
|
||||
.PHONY : src/resources/BufferBusWriter.o
|
||||
|
||||
# target to build an object file
|
||||
src/resources/BufferBusWriter.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/BufferBusWriter.cpp.o
|
||||
.PHONY : src/resources/BufferBusWriter.cpp.o
|
||||
|
||||
src/resources/BufferBusWriter.i: src/resources/BufferBusWriter.cpp.i
|
||||
.PHONY : src/resources/BufferBusWriter.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/resources/BufferBusWriter.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/BufferBusWriter.cpp.i
|
||||
.PHONY : src/resources/BufferBusWriter.cpp.i
|
||||
|
||||
src/resources/BufferBusWriter.s: src/resources/BufferBusWriter.cpp.s
|
||||
.PHONY : src/resources/BufferBusWriter.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/resources/BufferBusWriter.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/BufferBusWriter.cpp.s
|
||||
.PHONY : src/resources/BufferBusWriter.cpp.s
|
||||
|
||||
src/resources/DefaultAllocator.o: src/resources/DefaultAllocator.cpp.o
|
||||
.PHONY : src/resources/DefaultAllocator.o
|
||||
|
||||
# target to build an object file
|
||||
src/resources/DefaultAllocator.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/DefaultAllocator.cpp.o
|
||||
.PHONY : src/resources/DefaultAllocator.cpp.o
|
||||
|
||||
src/resources/DefaultAllocator.i: src/resources/DefaultAllocator.cpp.i
|
||||
.PHONY : src/resources/DefaultAllocator.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/resources/DefaultAllocator.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/DefaultAllocator.cpp.i
|
||||
.PHONY : src/resources/DefaultAllocator.cpp.i
|
||||
|
||||
src/resources/DefaultAllocator.s: src/resources/DefaultAllocator.cpp.s
|
||||
.PHONY : src/resources/DefaultAllocator.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/resources/DefaultAllocator.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/DefaultAllocator.cpp.s
|
||||
.PHONY : src/resources/DefaultAllocator.cpp.s
|
||||
|
||||
src/resources/Image.o: src/resources/Image.cpp.o
|
||||
.PHONY : src/resources/Image.o
|
||||
|
||||
# target to build an object file
|
||||
src/resources/Image.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/Image.cpp.o
|
||||
.PHONY : src/resources/Image.cpp.o
|
||||
|
||||
src/resources/Image.i: src/resources/Image.cpp.i
|
||||
.PHONY : src/resources/Image.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/resources/Image.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/Image.cpp.i
|
||||
.PHONY : src/resources/Image.cpp.i
|
||||
|
||||
src/resources/Image.s: src/resources/Image.cpp.s
|
||||
.PHONY : src/resources/Image.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/resources/Image.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/Image.cpp.s
|
||||
.PHONY : src/resources/Image.cpp.s
|
||||
|
||||
src/resources/ImageBusWriter.o: src/resources/ImageBusWriter.cpp.o
|
||||
.PHONY : src/resources/ImageBusWriter.o
|
||||
|
||||
# target to build an object file
|
||||
src/resources/ImageBusWriter.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/ImageBusWriter.cpp.o
|
||||
.PHONY : src/resources/ImageBusWriter.cpp.o
|
||||
|
||||
src/resources/ImageBusWriter.i: src/resources/ImageBusWriter.cpp.i
|
||||
.PHONY : src/resources/ImageBusWriter.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/resources/ImageBusWriter.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/ImageBusWriter.cpp.i
|
||||
.PHONY : src/resources/ImageBusWriter.cpp.i
|
||||
|
||||
src/resources/ImageBusWriter.s: src/resources/ImageBusWriter.cpp.s
|
||||
.PHONY : src/resources/ImageBusWriter.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/resources/ImageBusWriter.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/ImageBusWriter.cpp.s
|
||||
.PHONY : src/resources/ImageBusWriter.cpp.s
|
||||
|
||||
src/resources/ImageView.o: src/resources/ImageView.cpp.o
|
||||
.PHONY : src/resources/ImageView.o
|
||||
|
||||
# target to build an object file
|
||||
src/resources/ImageView.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/ImageView.cpp.o
|
||||
.PHONY : src/resources/ImageView.cpp.o
|
||||
|
||||
src/resources/ImageView.i: src/resources/ImageView.cpp.i
|
||||
.PHONY : src/resources/ImageView.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/resources/ImageView.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/ImageView.cpp.i
|
||||
.PHONY : src/resources/ImageView.cpp.i
|
||||
|
||||
src/resources/ImageView.s: src/resources/ImageView.cpp.s
|
||||
.PHONY : src/resources/ImageView.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/resources/ImageView.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/ImageView.cpp.s
|
||||
.PHONY : src/resources/ImageView.cpp.s
|
||||
|
||||
src/resources/MipmapGenerator.o: src/resources/MipmapGenerator.cpp.o
|
||||
.PHONY : src/resources/MipmapGenerator.o
|
||||
|
||||
# target to build an object file
|
||||
src/resources/MipmapGenerator.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/MipmapGenerator.cpp.o
|
||||
.PHONY : src/resources/MipmapGenerator.cpp.o
|
||||
|
||||
src/resources/MipmapGenerator.i: src/resources/MipmapGenerator.cpp.i
|
||||
.PHONY : src/resources/MipmapGenerator.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/resources/MipmapGenerator.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/MipmapGenerator.cpp.i
|
||||
.PHONY : src/resources/MipmapGenerator.cpp.i
|
||||
|
||||
src/resources/MipmapGenerator.s: src/resources/MipmapGenerator.cpp.s
|
||||
.PHONY : src/resources/MipmapGenerator.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/resources/MipmapGenerator.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/resources/MipmapGenerator.cpp.s
|
||||
.PHONY : src/resources/MipmapGenerator.cpp.s
|
||||
|
||||
src/shaders/GlslShaderBuilder.o: src/shaders/GlslShaderBuilder.cpp.o
|
||||
.PHONY : src/shaders/GlslShaderBuilder.o
|
||||
|
||||
# target to build an object file
|
||||
src/shaders/GlslShaderBuilder.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/GlslShaderBuilder.cpp.o
|
||||
.PHONY : src/shaders/GlslShaderBuilder.cpp.o
|
||||
|
||||
src/shaders/GlslShaderBuilder.i: src/shaders/GlslShaderBuilder.cpp.i
|
||||
.PHONY : src/shaders/GlslShaderBuilder.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/shaders/GlslShaderBuilder.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/GlslShaderBuilder.cpp.i
|
||||
.PHONY : src/shaders/GlslShaderBuilder.cpp.i
|
||||
|
||||
src/shaders/GlslShaderBuilder.s: src/shaders/GlslShaderBuilder.cpp.s
|
||||
.PHONY : src/shaders/GlslShaderBuilder.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/shaders/GlslShaderBuilder.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/GlslShaderBuilder.cpp.s
|
||||
.PHONY : src/shaders/GlslShaderBuilder.cpp.s
|
||||
|
||||
src/shaders/Pipeline.o: src/shaders/Pipeline.cpp.o
|
||||
.PHONY : src/shaders/Pipeline.o
|
||||
|
||||
# target to build an object file
|
||||
src/shaders/Pipeline.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/Pipeline.cpp.o
|
||||
.PHONY : src/shaders/Pipeline.cpp.o
|
||||
|
||||
src/shaders/Pipeline.i: src/shaders/Pipeline.cpp.i
|
||||
.PHONY : src/shaders/Pipeline.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/shaders/Pipeline.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/Pipeline.cpp.i
|
||||
.PHONY : src/shaders/Pipeline.cpp.i
|
||||
|
||||
src/shaders/Pipeline.s: src/shaders/Pipeline.cpp.s
|
||||
.PHONY : src/shaders/Pipeline.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/shaders/Pipeline.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/Pipeline.cpp.s
|
||||
.PHONY : src/shaders/Pipeline.cpp.s
|
||||
|
||||
src/shaders/PipelineBuilder.o: src/shaders/PipelineBuilder.cpp.o
|
||||
.PHONY : src/shaders/PipelineBuilder.o
|
||||
|
||||
# target to build an object file
|
||||
src/shaders/PipelineBuilder.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/PipelineBuilder.cpp.o
|
||||
.PHONY : src/shaders/PipelineBuilder.cpp.o
|
||||
|
||||
src/shaders/PipelineBuilder.i: src/shaders/PipelineBuilder.cpp.i
|
||||
.PHONY : src/shaders/PipelineBuilder.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/shaders/PipelineBuilder.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/PipelineBuilder.cpp.i
|
||||
.PHONY : src/shaders/PipelineBuilder.cpp.i
|
||||
|
||||
src/shaders/PipelineBuilder.s: src/shaders/PipelineBuilder.cpp.s
|
||||
.PHONY : src/shaders/PipelineBuilder.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/shaders/PipelineBuilder.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/PipelineBuilder.cpp.s
|
||||
.PHONY : src/shaders/PipelineBuilder.cpp.s
|
||||
|
||||
src/shaders/SpirvShaderBuilder.o: src/shaders/SpirvShaderBuilder.cpp.o
|
||||
.PHONY : src/shaders/SpirvShaderBuilder.o
|
||||
|
||||
# target to build an object file
|
||||
src/shaders/SpirvShaderBuilder.cpp.o:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/SpirvShaderBuilder.cpp.o
|
||||
.PHONY : src/shaders/SpirvShaderBuilder.cpp.o
|
||||
|
||||
src/shaders/SpirvShaderBuilder.i: src/shaders/SpirvShaderBuilder.cpp.i
|
||||
.PHONY : src/shaders/SpirvShaderBuilder.i
|
||||
|
||||
# target to preprocess a source file
|
||||
src/shaders/SpirvShaderBuilder.cpp.i:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/SpirvShaderBuilder.cpp.i
|
||||
.PHONY : src/shaders/SpirvShaderBuilder.cpp.i
|
||||
|
||||
src/shaders/SpirvShaderBuilder.s: src/shaders/SpirvShaderBuilder.cpp.s
|
||||
.PHONY : src/shaders/SpirvShaderBuilder.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
src/shaders/SpirvShaderBuilder.cpp.s:
|
||||
cd /home/martin/projects/mmo && $(MAKE) $(MAKESILENT) -f external/loft/modules/base/CMakeFiles/loft_base.dir/build.make external/loft/modules/base/CMakeFiles/loft_base.dir/src/shaders/SpirvShaderBuilder.cpp.s
|
||||
.PHONY : src/shaders/SpirvShaderBuilder.cpp.s
|
||||
|
||||
# Help Target
|
||||
help:
|
||||
@echo "The following are some of the valid targets for this Makefile:"
|
||||
@echo "... all (the default if no target is provided)"
|
||||
@echo "... clean"
|
||||
@echo "... depend"
|
||||
@echo "... edit_cache"
|
||||
@echo "... rebuild_cache"
|
||||
@echo "... loft_base"
|
||||
@echo "... src/FramebufferBuilder.o"
|
||||
@echo "... src/FramebufferBuilder.i"
|
||||
@echo "... src/FramebufferBuilder.s"
|
||||
@echo "... src/Gpu.o"
|
||||
@echo "... src/Gpu.i"
|
||||
@echo "... src/Gpu.s"
|
||||
@echo "... src/Instance.o"
|
||||
@echo "... src/Instance.i"
|
||||
@echo "... src/Instance.s"
|
||||
@echo "... src/io/file.o"
|
||||
@echo "... src/io/file.i"
|
||||
@echo "... src/io/file.s"
|
||||
@echo "... src/resources/Buffer.o"
|
||||
@echo "... src/resources/Buffer.i"
|
||||
@echo "... src/resources/Buffer.s"
|
||||
@echo "... src/resources/BufferBusWriter.o"
|
||||
@echo "... src/resources/BufferBusWriter.i"
|
||||
@echo "... src/resources/BufferBusWriter.s"
|
||||
@echo "... src/resources/DefaultAllocator.o"
|
||||
@echo "... src/resources/DefaultAllocator.i"
|
||||
@echo "... src/resources/DefaultAllocator.s"
|
||||
@echo "... src/resources/Image.o"
|
||||
@echo "... src/resources/Image.i"
|
||||
@echo "... src/resources/Image.s"
|
||||
@echo "... src/resources/ImageBusWriter.o"
|
||||
@echo "... src/resources/ImageBusWriter.i"
|
||||
@echo "... src/resources/ImageBusWriter.s"
|
||||
@echo "... src/resources/ImageView.o"
|
||||
@echo "... src/resources/ImageView.i"
|
||||
@echo "... src/resources/ImageView.s"
|
||||
@echo "... src/resources/MipmapGenerator.o"
|
||||
@echo "... src/resources/MipmapGenerator.i"
|
||||
@echo "... src/resources/MipmapGenerator.s"
|
||||
@echo "... src/shaders/GlslShaderBuilder.o"
|
||||
@echo "... src/shaders/GlslShaderBuilder.i"
|
||||
@echo "... src/shaders/GlslShaderBuilder.s"
|
||||
@echo "... src/shaders/Pipeline.o"
|
||||
@echo "... src/shaders/Pipeline.i"
|
||||
@echo "... src/shaders/Pipeline.s"
|
||||
@echo "... src/shaders/PipelineBuilder.o"
|
||||
@echo "... src/shaders/PipelineBuilder.i"
|
||||
@echo "... src/shaders/PipelineBuilder.s"
|
||||
@echo "... src/shaders/SpirvShaderBuilder.o"
|
||||
@echo "... src/shaders/SpirvShaderBuilder.i"
|
||||
@echo "... src/shaders/SpirvShaderBuilder.s"
|
||||
.PHONY : help
|
||||
|
||||
|
||||
|
||||
#=============================================================================
|
||||
# Special targets to cleanup operation of make.
|
||||
|
||||
# Special rule to run CMake to check the build system integrity.
|
||||
# No rule that depends on this can have commands that come from listfiles
|
||||
# because they might be regenerated.
|
||||
cmake_check_build_system:
|
||||
cd /home/martin/projects/mmo && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
|
||||
.PHONY : cmake_check_build_system
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <volk.h>
|
||||
#include <vector>
|
||||
#include "Gpu.hpp"
|
||||
|
||||
struct Framebuffer {
|
||||
VkFramebuffer framebuffer;
|
||||
|
||||
Framebuffer(VkFramebuffer fb);
|
||||
|
||||
Framebuffer(const Gpu* gpu, const VkRenderPass renderpass, const VkExtent2D extent,
|
||||
const std::vector<VkImageView>& attachments);
|
||||
};
|
||||
|
||||
class FramebufferBuilder {
|
||||
private:
|
||||
VkRenderPass m_renderpass;
|
||||
VkExtent2D m_extent;
|
||||
|
||||
std::vector<ImageView> m_attachments;
|
||||
|
||||
public:
|
||||
FramebufferBuilder(VkRenderPass renderpass, VkExtent2D extent);
|
||||
|
||||
FramebufferBuilder(VkRenderPass renderpass, VkExtent2D extent, uint32_t numAttachments);
|
||||
|
||||
FramebufferBuilder(VkRenderPass renderpass, VkExtent2D extent, std::vector<ImageView> attachments);
|
||||
|
||||
FramebufferBuilder& set_attachment(uint32_t index, VkImageView view);
|
||||
|
||||
Framebuffer build(const Gpu* gpu);
|
||||
};
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
#include "result.hpp"
|
||||
#include "props.hpp"
|
||||
#include "Instance.hpp"
|
||||
#include "Surface.hpp"
|
||||
#include "resources/GpuAllocator.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
|
||||
/**
|
||||
* Abstract interface for a GPU
|
||||
*/
|
||||
class Gpu {
|
||||
private:
|
||||
const Instance* m_instance;
|
||||
VkPhysicalDevice m_gpu = VK_NULL_HANDLE;
|
||||
VkDevice m_dev = VK_NULL_HANDLE;
|
||||
VkDescriptorPool m_descriptorPool{};
|
||||
|
||||
// Queue for a general commands
|
||||
VkQueue m_graphicsQueue{};
|
||||
uint32_t m_graphicsQueueIdx{};
|
||||
VkCommandPool m_graphicsCommandPool{};
|
||||
|
||||
// Queue for a transfer commands
|
||||
VkQueue m_transferQueue{};
|
||||
uint32_t m_transferQueueIdx{};
|
||||
VkCommandPool m_transferCommandPool{};
|
||||
|
||||
// Queue for present commands
|
||||
VkQueue m_presentQueue{};
|
||||
uint32_t m_presentQueueIdx{};
|
||||
VkCommandPool m_presentCommandPool{};
|
||||
|
||||
VkCommandBuffer m_tracyCommandBuffer;
|
||||
|
||||
std::vector<int32_t> get_queues(std::optional<Surface*> surface);
|
||||
|
||||
ResultCode create_logical_device(std::optional<Surface*> surface);
|
||||
|
||||
ResultCode choose_gpu(VkPhysicalDevice *pOut);
|
||||
|
||||
ResultCode create_descriptor_pool();
|
||||
|
||||
std::unique_ptr<GpuAllocator> m_pAllocator;
|
||||
|
||||
public:
|
||||
GET(m_gpu, gpu);
|
||||
GET(m_dev, dev);
|
||||
|
||||
[[nodiscard]] const Instance* instance() const {
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
GET(m_descriptorPool, descriptor_pool);
|
||||
|
||||
GET(m_graphicsCommandPool, graphics_command_pool);
|
||||
GET(m_graphicsQueue, graphics_queue);
|
||||
|
||||
GET(m_transferCommandPool, transfer_command_pool);
|
||||
GET(m_transferQueue, transfer_queue);
|
||||
|
||||
GET(m_tracyCommandBuffer, tracy_cmd_buf);
|
||||
|
||||
GET(m_pAllocator.get(), memory);
|
||||
|
||||
explicit
|
||||
Gpu(const Instance* instance, std::optional<Surface*> surface);
|
||||
|
||||
~Gpu();
|
||||
|
||||
// Forbid copy
|
||||
Gpu(const Gpu&) = delete;
|
||||
|
||||
static result<Gpu, ResultCode> create(std::shared_ptr<const Instance> instance, VkSurfaceKHR surface);
|
||||
|
||||
inline std::vector<uint32_t> present_queue_ids() const {
|
||||
return {m_presentQueueIdx};
|
||||
}
|
||||
|
||||
inline uint32_t transfer_queue_idx() const {
|
||||
return m_transferQueueIdx;
|
||||
}
|
||||
|
||||
|
||||
void enqueue_present(VkPresentInfoKHR *pPresentInfo) const;
|
||||
void enqueue_graphics(VkSubmitInfo2 *pSubmitInfo, VkFence fence) const;
|
||||
void enqueue_transfer(VkSubmitInfo *pSubmitInfo, VkFence fence) const;
|
||||
|
||||
inline VkSemaphore create_semaphore() const {
|
||||
VkSemaphoreCreateInfo semaphore_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
};
|
||||
|
||||
VkSemaphore semaphore = VK_NULL_HANDLE;
|
||||
if(vkCreateSemaphore(this->dev(), &semaphore_info, nullptr, &semaphore)) {
|
||||
throw std::runtime_error("Failed to create semaphore");
|
||||
}
|
||||
|
||||
return semaphore;
|
||||
}
|
||||
|
||||
inline VkFence create_fence(bool is_signaled) const {
|
||||
VkFenceCreateInfo fence_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.flags = is_signaled ? VK_FENCE_CREATE_SIGNALED_BIT : (VkFenceCreateFlagBits)0
|
||||
};
|
||||
|
||||
VkFence fence = VK_NULL_HANDLE;
|
||||
if(vkCreateFence(this->dev(), &fence_info, nullptr, &fence)) {
|
||||
throw std::runtime_error("Failed to create fence");
|
||||
}
|
||||
|
||||
return fence;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by martin on 11/12/23.
|
||||
//
|
||||
|
||||
#ifndef LOFT_GPUSCHEDULER_H
|
||||
#define LOFT_GPUSCHEDULER_H
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
class GpuScheduler {
|
||||
public:
|
||||
virtual void enqueue_transfer(VkSubmitInfo submitInfo) = 0;
|
||||
virtual void enqueue_graphics(VkSubmitInfo submitInfo) = 0;
|
||||
virtual void enqueue_present(VkPresentInfoKHR presentInfo) = 0;
|
||||
};
|
||||
|
||||
#endif //LOFT_GPUSCHEDULER_H
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <volk.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "props.hpp"
|
||||
#include "debug/Debug.hpp"
|
||||
|
||||
/**
|
||||
* Maintains a connection to a GPU driver
|
||||
*/
|
||||
class Instance {
|
||||
private:
|
||||
VkInstance m_instance;
|
||||
|
||||
public:
|
||||
GET(m_instance, instance);
|
||||
|
||||
// disable copy
|
||||
Instance(const Instance&) = delete;
|
||||
Instance() = delete;
|
||||
|
||||
Instance(const Instance&& other) {
|
||||
this->m_instance = other.m_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new instance and initializes a connection to a GPU driver
|
||||
* @param applicationName Name of the application
|
||||
* @param engineName Name of the rendering engine
|
||||
* @param extensions Additional Vulkan extensions you might want to enable
|
||||
* @param callback Debug log callback
|
||||
*/
|
||||
Instance(const std::string applicationName,
|
||||
const std::string engineName,
|
||||
std::vector<std::string> extensions,
|
||||
std::vector<std::string> layers,
|
||||
lft::dbg::lft_log_callback callback);
|
||||
|
||||
static std::vector<std::string> find_unsupported_layers(
|
||||
std::vector<std::string>& required_layers
|
||||
) {
|
||||
uint32_t available_layers_count = 0;
|
||||
vkEnumerateInstanceLayerProperties(&available_layers_count, nullptr);
|
||||
|
||||
if(available_layers_count == 0) {
|
||||
return required_layers;
|
||||
}
|
||||
|
||||
std::vector<VkLayerProperties> available_layers(available_layers_count);
|
||||
vkEnumerateInstanceLayerProperties(&available_layers_count, available_layers.data());
|
||||
|
||||
std::vector<std::string> available_layer_names(available_layers_count);
|
||||
std::transform(available_layers.begin(), available_layers.end(),
|
||||
available_layer_names.begin(),
|
||||
[](const VkLayerProperties& props) {
|
||||
return std::string(props.layerName);
|
||||
});
|
||||
|
||||
std::sort(available_layer_names.begin(), available_layer_names.end());
|
||||
std::sort(required_layers.begin(), required_layers.end());
|
||||
|
||||
std::vector<std::string> unsupported_layers;
|
||||
std::set_difference(required_layers.begin(), required_layers.end(),
|
||||
available_layer_names.begin(), available_layer_names.end(),
|
||||
std::back_inserter(unsupported_layers));
|
||||
|
||||
return unsupported_layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the required extensions are available
|
||||
* @return A vector of indices of not available extensionse
|
||||
*/
|
||||
static std::vector<std::string> check_extensions(const std::vector<std::string>& requiredExtensions) {
|
||||
auto supportedExtensions = list_extensions();
|
||||
|
||||
std::vector<std::string> unsupported_extensions;
|
||||
std::set_difference(requiredExtensions.begin(), requiredExtensions.end(),
|
||||
supportedExtensions.begin(), supportedExtensions.end(),
|
||||
std::back_inserter(unsupported_extensions));
|
||||
|
||||
return unsupported_extensions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a list of available physical devices
|
||||
* @return A vector of VkPhysicalDevice objects representing available physical devices
|
||||
*/
|
||||
[[nodiscard]] inline std::vector<VkPhysicalDevice> list_physical_devices() const {
|
||||
uint32_t numDevices = 0;
|
||||
vkEnumeratePhysicalDevices(m_instance, &numDevices, nullptr);
|
||||
|
||||
std::vector<VkPhysicalDevice> devices(numDevices);
|
||||
vkEnumeratePhysicalDevices(m_instance, &numDevices, devices.data());
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of available instance extensions
|
||||
* @return A vector of strings representing available instance extensions
|
||||
*/
|
||||
[[nodiscard]] static inline std::vector<std::string> list_extensions() {
|
||||
uint32_t numExtensions = 0;
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &numExtensions, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> extensions(numExtensions);
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &numExtensions, extensions.data());
|
||||
|
||||
std::vector<std::string> extension_names(numExtensions);
|
||||
std::transform(extensions.begin(), extensions.end(),
|
||||
extension_names.begin(),
|
||||
[](const VkExtensionProperties& props) {
|
||||
return std::string(props.extensionName);
|
||||
});
|
||||
|
||||
return extension_names;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace lft {
|
||||
|
||||
class GpuException : public std::exception {
|
||||
std::string m_reason;
|
||||
|
||||
public:
|
||||
GpuException(const std::string& reason) : m_reason(reason) {
|
||||
}
|
||||
|
||||
virtual const char* what() const noexcept override {
|
||||
return m_reason.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "shaders/Pipeline.hpp"
|
||||
|
||||
namespace lft {
|
||||
|
||||
class Recording;
|
||||
|
||||
class RecordingBindPoint {
|
||||
private:
|
||||
const Recording* m_recording;
|
||||
Pipeline m_pipeline;
|
||||
VkPipelineBindPoint m_bind_point;
|
||||
|
||||
public:
|
||||
RecordingBindPoint(
|
||||
const Recording* recording,
|
||||
const Pipeline pipeline,
|
||||
VkPipelineBindPoint bind_point
|
||||
);
|
||||
|
||||
const RecordingBindPoint& bind_descriptor_set(
|
||||
uint32_t set,
|
||||
VkDescriptorSet descriptor_set
|
||||
) const;
|
||||
|
||||
|
||||
const RecordingBindPoint& bind_descriptor_sets(
|
||||
uint32_t first_set,
|
||||
const std::vector<VkDescriptorSet>& descriptor_sets
|
||||
) const;
|
||||
|
||||
const RecordingBindPoint& push_constants(
|
||||
VkShaderStageFlags shader_stages,
|
||||
uint32_t offset, uint32_t size, const void* data
|
||||
) const;
|
||||
};
|
||||
|
||||
class Recording {
|
||||
private:
|
||||
VkCommandBuffer m_cmdbuf;
|
||||
std::optional<RecordingBindPoint> m_latest_graphics_pipeline;
|
||||
|
||||
public:
|
||||
GET(m_cmdbuf, cmdbuf);
|
||||
|
||||
Recording(VkCommandBuffer cmdbuf) : m_cmdbuf(cmdbuf) {}
|
||||
|
||||
/**
|
||||
* Binds pipeline. Will bind all the descriptor sets, etc. to it after.
|
||||
*/
|
||||
inline const RecordingBindPoint bind_graphics_pipeline(const Pipeline& pipeline) const {
|
||||
return RecordingBindPoint(this, pipeline, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds pipeline. Will bind all the descriptor sets, etc. to it after.
|
||||
*/
|
||||
inline const RecordingBindPoint bind_compute_pipeline(const Pipeline& pipeline) const {
|
||||
return RecordingBindPoint(this, pipeline, VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
}
|
||||
|
||||
inline const Recording& draw(
|
||||
uint32_t vertex_count,
|
||||
uint32_t instance_count,
|
||||
uint32_t first_vertex,
|
||||
uint32_t first_instance
|
||||
) const {
|
||||
vkCmdDraw(m_cmdbuf, vertex_count, instance_count, first_vertex, first_instance);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const Recording& draw_indexed(
|
||||
uint32_t index_count,
|
||||
uint32_t instance_count,
|
||||
uint32_t first_index,
|
||||
uint32_t vertex_offset,
|
||||
uint32_t first_instance
|
||||
) const {
|
||||
vkCmdDrawIndexed(m_cmdbuf, index_count, instance_count, first_index, vertex_offset, first_instance);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const Recording& bind_vertex_buffers(
|
||||
const std::vector<Buffer> buffers,
|
||||
std::vector<std::size_t> offsets
|
||||
) const {
|
||||
std::vector<VkBuffer> vertex_buffers(buffers.size());
|
||||
std::transform(buffers.begin(), buffers.end(), vertex_buffers.begin(),
|
||||
[](const Buffer& buffer) { return buffer.buf; });
|
||||
|
||||
vkCmdBindVertexBuffers(m_cmdbuf, 0, vertex_buffers.size(), vertex_buffers.data(), offsets.data());
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const Recording& bind_index_buffer(
|
||||
const Buffer index_buffer,
|
||||
std::size_t offset,
|
||||
VkIndexType index_type
|
||||
) const {
|
||||
vkCmdBindIndexBuffer(m_cmdbuf, index_buffer.buf, offset, index_type);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const Recording& dispatch(
|
||||
uint32_t group_count_x,
|
||||
uint32_t group_count_y,
|
||||
uint32_t group_count_z
|
||||
) const {
|
||||
vkCmdDispatch(m_cmdbuf, group_count_x, group_count_y, group_count_z);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <volk.h>
|
||||
#include "Gpu.hpp"
|
||||
#include "RenderPassLayout.hpp"
|
||||
|
||||
class RenderContext {
|
||||
private:
|
||||
VkCommandBuffer m_commandBuffer;
|
||||
Gpu *m_pGpu;
|
||||
RenderPassLayout *m_pLayout;
|
||||
VkFramebuffer m_framebuffer;
|
||||
|
||||
public:
|
||||
GET(m_commandBuffer, command_buffer);
|
||||
GET(m_framebuffer, framebuffer);
|
||||
GET(m_pGpu, gpu);
|
||||
GET(m_pLayout, layout);
|
||||
|
||||
RenderContext(Gpu *pGpu, VkCommandBuffer commandBuffer,
|
||||
RenderPassLayout *pLayout, VkFramebuffer framebuffer) :
|
||||
m_pGpu(pGpu), m_commandBuffer(commandBuffer), m_pLayout(pLayout),
|
||||
m_framebuffer(framebuffer) {
|
||||
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
struct RenderPassLayout {
|
||||
VkRenderPass renderpass;
|
||||
VkDescriptorSetLayout setLayout[4];
|
||||
VkPipelineLayout layout;
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <volk.h>
|
||||
|
||||
#include "Gpu.hpp"
|
||||
|
||||
namespace lft {
|
||||
|
||||
class SamplerBuilder {
|
||||
private:
|
||||
VkSamplerCreateInfo m_create_info;
|
||||
|
||||
public:
|
||||
SamplerBuilder() : m_create_info({}) {
|
||||
m_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& address_mode_u(VkSamplerAddressMode address_mode) {
|
||||
m_create_info.addressModeU = address_mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& address_mode_v(VkSamplerAddressMode address_mode) {
|
||||
m_create_info.addressModeV = address_mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& address_mode_w(VkSamplerAddressMode address_mode) {
|
||||
m_create_info.addressModeW = address_mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& address_mode(VkSamplerAddressMode address_mode) {
|
||||
address_mode_u(address_mode);
|
||||
address_mode_v(address_mode);
|
||||
address_mode_w(address_mode);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& min_filter(VkFilter filter) {
|
||||
m_create_info.minFilter = filter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& mag_filter(VkFilter filter) {
|
||||
m_create_info.magFilter = filter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& filter(VkFilter filter) {
|
||||
min_filter(filter);
|
||||
mag_filter(filter);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& mipmap_mode(VkSamplerMipmapMode mipmap_mode) {
|
||||
m_create_info.mipmapMode = mipmap_mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& border_color(VkBorderColor color) {
|
||||
m_create_info.borderColor = color;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& lod(float min_lod, float max_lod) {
|
||||
m_create_info.minLod = min_lod;
|
||||
m_create_info.maxLod = max_lod;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline VkSampler build(const Gpu* gpu) {
|
||||
VkSampler sampler = VK_NULL_HANDLE;
|
||||
if(vkCreateSampler(gpu->dev(), &m_create_info, nullptr, &sampler)) {
|
||||
throw std::runtime_error("Failed to create sampler");
|
||||
}
|
||||
return sampler;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <volk.h>
|
||||
|
||||
#include "Instance.hpp"
|
||||
|
||||
/**
|
||||
* Surface is a target for the Gpu instance to render to.
|
||||
*/
|
||||
struct Surface {
|
||||
private:
|
||||
VkInstance m_instance;
|
||||
VkSurfaceKHR m_vk_surface;
|
||||
|
||||
public:
|
||||
GET(m_vk_surface, surface);
|
||||
|
||||
Surface(const Instance* instance, VkSurfaceKHR vk_surface) :
|
||||
m_instance(instance->instance()), m_vk_surface(vk_surface) {}
|
||||
|
||||
Surface(const Surface&) = delete;
|
||||
|
||||
Surface(Surface&& other) noexcept :
|
||||
m_instance(std::exchange(other.m_instance, nullptr)),
|
||||
m_vk_surface(std::exchange(other.m_vk_surface, nullptr)) {
|
||||
|
||||
}
|
||||
|
||||
Surface& operator=(const Surface& other) = delete;
|
||||
Surface& operator=(const Surface&& other) noexcept {
|
||||
this->m_vk_surface = other.m_vk_surface;
|
||||
this->m_instance = other.m_instance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Surface() {
|
||||
vkDestroySurfaceKHR(m_instance, m_vk_surface, nullptr);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "Recording.hpp"
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
namespace lft {
|
||||
|
||||
class ImageSubresource {
|
||||
};
|
||||
|
||||
class ImageSubresourceRange {
|
||||
VkImageSubresourceRange m_range;
|
||||
|
||||
public:
|
||||
ImageSubresourceRange(const Image& image,
|
||||
uint32_t base_mip_level, uint32_t level_count,
|
||||
uint32_t base_array_layer, uint32_t layer_count) {
|
||||
m_range.aspectMask = image.m_aspect_mask;
|
||||
|
||||
m_range.baseMipLevel = base_mip_level;
|
||||
m_range.levelCount = level_count;
|
||||
m_range.baseArrayLayer = base_array_layer;
|
||||
m_range.layerCount = layer_count;
|
||||
}
|
||||
|
||||
static ImageSubresourceRange full(const Image& image) {
|
||||
return ImageSubresourceRange(image, 0, VK_REMAINING_MIP_LEVELS,
|
||||
0, VK_REMAINING_ARRAY_LAYERS);
|
||||
}
|
||||
|
||||
static ImageSubresourceRange mipmap(const Image& image, uint32_t base_mip_level, uint32_t level_count) {
|
||||
return ImageSubresourceRange(image, 0, VK_REMAINING_MIP_LEVELS,
|
||||
0, VK_REMAINING_ARRAY_LAYERS);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// Created by martin on 8/1/24.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef LOFT_DEBUG_HPP
|
||||
#define LOFT_DEBUG_HPP
|
||||
|
||||
#include <string>
|
||||
#include <stdarg.h>
|
||||
|
||||
namespace lft::dbg {
|
||||
enum LogMessageSeverity {
|
||||
info = 0,
|
||||
warning,
|
||||
error
|
||||
};
|
||||
|
||||
enum LogMessageType {
|
||||
general = 0,
|
||||
validation,
|
||||
performance
|
||||
};
|
||||
|
||||
typedef void(*lft_log_callback)(LogMessageSeverity, LogMessageType, const char *__restrict __format, va_list args);
|
||||
|
||||
}
|
||||
extern lft::dbg::lft_log_callback g_logCallback;
|
||||
|
||||
#define LOG_INFO(fmt, ...) g_logCallback(lft::dbg::LogMessageSeverity::info, lft::dbg::LogMessageType::general, fmt, __VA_ARGS__)
|
||||
#define LOG_WARN(fmt, ...) g_logCallback(lft::dbg::LogMessageSeverity::warning, lft::dbg::LogMessageType::general, fmt, __VA_ARGS__)
|
||||
#define LOG_FAIL(fmt, ...) g_logCallback(lft::dbg::LogMessageSeverity::error, lft::dbg::LogMessageType::general, fmt, __VA_ARGS__)
|
||||
|
||||
namespace lft::log {
|
||||
static void info(const char* __format, ...) {
|
||||
va_list list;
|
||||
va_start(list, __format);
|
||||
// g_logCallback(lft::dbg::LogMessageSeverity::info, lft::dbg::LogMessageType::general, __format, list);
|
||||
va_end(list);
|
||||
}
|
||||
|
||||
static void warn(const char* __format, ...) {
|
||||
va_list list;
|
||||
va_start(list, __format);
|
||||
// g_logCallback(lft::dbg::LogMessageSeverity::warning, lft::dbg::LogMessageType::general, __format, list);
|
||||
va_end(list);
|
||||
}
|
||||
|
||||
static void fail(const char* __format, ...) {
|
||||
va_list list;
|
||||
va_start(list, __format);
|
||||
// g_logCallback(lft::dbg::LogMessageSeverity::error, lft::dbg::LogMessageType::general, __format, list);
|
||||
va_end(list);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //LOFT_DEBUG_HPP
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Gpu.hpp"
|
||||
|
||||
class MockGpu : Gpu {
|
||||
public:
|
||||
MockGpu();
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Created by martin on 7/1/24.
|
||||
//
|
||||
|
||||
#ifndef LOFT_SHADERBINARY_H
|
||||
#define LOFT_SHADERBINARY_H
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
struct ShaderBinary {
|
||||
private:
|
||||
std::vector<uint32_t> m_data;
|
||||
|
||||
public:
|
||||
inline const std::vector<uint32_t>& data() const {
|
||||
return m_data;
|
||||
}
|
||||
|
||||
inline const uint32_t code_size() const {
|
||||
// last integer is '\0' => should not be included in code size
|
||||
return m_data.size() - 1;
|
||||
}
|
||||
|
||||
explicit ShaderBinary(std::vector<uint32_t> data) :
|
||||
m_data(std::move(data)) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
#endif //LOFT_SHADERBINARY_H
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include "ShaderBinary.h"
|
||||
|
||||
namespace io::file {
|
||||
/**
|
||||
* Reads file on path in as binary.
|
||||
*
|
||||
* @param path Path of the file
|
||||
* @param pOutSize Pointer to the size_t variable to which the number of
|
||||
* bytes of the file will be set.
|
||||
*/
|
||||
ShaderBinary read_binary(const std::string& path);
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#if _WIN32
|
||||
#define GET(slot, name) const inline decltype(slot) name() const { return slot; }
|
||||
#define REF(slot, name) const inline decltype(slot)& name() const { return slot; }
|
||||
#else
|
||||
#define GET(slot, name) [[nodiscard("Do not discard result of a getter! Use the result!")]] \
|
||||
const inline __typeof(slot) name() const { return slot; }
|
||||
#define REF(slot, name) [[nodiscard("Do not discard result of a getter! Use the result!")]] \
|
||||
const inline __typeof(slot)& name() const { return slot; }
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <volk.h>
|
||||
#include <memory>
|
||||
#include "GpuAllocation.h"
|
||||
|
||||
class Gpu;
|
||||
|
||||
/**
|
||||
* Buffer
|
||||
* Device memory suballocation with generic data inside.
|
||||
*/
|
||||
struct Buffer {
|
||||
VkBuffer buf;
|
||||
GpuAllocation allocation;
|
||||
|
||||
Buffer() : Buffer(VK_NULL_HANDLE, {}) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
Buffer(VkBuffer buffer, GpuAllocation allocation) :
|
||||
buf(buffer), allocation(allocation) {
|
||||
|
||||
}
|
||||
|
||||
Buffer(const Buffer&& a) noexcept :
|
||||
buf(a.buf), allocation(a.allocation) {
|
||||
|
||||
}
|
||||
|
||||
Buffer(const Buffer& a) noexcept :
|
||||
buf(a.buf), allocation(a.allocation) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void set_debug_name(const Gpu* gpu, const std::string& name) const;
|
||||
|
||||
/* disable copy */
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "Gpu.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Writes data to a buffer by using a staging buffer
|
||||
*/
|
||||
class BufferBusWriter {
|
||||
private:
|
||||
const Gpu* m_gpu;
|
||||
|
||||
Buffer m_stagingBuffer;
|
||||
size_t m_busSize;
|
||||
VkCommandBuffer m_stagingCommandBuffer;
|
||||
|
||||
void *m_pData;
|
||||
size_t m_unflushedSize;
|
||||
|
||||
uint32_t m_numWrites;
|
||||
std::vector<std::pair<Buffer*, VkBufferCopy>> m_writes;
|
||||
|
||||
VkFence m_fence;
|
||||
|
||||
int create_staging_command_buffer();
|
||||
int create_staging_buffer(size_t size);
|
||||
|
||||
public:
|
||||
BufferBusWriter(const Gpu* gpu, size_t size);
|
||||
~BufferBusWriter();
|
||||
|
||||
void write(Buffer* pTarget, void *pData, size_t offset, size_t size);
|
||||
void flush();
|
||||
|
||||
void wait();
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "resources/GpuAllocator.h"
|
||||
|
||||
#include "vk_mem_alloc.h"
|
||||
|
||||
class DefaultAllocator : public GpuAllocator {
|
||||
private:
|
||||
VmaAllocator m_allocator;
|
||||
|
||||
public:
|
||||
explicit DefaultAllocator(Gpu *pGpu);
|
||||
|
||||
int create_image(ImageCreateInfo *pImageInfo,
|
||||
MemoryAllocationInfo *pAllocInfo,
|
||||
Image *pOut) override;
|
||||
|
||||
int create_buffer(BufferCreateInfo *pBufferInfo,
|
||||
MemoryAllocationInfo *pAllocInfo,
|
||||
Buffer *pOut) override;
|
||||
|
||||
void destroy_buffer(Buffer *pBuffer) override {
|
||||
|
||||
}
|
||||
void destroy_image(Image *pImage) override {
|
||||
|
||||
}
|
||||
|
||||
inline void map(GpuAllocation& allocation, void **pData) override {
|
||||
vmaMapMemory(m_allocator, allocation.allocation, pData);
|
||||
}
|
||||
|
||||
inline void unmap(GpuAllocation& allocation) override {
|
||||
vmaUnmapMemory(m_allocator, allocation.allocation);
|
||||
}
|
||||
|
||||
inline VkResult flush(GpuAllocation& allocation, size_t offset, size_t size) override {
|
||||
vmaFlushAllocation(m_allocator, allocation.allocation, offset, size);
|
||||
return vmaInvalidateAllocation(m_allocator, allocation.allocation, offset, size);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "vk_mem_alloc.h"
|
||||
|
||||
/*
|
||||
* Gpu memory node.
|
||||
*/
|
||||
struct GpuAllocation {
|
||||
VmaAllocation allocation;
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include "Image.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "GpuAllocation.h"
|
||||
|
||||
struct BufferCreateInfo {
|
||||
size_t size;
|
||||
VkBufferUsageFlags usage;
|
||||
|
||||
bool isExclusive;
|
||||
};
|
||||
|
||||
struct ImageCreateInfo {
|
||||
VkExtent2D extent;
|
||||
VkFormat format;
|
||||
|
||||
VkImageUsageFlags usage;
|
||||
VkImageAspectFlags aspectMask;
|
||||
|
||||
uint32_t arrayLayers;
|
||||
uint32_t mipLevels;
|
||||
};
|
||||
|
||||
enum MemoryUsage {
|
||||
MEMORY_USAGE_AUTO = 0,
|
||||
MEMORY_USAGE_AUTO_PREFER_DEVICE = 1,
|
||||
MEMORY_USAGE_AUTO_PREFER_HOST = 2
|
||||
};
|
||||
|
||||
struct MemoryAllocationInfo {
|
||||
MemoryUsage usage;
|
||||
VkMemoryPropertyFlags requiredFlags;
|
||||
};
|
||||
|
||||
class Gpu;
|
||||
/**
|
||||
* Allocating of memory
|
||||
*/
|
||||
class GpuAllocator {
|
||||
protected:
|
||||
|
||||
public:
|
||||
virtual int create_buffer(BufferCreateInfo *pBufferInfo,
|
||||
MemoryAllocationInfo *pAllocInfo, Buffer *pOut) = 0;
|
||||
virtual int create_image(ImageCreateInfo *pImageInfo,
|
||||
MemoryAllocationInfo *pAllocInfo, Image *pOut) = 0;
|
||||
|
||||
virtual void map(GpuAllocation& allocation, void **pData) = 0;
|
||||
virtual void unmap(GpuAllocation& allocation) = 0;
|
||||
|
||||
virtual void destroy_buffer(Buffer *pBuffer) = 0;
|
||||
virtual void destroy_image(Image *pImage) = 0;
|
||||
|
||||
virtual VkResult flush(GpuAllocation& allocation,
|
||||
size_t offset, size_t size) = 0;
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <volk.h>
|
||||
#include <memory>
|
||||
|
||||
#include "resources/GpuAllocation.h"
|
||||
#include "ImageView.hpp"
|
||||
|
||||
class Gpu;
|
||||
|
||||
struct Image {
|
||||
VkImage img;
|
||||
|
||||
VkImageAspectFlagBits m_aspect_mask;
|
||||
uint32_t m_layer_count;
|
||||
uint32_t m_level_count;
|
||||
|
||||
GpuAllocation allocation;
|
||||
|
||||
public:
|
||||
Image() : Image(VK_NULL_HANDLE, {}) {
|
||||
|
||||
}
|
||||
|
||||
Image(VkImage img, GpuAllocation allocation) :
|
||||
img(img), allocation(allocation) {
|
||||
|
||||
}
|
||||
|
||||
ImageView create_view(const Gpu* gpu, VkFormat format,
|
||||
VkImageSubresourceRange subresource);
|
||||
|
||||
void set_debug_name(const Gpu* gpu, const std::string& name) const;
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include "Gpu.hpp"
|
||||
|
||||
class ImageBusWriter {
|
||||
private:
|
||||
const Gpu* m_gpu;
|
||||
|
||||
/**
|
||||
* Image to which we are writing
|
||||
*/
|
||||
Image *m_pTarget;
|
||||
uint32_t m_formatSize;
|
||||
uint32_t m_imageSize;
|
||||
|
||||
|
||||
/**
|
||||
* Intermediate staging buffer to pass data from heap 3 to heap 0
|
||||
*/
|
||||
Buffer m_stagingBuffer;
|
||||
size_t m_stagingBufferSize;
|
||||
VkCommandBuffer m_stagingCommandBuffer;
|
||||
|
||||
/**
|
||||
* Pointing to where the staging buffer is mapped
|
||||
*/
|
||||
void *m_pMappedData;
|
||||
|
||||
|
||||
std::vector<VkBufferImageCopy> m_writes;
|
||||
uint32_t m_numWrites;
|
||||
|
||||
VkFence m_fence;
|
||||
|
||||
int create_staging_buffer(size_t size);
|
||||
|
||||
int create_staging_command_buffer();
|
||||
|
||||
int create_fence();
|
||||
|
||||
public:
|
||||
ImageBusWriter(const Gpu* gpu, Image *pImage,
|
||||
VkExtent2D extent, uint32_t formatSize,
|
||||
size_t maxWrites);
|
||||
|
||||
void write(VkBufferImageCopy region, void *pData, size_t size);
|
||||
|
||||
void set_target(Image *pTarget) {
|
||||
flush();
|
||||
m_pTarget = pTarget;
|
||||
}
|
||||
|
||||
void flush();
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <volk.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
class Gpu;
|
||||
|
||||
struct ImageView {
|
||||
VkImageView view;
|
||||
|
||||
ImageView() :
|
||||
view(VK_NULL_HANDLE) {
|
||||
}
|
||||
|
||||
ImageView(VkImageView view) :
|
||||
view(view) {
|
||||
}
|
||||
|
||||
void set_debug_name(const std::shared_ptr<const Gpu>& gpu, const std::string& name) const;
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <volk.h>
|
||||
|
||||
#include "Gpu.hpp"
|
||||
|
||||
class MipmapGenerator {
|
||||
private:
|
||||
const Gpu* m_gpu;
|
||||
|
||||
VkCommandBuffer m_commandBuffer;
|
||||
|
||||
VkFence m_fence;
|
||||
|
||||
VkFence create_fence(const Gpu* gpu);
|
||||
|
||||
VkCommandBuffer create_command_buffer(const Gpu* gpu);
|
||||
|
||||
public:
|
||||
explicit MipmapGenerator(const Gpu* gpu);
|
||||
|
||||
uint32_t generate(Image image, VkImageLayout oldLayout, VkExtent2D extent, VkImageSubresourceRange range);
|
||||
};
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <signal.h>
|
||||
#include <utility>
|
||||
|
||||
#define EXPECT(expression,msg) if(!(expression)) { throw std::runtime_error(msg); }
|
||||
|
||||
enum ResultCode {
|
||||
RESULT_OK,
|
||||
RESULT_INVALID_ARGUMENT,
|
||||
RESULT_DRW_FAILURE,
|
||||
RESULT_GPU_ALLOCATION_FAIL,
|
||||
RESULT_GPU_RESOURCE_FAIL,
|
||||
RESULT_GPU_IMAGE_MEMORY_FAIL,
|
||||
RESULT_DRW_FAILED_CREATE_SHADER,
|
||||
RESULT_GPU_DEVICE_CREATION_FAILED,
|
||||
RESULT_GPU_COMMAND_POOL_CREATION_FAILED,
|
||||
RESULT_GPU_DESCRIPTOR_POOL_CREATION_FAILED,
|
||||
RESULT_NO_AVAILABLE_GPU,
|
||||
};
|
||||
|
||||
/**
|
||||
* Result. Returns either TResult or TError
|
||||
*/
|
||||
template<typename TResult, typename TError>
|
||||
union result {
|
||||
private:
|
||||
bool m_isOk;
|
||||
|
||||
struct {
|
||||
bool m_isOk;
|
||||
TResult m_result;
|
||||
} m_result;
|
||||
|
||||
struct {
|
||||
bool m_isOk;
|
||||
TError m_error;
|
||||
} m_error;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
result(TResult result) :
|
||||
m_result({
|
||||
.m_isOk = true,
|
||||
.m_result = result
|
||||
}) {
|
||||
|
||||
}
|
||||
|
||||
~result() {
|
||||
|
||||
}
|
||||
|
||||
static result ok(TResult value) { return std::move(result(value)); }
|
||||
|
||||
static result err(TError err) { return { .m_error = err }; }
|
||||
|
||||
void expect(const char* msg) { raise(SIGINT); }
|
||||
|
||||
bool is_ok() const { return m_isOk; }
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
/**
|
||||
* Defines blending operations for a graphics pipeline.
|
||||
*/
|
||||
struct BlendingInfo {
|
||||
VkBlendOp colorBlendOp;
|
||||
VkBlendFactor srcColorBlendFactor;
|
||||
VkBlendFactor dstColorBlendFactor;
|
||||
|
||||
VkBlendOp alphaBlendOp;
|
||||
VkBlendFactor srcAlphaBlendFactor;
|
||||
VkBlendFactor dstAlphaBlendFactor;
|
||||
|
||||
BlendingInfo() :
|
||||
colorBlendOp(VK_BLEND_OP_ADD),
|
||||
srcColorBlendFactor(VK_BLEND_FACTOR_SRC_ALPHA),
|
||||
dstColorBlendFactor(VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA),
|
||||
alphaBlendOp(VK_BLEND_OP_ADD),
|
||||
srcAlphaBlendFactor(VK_BLEND_FACTOR_SRC_ALPHA),
|
||||
dstAlphaBlendFactor(VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA) {
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "Shader.hpp"
|
||||
#include "Pipeline.hpp"
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
namespace lft {
|
||||
|
||||
class ComputePipelineBuilder {
|
||||
private:
|
||||
const Shader* m_shader;
|
||||
VkPipelineLayout m_layout;
|
||||
|
||||
public:
|
||||
ComputePipelineBuilder(const Shader* shader, VkPipelineLayout layout);
|
||||
|
||||
Pipeline build(const Gpu* gpu);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "ShaderBuilder.hpp"
|
||||
|
||||
class GlslShaderBuilder : public ShaderBuilder {
|
||||
public:
|
||||
Shader from_file(std::string path) override;
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include <volk.h>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
#include "RenderContext.hpp"
|
||||
#include "Shader.hpp"
|
||||
#include "Gpu.hpp"
|
||||
|
||||
/**
|
||||
* Abstracts a Vulkan pipeline
|
||||
*/
|
||||
class Pipeline {
|
||||
VkPipeline m_pipeline;
|
||||
VkPipelineLayout m_layout;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Wraps new pipeline with layout
|
||||
* @param layout pipeline layout
|
||||
* @param pipeline pipeline
|
||||
*/
|
||||
Pipeline(VkPipelineLayout layout, VkPipeline pipeline) :
|
||||
m_layout(layout), m_pipeline(pipeline) {
|
||||
|
||||
}
|
||||
|
||||
VkPipeline pipeline() const {
|
||||
return m_pipeline;
|
||||
}
|
||||
|
||||
VkPipelineLayout pipeline_layout() const {
|
||||
return m_layout;
|
||||
}
|
||||
|
||||
Pipeline& use(RenderContext *pRenderContext) {
|
||||
vkCmdBindPipeline(pRenderContext->command_buffer(),
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
m_pipeline);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Pipeline& bind_input_set(RenderContext *pRenderContext, uint32_t idx, uint32_t num, VkDescriptorSet *pSets) {
|
||||
vkCmdBindDescriptorSets(pRenderContext->command_buffer(),
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
m_layout,
|
||||
idx, num, pSets,
|
||||
0, nullptr);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void set_debug_name(const Gpu* gpu, const std::string name) const {
|
||||
#if LOFT_DEBUG
|
||||
VkDebugUtilsObjectNameInfoEXT nameInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_PIPELINE,
|
||||
.objectHandle = (uint64_t)pipeline(),
|
||||
.pObjectName = name.c_str(),
|
||||
};
|
||||
|
||||
vkSetDebugUtilsObjectNameEXT(gpu->dev(), &nameInfo);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,147 @@
|
||||
#pragma once
|
||||
|
||||
#include "Gpu.hpp"
|
||||
#include "Shader.hpp"
|
||||
#include "VertexBinding.h"
|
||||
#include "VertexAttribute.h"
|
||||
#include "BlendingInfo.h"
|
||||
#include "Pipeline.hpp"
|
||||
#include <volk.h>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
class PipelineLayoutBuilder {
|
||||
private:
|
||||
std::vector<VkDescriptorSetLayout> m_layouts;
|
||||
std::vector<VkPushConstantRange> m_pushConstantRanges;
|
||||
|
||||
uint32_t m_numLayouts;
|
||||
|
||||
public:
|
||||
PipelineLayoutBuilder() :
|
||||
m_layouts(4), m_pushConstantRanges(), m_numLayouts(0) {
|
||||
}
|
||||
|
||||
PipelineLayoutBuilder& input_set(uint32_t idx, VkDescriptorSetLayout setLayout) {
|
||||
if(idx >= m_layouts.size()) {
|
||||
throw std::runtime_error("As of now, only 4 descriptor set layouts are supported");
|
||||
}
|
||||
|
||||
m_layouts[idx] = setLayout;
|
||||
m_numLayouts = std::max(m_numLayouts, idx + 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PipelineLayoutBuilder& push_constant_range(uint32_t offset, uint32_t size, VkShaderStageFlags stages) {
|
||||
m_pushConstantRanges.push_back({
|
||||
.stageFlags = stages,
|
||||
.offset = offset,
|
||||
.size = size,
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
VkPipelineLayout build(const Gpu* gpu) {
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = m_numLayouts,
|
||||
.pSetLayouts = m_layouts.data(),
|
||||
.pushConstantRangeCount = (uint32_t)m_pushConstantRanges.size(),
|
||||
.pPushConstantRanges = m_pushConstantRanges.data(),
|
||||
};
|
||||
|
||||
VkPipelineLayout inputLayout = VK_NULL_HANDLE;
|
||||
if (vkCreatePipelineLayout(gpu->dev(), &pipelineLayoutInfo, nullptr, &inputLayout)) {
|
||||
throw std::runtime_error("Failed to build pipeline layout");
|
||||
}
|
||||
|
||||
return inputLayout;
|
||||
}
|
||||
};
|
||||
|
||||
class PipelineBuilder {
|
||||
private:
|
||||
const Gpu* m_gpu;
|
||||
|
||||
VkPipelineLayout m_layout;
|
||||
VkRenderPass m_renderpass;
|
||||
|
||||
VkViewport m_viewport;
|
||||
VkRect2D m_scissor;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo m_rasterInfo;
|
||||
VkPipelineInputAssemblyStateCreateInfo m_inputAssemblyInfo;
|
||||
VkPipelineDepthStencilStateCreateInfo m_depthStencilInfo;
|
||||
VkPipelineVertexInputStateCreateInfo m_vertexInputInfo;
|
||||
|
||||
std::vector<VkPipelineColorBlendAttachmentState> m_blendingInfo;
|
||||
std::vector<VkPipelineShaderStageCreateInfo> stages;
|
||||
|
||||
std::vector<VertexBinding> m_vertexBindings;
|
||||
std::vector<VertexAttribute> m_vertexAttributes;
|
||||
|
||||
public:
|
||||
inline size_t num_attachments() { return m_blendingInfo.size(); }
|
||||
|
||||
PipelineBuilder(const Gpu* gpu, const VkViewport& viewport,
|
||||
VkPipelineLayout layout, VkRenderPass outputLayout,
|
||||
uint32_t numAttachments,
|
||||
const Shader* vertexShader, const Shader* fragmentShader);
|
||||
|
||||
inline PipelineBuilder& set_vertex_input_info(std::vector<VertexBinding> bindings,
|
||||
std::vector<VertexAttribute> attributes) {
|
||||
m_vertexBindings = std::move(bindings);
|
||||
m_vertexAttributes = std::move(attributes);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Rasterization */
|
||||
inline PipelineBuilder& polygon_mode(VkPolygonMode mode) {
|
||||
this->m_rasterInfo.polygonMode = mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PipelineBuilder& cull_mode(VkCullModeFlags flags) {
|
||||
this->m_rasterInfo.cullMode = flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PipelineBuilder& topology(VkPrimitiveTopology topology) {
|
||||
this->m_inputAssemblyInfo.topology = topology;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PipelineBuilder& set_depth_bias(float depthBiasConstantFactor, float depthBiasClamp,
|
||||
float depthBiasSlopeFactor) {
|
||||
m_rasterInfo.depthBiasEnable = true,
|
||||
m_rasterInfo.depthBiasConstantFactor = depthBiasConstantFactor;
|
||||
m_rasterInfo.depthBiasClamp = depthBiasClamp;
|
||||
m_rasterInfo.depthBiasSlopeFactor = depthBiasSlopeFactor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PipelineBuilder& unset_blending(uint32_t attachmentIdx) {
|
||||
m_blendingInfo[attachmentIdx].blendEnable = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PipelineBuilder& set_blending(uint32_t attachmentIdx, BlendingInfo blendingInfo) {
|
||||
m_blendingInfo[attachmentIdx] = {
|
||||
.blendEnable = true,
|
||||
.srcColorBlendFactor = blendingInfo.srcColorBlendFactor,
|
||||
.dstColorBlendFactor = blendingInfo.dstColorBlendFactor,
|
||||
.colorBlendOp = blendingInfo.colorBlendOp,
|
||||
.srcAlphaBlendFactor = blendingInfo.srcAlphaBlendFactor,
|
||||
.dstAlphaBlendFactor = blendingInfo.dstAlphaBlendFactor,
|
||||
.alphaBlendOp = blendingInfo.alphaBlendOp,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
|
||||
VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT |
|
||||
VK_COLOR_COMPONENT_A_BIT
|
||||
};
|
||||
return *this;
|
||||
}
|
||||
|
||||
Pipeline build();
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
#include "Gpu.hpp"
|
||||
|
||||
namespace lft {
|
||||
class PipelineLayoutBuilder {
|
||||
private:
|
||||
std::vector<VkDescriptorSetLayout> m_layouts;
|
||||
std::vector<VkPushConstantRange> m_pushConstantRanges;
|
||||
|
||||
uint32_t m_numLayouts;
|
||||
|
||||
public:
|
||||
PipelineLayoutBuilder() :
|
||||
m_layouts(4), m_pushConstantRanges(), m_numLayouts(0) {
|
||||
}
|
||||
|
||||
PipelineLayoutBuilder& input_set(uint32_t idx, VkDescriptorSetLayout setLayout) {
|
||||
if(idx >= m_layouts.size()) {
|
||||
throw std::runtime_error("As of now, only 4 descriptor set layouts are supported");
|
||||
}
|
||||
|
||||
m_layouts[idx] = setLayout;
|
||||
m_numLayouts = std::max(m_numLayouts, idx + 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PipelineLayoutBuilder& push_constant_range(uint32_t offset, uint32_t size, VkShaderStageFlags stages) {
|
||||
m_pushConstantRanges.push_back({
|
||||
.stageFlags = stages,
|
||||
.offset = offset,
|
||||
.size = size,
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
VkPipelineLayout build(const Gpu* gpu) {
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = m_numLayouts,
|
||||
.pSetLayouts = m_layouts.data(),
|
||||
.pushConstantRangeCount = (uint32_t)m_pushConstantRanges.size(),
|
||||
.pPushConstantRanges = m_pushConstantRanges.data(),
|
||||
};
|
||||
|
||||
VkPipelineLayout inputLayout = VK_NULL_HANDLE;
|
||||
if (vkCreatePipelineLayout(gpu->dev(), &pipelineLayoutInfo, nullptr, &inputLayout)) {
|
||||
throw std::runtime_error("Failed to build pipeline layout");
|
||||
}
|
||||
|
||||
return inputLayout;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "Gpu.hpp"
|
||||
|
||||
namespace lft {
|
||||
class SamplerBuilder {
|
||||
VkSamplerCreateInfo m_sampler_info = {};
|
||||
|
||||
public:
|
||||
SamplerBuilder() {
|
||||
m_sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& mag_filter(VkFilter filter) {
|
||||
m_sampler_info.magFilter = filter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& min_filter(VkFilter filter) {
|
||||
m_sampler_info.minFilter = filter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& filter(VkFilter filter) {
|
||||
mag_filter(filter);
|
||||
min_filter(filter);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& address_mode_u(VkSamplerAddressMode address_mode) {
|
||||
m_sampler_info.addressModeU = address_mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline SamplerBuilder& address_mode_v(VkSamplerAddressMode address_mode) {
|
||||
m_sampler_info.addressModeV = address_mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& address_mode_w(VkSamplerAddressMode address_mode) {
|
||||
m_sampler_info.addressModeW = address_mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& address_mode(VkSamplerAddressMode address_mode) {
|
||||
address_mode_u(address_mode);
|
||||
address_mode_v(address_mode);
|
||||
address_mode_w(address_mode);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline SamplerBuilder& border_color(VkBorderColor border_color) {
|
||||
m_sampler_info.borderColor = border_color;
|
||||
return *this;
|
||||
}
|
||||
|
||||
VkSampler build(std::shared_ptr<Gpu> gpu) {
|
||||
VkSampler sampler = VK_NULL_HANDLE;
|
||||
if(vkCreateSampler(gpu->dev(), &m_sampler_info, nullptr, &sampler)) {
|
||||
throw std::runtime_error("failed to create sampler");
|
||||
}
|
||||
|
||||
return sampler;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Created by martin on 10/24/23.
|
||||
//
|
||||
|
||||
#ifndef LOFT_SHADER_HPP
|
||||
#define LOFT_SHADER_HPP
|
||||
|
||||
#include "Gpu.hpp"
|
||||
#include "io/ShaderBinary.h"
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
struct Shader {
|
||||
private:
|
||||
VkShaderModule m_module;
|
||||
|
||||
public:
|
||||
Shader(Shader&& s) :
|
||||
m_module(s.m_module) {
|
||||
}
|
||||
|
||||
Shader(VkShaderModule m) :
|
||||
m_module(m) {
|
||||
|
||||
}
|
||||
|
||||
const inline Shader& set_name(const Gpu* gpu, const std::string &name) {
|
||||
#if LOFT_DEBUG
|
||||
VkDebugUtilsObjectNameInfoEXT nameInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_SHADER_MODULE,
|
||||
.objectHandle = (uint64_t) m_module,
|
||||
.pObjectName = name.c_str(),
|
||||
};
|
||||
vkSetDebugUtilsObjectNameEXT(gpu->dev(), &nameInfo);
|
||||
#endif
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline VkShaderModule module() const {
|
||||
return m_module;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //LOFT_SHADER_HPP
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by martin on 10/24/23.
|
||||
//
|
||||
|
||||
#ifndef LOFT_SHADERBUILDER_HPP
|
||||
#define LOFT_SHADERBUILDER_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Shader.hpp"
|
||||
|
||||
class ShaderBuilder {
|
||||
public:
|
||||
virtual Shader from_file(std::string path) = 0;
|
||||
};
|
||||
|
||||
#endif //LOFT_SHADERBUILDER_HPP
|
||||
@@ -0,0 +1,279 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <volk.h>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <assert.h>
|
||||
#include <stdexcept>
|
||||
#include <print>
|
||||
|
||||
#include "resources/Buffer.hpp"
|
||||
#include "resources/Image.hpp"
|
||||
#include "Gpu.hpp"
|
||||
|
||||
|
||||
/**
|
||||
* ShaderInputSetBufferWrite
|
||||
* For having uniform buffer
|
||||
*/
|
||||
struct ShaderInputSetBufferWrite {
|
||||
private:
|
||||
VkDescriptorType m_type;
|
||||
uint32_t m_binding;
|
||||
VkDescriptorBufferInfo m_bufferInfo;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates new shader input set write for Buffer
|
||||
*/
|
||||
ShaderInputSetBufferWrite(VkDescriptorType type, uint32_t binding, const Buffer& buffer,
|
||||
uint32_t offset, uint32_t size) :
|
||||
m_bufferInfo(
|
||||
{
|
||||
.buffer = buffer.buf,
|
||||
.offset = offset,
|
||||
.range = size
|
||||
}
|
||||
),
|
||||
m_binding(binding),
|
||||
m_type(type) {
|
||||
|
||||
}
|
||||
|
||||
const VkDescriptorBufferInfo* info() {
|
||||
return &m_bufferInfo;
|
||||
}
|
||||
};
|
||||
|
||||
struct ShaderInputSetImageWrite {
|
||||
private:
|
||||
VkDescriptorType m_type;
|
||||
uint32_t m_binding;
|
||||
VkDescriptorImageInfo m_imageInfo;
|
||||
|
||||
public:
|
||||
ShaderInputSetImageWrite(uint32_t binding, const ImageView& view, VkSampler sampler) :
|
||||
m_imageInfo(
|
||||
{
|
||||
.sampler = sampler,
|
||||
.imageView = view.view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
}
|
||||
),
|
||||
m_binding(binding),
|
||||
m_type(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) {
|
||||
|
||||
}
|
||||
|
||||
const VkDescriptorImageInfo* info() {
|
||||
return &m_imageInfo;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
union ShaderInputSetWrite {
|
||||
private:
|
||||
struct {
|
||||
VkDescriptorType type;
|
||||
uint32_t binding;
|
||||
} common;
|
||||
ShaderInputSetBufferWrite buffer;
|
||||
ShaderInputSetImageWrite image;
|
||||
|
||||
public:
|
||||
ShaderInputSetWrite() :
|
||||
common() {
|
||||
}
|
||||
|
||||
explicit ShaderInputSetWrite(ShaderInputSetBufferWrite bufferWrite) :
|
||||
buffer(bufferWrite) {
|
||||
|
||||
}
|
||||
|
||||
explicit ShaderInputSetWrite(ShaderInputSetImageWrite imageWrite) :
|
||||
image(imageWrite) {
|
||||
|
||||
}
|
||||
|
||||
uint32_t is_buffer_write(VkDescriptorType type) {
|
||||
return type > VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
|
||||
}
|
||||
|
||||
VkWriteDescriptorSet to_write(VkDescriptorSet set) {
|
||||
return {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = set,
|
||||
.dstBinding = common.binding,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = common.type,
|
||||
.pImageInfo = is_buffer_write(common.type) ? nullptr : image.info(),
|
||||
.pBufferInfo = is_buffer_write(common.type) ? buffer.info() : nullptr,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ShaderInputSetBuilder
|
||||
*
|
||||
* Builds descriptor sets
|
||||
*/
|
||||
struct ShaderInputSetBuilder {
|
||||
private:
|
||||
std::vector<ShaderInputSetWrite> m_writes;
|
||||
|
||||
public:
|
||||
explicit ShaderInputSetBuilder() :
|
||||
m_writes() {
|
||||
|
||||
}
|
||||
|
||||
ShaderInputSetBuilder& image(uint32_t binding, const ImageView& imageView, VkSampler sampler) {
|
||||
assert(imageView.view != VK_NULL_HANDLE);
|
||||
assert(sampler != VK_NULL_HANDLE);
|
||||
|
||||
m_writes.push_back(ShaderInputSetWrite(ShaderInputSetImageWrite(binding, imageView, sampler)));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ShaderInputSetBuilder& buffer(const VkDescriptorType type, const uint32_t binding, const Buffer& buffer, const uint32_t offset, const uint32_t size) {
|
||||
assert(buffer.buf != VK_NULL_HANDLE);
|
||||
|
||||
m_writes.push_back(ShaderInputSetWrite(ShaderInputSetBufferWrite(type, binding, buffer, offset, size)));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates new descriptor sets from layout.
|
||||
* All the writes must be set already.
|
||||
* @param pGpu Gpu on which to perform
|
||||
* @param layout Descriptor set layout
|
||||
* @return Allocated descriptor set with all the writes.
|
||||
*/
|
||||
VkDescriptorSet build(const Gpu* gpu, VkDescriptorSetLayout layout) {
|
||||
VkDescriptorSetAllocateInfo descriptorInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorPool = gpu->descriptor_pool(),
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = &layout
|
||||
};
|
||||
|
||||
VkDescriptorSet set = VK_NULL_HANDLE;
|
||||
if(vkAllocateDescriptorSets(gpu->dev(), &descriptorInfo, &set)) {
|
||||
throw std::runtime_error("Failed to allocate descriptor set");
|
||||
}
|
||||
|
||||
std::vector<VkWriteDescriptorSet> writes(m_writes.size());
|
||||
for(uint32_t i = 0; i < m_writes.size(); i++) {
|
||||
writes[i] = m_writes[i].to_write(set);
|
||||
}
|
||||
|
||||
vkUpdateDescriptorSets(gpu->dev(), writes.size(), writes.data(),
|
||||
0, nullptr);
|
||||
|
||||
return set;
|
||||
}
|
||||
};
|
||||
|
||||
struct ShaderInputSet {
|
||||
private:
|
||||
VkDescriptorSet m_descriptorSet;
|
||||
|
||||
public:
|
||||
inline const VkDescriptorSet descriptor_set() const {
|
||||
return m_descriptorSet;
|
||||
}
|
||||
|
||||
ShaderInputSet(VkDescriptorSet descriptorSet) :
|
||||
m_descriptorSet(descriptorSet) {
|
||||
|
||||
}
|
||||
|
||||
ShaderInputSet(const Gpu* gpu, VkDescriptorSetLayout layout) :
|
||||
m_descriptorSet(VK_NULL_HANDLE) {
|
||||
|
||||
VkDescriptorSetAllocateInfo descriptorInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorPool = gpu->descriptor_pool(),
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = &layout
|
||||
};
|
||||
|
||||
if(vkAllocateDescriptorSets(gpu->dev(), &descriptorInfo, &m_descriptorSet)) {
|
||||
throw std::runtime_error("Failed to allocate descriptor set");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
enum ShaderInputWriteType {
|
||||
|
||||
};
|
||||
|
||||
class ShaderInputSetWriter {
|
||||
private:
|
||||
const Gpu* m_gpu;
|
||||
std::vector<VkWriteDescriptorSet> m_writes;
|
||||
|
||||
std::vector<std::vector<VkDescriptorImageInfo>> m_imageWrites;
|
||||
std::vector<std::vector<VkDescriptorBufferInfo>> m_bufferWrites;
|
||||
|
||||
public:
|
||||
explicit ShaderInputSetWriter(const Gpu* gpu) :
|
||||
m_gpu(gpu) {
|
||||
|
||||
}
|
||||
|
||||
ShaderInputSetWriter& write_images(const ShaderInputSet& dstInputSet,
|
||||
const uint32_t dstBinding,
|
||||
const uint32_t dstArrayElement,
|
||||
const VkDescriptorType type,
|
||||
const std::vector<VkDescriptorImageInfo>& writes) {
|
||||
/* copy write data, to not lose it */
|
||||
m_imageWrites.push_back(writes);
|
||||
|
||||
m_writes.push_back({
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = dstInputSet.descriptor_set(),
|
||||
.dstBinding = dstBinding,
|
||||
.dstArrayElement = dstArrayElement,
|
||||
.descriptorCount = (uint32_t)writes.size(),
|
||||
.descriptorType = type,
|
||||
.pImageInfo = m_imageWrites[m_imageWrites.size() - 1].data()
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ShaderInputSetWriter& write_buffer(const ShaderInputSet& dstInputSet,
|
||||
const uint32_t dstBinding,
|
||||
const uint32_t dstArrayElement,
|
||||
const VkDescriptorType type,
|
||||
const std::vector<VkDescriptorBufferInfo>& writes) {
|
||||
/* copy write data, to not lose it */
|
||||
m_bufferWrites.push_back(writes);
|
||||
|
||||
m_writes.push_back({
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = dstInputSet.descriptor_set(),
|
||||
.dstBinding = dstBinding,
|
||||
.dstArrayElement = dstArrayElement,
|
||||
.descriptorCount = (uint32_t)writes.size(),
|
||||
.descriptorType = type,
|
||||
.pBufferInfo = m_bufferWrites[m_bufferWrites.size() - 1].data()
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ShaderInputSetWriter& write() {
|
||||
vkUpdateDescriptorSets(m_gpu->dev(), m_writes.size(), m_writes.data(), 0, nullptr);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#include "Gpu.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <volk.h>
|
||||
#include <assert.h>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
class ShaderInputSetLayoutBuilder {
|
||||
private:
|
||||
std::vector<VkDescriptorSetLayoutBinding> m_bindings;
|
||||
|
||||
public:
|
||||
ShaderInputSetLayoutBuilder() :
|
||||
m_bindings() {
|
||||
}
|
||||
|
||||
ShaderInputSetLayoutBuilder(std::vector<VkDescriptorSetLayoutBinding> bindings) :
|
||||
m_bindings(bindings) {
|
||||
}
|
||||
|
||||
ShaderInputSetLayoutBuilder& uniform_buffer(
|
||||
uint32_t binding,
|
||||
VkShaderStageFlags shader_stages = VK_SHADER_STAGE_ALL
|
||||
) {
|
||||
m_bindings.push_back({
|
||||
.binding = binding,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = shader_stages,
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ShaderInputSetLayoutBuilder& image(
|
||||
uint32_t binding,
|
||||
VkShaderStageFlags shader_stages = VK_SHADER_STAGE_ALL
|
||||
) {
|
||||
m_bindings.push_back({
|
||||
.binding = binding,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = shader_stages,
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ShaderInputSetLayoutBuilder& n_images(
|
||||
uint32_t binding,
|
||||
uint32_t count,
|
||||
VkShaderStageFlags shader_stages = VK_SHADER_STAGE_ALL
|
||||
) {
|
||||
m_bindings.push_back({
|
||||
.binding = binding,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = count,
|
||||
.stageFlags = shader_stages,
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ShaderInputSetLayoutBuilder& binding(
|
||||
uint32_t binding,
|
||||
VkDescriptorType type,
|
||||
uint32_t count,
|
||||
VkShaderStageFlags stages
|
||||
) {
|
||||
m_bindings.push_back({
|
||||
.binding = binding,
|
||||
.descriptorType = type,
|
||||
.descriptorCount = count,
|
||||
.stageFlags = stages,
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
VkDescriptorSetLayout build(const Gpu* gpu) const {
|
||||
VkDescriptorSetLayoutCreateInfo layoutInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.bindingCount = (uint32_t)m_bindings.size(),
|
||||
.pBindings = m_bindings.data(),
|
||||
};
|
||||
|
||||
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
|
||||
if(vkCreateDescriptorSetLayout(gpu->dev(), &layoutInfo, nullptr, &layout)) {
|
||||
throw std::runtime_error("Failed to create descriptor set layout");
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by martin on 10/24/23.
|
||||
//
|
||||
|
||||
#ifndef LOFT_SPIRVSHADERBUILDER_HPP
|
||||
#define LOFT_SPIRVSHADERBUILDER_HPP
|
||||
|
||||
#include "ShaderBuilder.hpp"
|
||||
#include "Gpu.hpp"
|
||||
|
||||
class SpirvShaderBuilder : public ShaderBuilder {
|
||||
private:
|
||||
const Gpu* m_gpu;
|
||||
|
||||
public:
|
||||
SpirvShaderBuilder(const Gpu* gpu);
|
||||
|
||||
Shader from_binary(const std::vector<uint32_t>& code) const;
|
||||
|
||||
Shader from_file(std::string path) override;
|
||||
};
|
||||
|
||||
#endif //LOFT_SPIRVSHADERBUILDER_HPP
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <volk.h>
|
||||
|
||||
struct VertexAttribute {
|
||||
uint32_t location;
|
||||
uint32_t binding;
|
||||
VkFormat format;
|
||||
uint32_t offset;
|
||||
|
||||
VkVertexInputAttributeDescription get_vk() {
|
||||
return *(VkVertexInputAttributeDescription*)this;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
struct VertexBinding {
|
||||
uint32_t binding;
|
||||
uint32_t stride;
|
||||
VkVertexInputRate inputRate;
|
||||
|
||||
VkVertexInputBindingDescription get_vk() {
|
||||
return *(VkVertexInputBindingDescription*)this;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
#include <stdexcept>
|
||||
#include "FramebufferBuilder.hpp"
|
||||
|
||||
Framebuffer::Framebuffer(VkFramebuffer framebuffer) :
|
||||
framebuffer(framebuffer) {
|
||||
|
||||
}
|
||||
|
||||
Framebuffer::Framebuffer(const Gpu* gpu, const VkRenderPass renderpass, const VkExtent2D extent,
|
||||
const std::vector<VkImageView>& attachments) {
|
||||
VkFramebufferCreateInfo framebufferInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.renderPass = renderpass,
|
||||
.attachmentCount = (uint32_t)attachments.size(),
|
||||
.pAttachments = attachments.data(),
|
||||
.width = extent.width,
|
||||
.height = extent.height,
|
||||
.layers = 1,
|
||||
};
|
||||
|
||||
if(vkCreateFramebuffer(gpu->dev(), &framebufferInfo, nullptr, &framebuffer)) {
|
||||
throw std::runtime_error("Failed to create framebuffer");
|
||||
}
|
||||
}
|
||||
|
||||
FramebufferBuilder::FramebufferBuilder(VkRenderPass renderpass, VkExtent2D extent) :
|
||||
FramebufferBuilder(renderpass, extent, 4) {
|
||||
|
||||
}
|
||||
|
||||
FramebufferBuilder::FramebufferBuilder(VkRenderPass renderpass, VkExtent2D extent, uint32_t numAttachments) :
|
||||
m_renderpass(renderpass), m_extent(extent), m_attachments(numAttachments) {
|
||||
|
||||
}
|
||||
|
||||
FramebufferBuilder::FramebufferBuilder(VkRenderPass renderpass, VkExtent2D extent, std::vector<ImageView> attachments) :
|
||||
m_renderpass(renderpass), m_extent(extent), m_attachments(attachments) {
|
||||
|
||||
}
|
||||
|
||||
Framebuffer FramebufferBuilder::build(const Gpu* gpu) {
|
||||
VkFramebufferCreateInfo framebufferInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.renderPass = m_renderpass,
|
||||
.attachmentCount = (uint32_t)m_attachments.size(),
|
||||
.pAttachments = (VkImageView*)m_attachments.data(),
|
||||
.width = m_extent.width,
|
||||
.height = m_extent.height,
|
||||
.layers = 1,
|
||||
};
|
||||
|
||||
VkFramebuffer framebuffer;
|
||||
if(vkCreateFramebuffer(gpu->dev(), &framebufferInfo, nullptr, &framebuffer)) {
|
||||
throw std::runtime_error("Failed to create framebuffer");
|
||||
}
|
||||
|
||||
return {framebuffer};
|
||||
}
|
||||
|
||||
FramebufferBuilder &FramebufferBuilder::set_attachment(uint32_t idx, VkImageView view) {
|
||||
m_attachments[idx] = ImageView(view);
|
||||
return *this;
|
||||
}
|
||||
+339
@@ -0,0 +1,339 @@
|
||||
#include "Gpu.hpp"
|
||||
|
||||
#include "resources/DefaultAllocator.h"
|
||||
#include "result.hpp"
|
||||
#include "result.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
static const char *DEVICE_EXTENSIONS[] = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME,
|
||||
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
|
||||
VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME,
|
||||
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME
|
||||
};
|
||||
|
||||
static const int NUM_DEVICE_EXTENSIONS = sizeof(DEVICE_EXTENSIONS) / sizeof(*DEVICE_EXTENSIONS);
|
||||
|
||||
#if VK_LAYERS_ENABLE
|
||||
static const char* LAYERS[] = {
|
||||
"VK_LAYER_KHRONOS_validation"
|
||||
};
|
||||
static const int NUM_LAYERS = sizeof(LAYERS) / sizeof(*LAYERS);
|
||||
|
||||
#else
|
||||
#define LAYERS nullptr
|
||||
static const int NUM_LAYERS = 0;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int32_t get_graphics_score(VkQueueFamilyProperties props) {
|
||||
bool isSupported = props.queueFlags | VK_QUEUE_GRAPHICS_BIT;
|
||||
return isSupported;
|
||||
}
|
||||
|
||||
int32_t get_transfer_score(VkQueueFamilyProperties props) {
|
||||
bool isSupported = props.queueFlags | VK_QUEUE_TRANSFER_BIT;
|
||||
bool isDedicated = props.queueFlags & ~(VK_QUEUE_GRAPHICS_BIT);
|
||||
|
||||
return (isDedicated << 1) * isSupported;
|
||||
}
|
||||
|
||||
int32_t get_present_score(VkQueueFamilyProperties props, bool isPresentSupported) {
|
||||
return isPresentSupported;
|
||||
}
|
||||
|
||||
std::vector<int32_t> Gpu::get_queues(std::optional<Surface*> surface) {
|
||||
uint32_t numQueues = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(m_gpu, &numQueues, 0x0);
|
||||
auto properties = std::vector<VkQueueFamilyProperties>(numQueues);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(m_gpu, &numQueues,
|
||||
properties.data());
|
||||
|
||||
if(numQueues == 0) {
|
||||
throw std::runtime_error("Failed to find any queue family");
|
||||
}
|
||||
|
||||
int32_t graphicsQueue = -1;
|
||||
|
||||
int32_t transferQueue = -1;
|
||||
int32_t transferScore = 0;
|
||||
|
||||
int32_t presentQueue = -1;
|
||||
int32_t presentScore = 0;
|
||||
|
||||
uint32_t i = 0;
|
||||
for(auto& prop : properties) {
|
||||
VkBool32 isPresentSupported = false;
|
||||
if(surface.has_value()) {
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(m_gpu, i, surface.value()->surface(), &isPresentSupported);
|
||||
} else {
|
||||
isPresentSupported = true;
|
||||
}
|
||||
|
||||
bool isTaken = false;
|
||||
int32_t iterGraphicsScore = get_graphics_score(prop) * (graphicsQueue == -1);
|
||||
int32_t iterTransferScore = get_transfer_score(prop);
|
||||
int32_t iterPresentScore = get_present_score(prop, isPresentSupported);
|
||||
|
||||
if(iterGraphicsScore > 0) {
|
||||
graphicsQueue = i;
|
||||
isTaken = true;
|
||||
}
|
||||
|
||||
if((iterTransferScore | (!isTaken << 2)) > transferScore) {
|
||||
transferQueue = i;
|
||||
transferScore = (iterTransferScore & (!isTaken << 2));
|
||||
isTaken = true;
|
||||
}
|
||||
|
||||
if((iterPresentScore | (!isTaken << 2)) > presentScore) {
|
||||
presentQueue = i;
|
||||
presentScore = (iterPresentScore & (!isTaken << 2));
|
||||
isTaken = true;
|
||||
}
|
||||
}
|
||||
|
||||
return { graphicsQueue, transferQueue, presentQueue };
|
||||
}
|
||||
|
||||
ResultCode Gpu::create_logical_device(std::optional<Surface*> supportedSurface) {
|
||||
auto queueFamilies = get_queues(supportedSurface);
|
||||
|
||||
std::vector<VkDeviceQueueCreateInfo> queueInfos(queueFamilies.size());
|
||||
float priority = 1.0f;
|
||||
|
||||
int32_t x = 0;
|
||||
for(int32_t i = 0; i < queueFamilies.size(); i++) {
|
||||
bool isDuplicate = false;
|
||||
for(int32_t y = i - 1; y >= 0; y--) {
|
||||
if(queueFamilies[i] == queueFamilies[y]) {
|
||||
isDuplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(isDuplicate) continue;
|
||||
|
||||
queueInfos[x] = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.queueFamilyIndex = (uint32_t)queueFamilies[x],
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &priority
|
||||
};
|
||||
x++;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceFeatures gpuFeatures = { };
|
||||
vkGetPhysicalDeviceFeatures(m_gpu, &gpuFeatures);
|
||||
|
||||
VkPhysicalDeviceSynchronization2Features syncFeatures = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES,
|
||||
.pNext = nullptr,
|
||||
.synchronization2 = true,
|
||||
};
|
||||
|
||||
VkPhysicalDeviceRobustness2FeaturesEXT robustness = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT,
|
||||
.pNext = &syncFeatures,
|
||||
.robustBufferAccess2 = true,
|
||||
.robustImageAccess2 = true,
|
||||
.nullDescriptor = true
|
||||
};
|
||||
|
||||
VkPhysicalDeviceCoherentMemoryFeaturesAMD coherentMemoryFeatures {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD,
|
||||
.pNext = &robustness,
|
||||
.deviceCoherentMemory = true
|
||||
};
|
||||
|
||||
VkDeviceCreateInfo deviceInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = &coherentMemoryFeatures,
|
||||
.queueCreateInfoCount = (uint32_t)x,
|
||||
.pQueueCreateInfos = queueInfos.data(),
|
||||
.enabledLayerCount = NUM_LAYERS,
|
||||
.ppEnabledLayerNames = LAYERS,
|
||||
.enabledExtensionCount = NUM_DEVICE_EXTENSIONS,
|
||||
.ppEnabledExtensionNames = DEVICE_EXTENSIONS,
|
||||
.pEnabledFeatures = &gpuFeatures,
|
||||
};
|
||||
|
||||
if(vkCreateDevice(m_gpu, &deviceInfo, NULL, &m_dev)) {
|
||||
return RESULT_GPU_DEVICE_CREATION_FAILED;
|
||||
}
|
||||
|
||||
VkCommandPoolCreateInfo poolInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||
.queueFamilyIndex = (uint32_t)queueFamilies[0],
|
||||
};
|
||||
|
||||
if(vkCreateCommandPool(m_dev, &poolInfo, nullptr, &m_graphicsCommandPool)) {
|
||||
return RESULT_GPU_COMMAND_POOL_CREATION_FAILED;
|
||||
}
|
||||
|
||||
vkGetDeviceQueue(m_dev, queueFamilies[0], 0, &m_graphicsQueue);
|
||||
if(queueFamilies[0] == queueFamilies[1]) {
|
||||
if(vkCreateCommandPool(m_dev, &poolInfo, nullptr, &m_transferCommandPool)) {
|
||||
return RESULT_GPU_COMMAND_POOL_CREATION_FAILED;
|
||||
}
|
||||
m_transferQueue = m_graphicsQueue;
|
||||
} else {
|
||||
poolInfo.queueFamilyIndex = (uint32_t)queueFamilies[1];
|
||||
if(vkCreateCommandPool(m_dev, &poolInfo, nullptr, &m_transferCommandPool)) {
|
||||
return RESULT_GPU_COMMAND_POOL_CREATION_FAILED;
|
||||
}
|
||||
vkGetDeviceQueue(m_dev, queueFamilies[1], 0, &m_transferQueue);
|
||||
}
|
||||
|
||||
if(vkCreateCommandPool(m_dev, &poolInfo, nullptr, &m_presentCommandPool)) {
|
||||
return RESULT_GPU_COMMAND_POOL_CREATION_FAILED;
|
||||
}
|
||||
|
||||
if(queueFamilies[0] == queueFamilies[2]) {
|
||||
m_presentQueue = m_graphicsQueue;
|
||||
} else if(queueFamilies[1] == queueFamilies[2]) {
|
||||
m_presentQueue = m_transferQueue;
|
||||
} if(queueFamilies[2] != queueFamilies[1] &&
|
||||
queueFamilies[2] != queueFamilies[0]) {
|
||||
vkGetDeviceQueue(m_dev, queueFamilies[2], 0, &m_presentQueue);
|
||||
}
|
||||
|
||||
m_graphicsQueueIdx = queueFamilies[0];
|
||||
m_transferQueueIdx = queueFamilies[1];
|
||||
m_presentQueueIdx = queueFamilies[2];
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
ResultCode Gpu::choose_gpu(VkPhysicalDevice *pOut) {
|
||||
uint32_t numDevices = 0;
|
||||
vkEnumeratePhysicalDevices(m_instance->instance(), &numDevices, nullptr);
|
||||
if(numDevices == 0) {
|
||||
throw std::runtime_error("No GPU supporting Vulkan was found. Try installing Vulkan drivers. Remember that some GPUs does not need to support Vulkan.");
|
||||
}
|
||||
|
||||
auto devices = std::vector<VkPhysicalDevice>(numDevices);
|
||||
vkEnumeratePhysicalDevices(m_instance->instance(), &numDevices, devices.data());
|
||||
|
||||
VkPhysicalDevice chosen = VK_NULL_HANDLE;
|
||||
|
||||
for(auto& device : devices) {
|
||||
VkPhysicalDeviceProperties props;
|
||||
vkGetPhysicalDeviceProperties(device, &props);
|
||||
|
||||
uint32_t numExtensions;
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr, &numExtensions, nullptr);
|
||||
std::vector<VkExtensionProperties> extensions(numExtensions);
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr, &numExtensions, extensions.data());
|
||||
|
||||
for(int x = 0; x < NUM_DEVICE_EXTENSIONS; x++) {
|
||||
bool isFound = false;
|
||||
for(int y = 0; y < numExtensions; y++) {
|
||||
if(!strcmp(extensions[y].extensionName, DEVICE_EXTENSIONS[x])) {
|
||||
isFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isFound) {
|
||||
lft::log::fail("Device %s does not support required device extension: (%s)",
|
||||
props.deviceName, DEVICE_EXTENSIONS[x]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
chosen = device;
|
||||
}
|
||||
|
||||
if(chosen == VK_NULL_HANDLE) {
|
||||
throw std::runtime_error("No GPU supporting all required features was found. Try updating your graphics card driver. This however might not help on older devices.");
|
||||
}
|
||||
|
||||
VkPhysicalDeviceProperties props;
|
||||
vkGetPhysicalDeviceProperties(chosen, &props);
|
||||
lft::log::info("Selected GPU: (%s)", props.deviceName);
|
||||
|
||||
*pOut = chosen;
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
ResultCode Gpu::create_descriptor_pool() {
|
||||
VkDescriptorPoolSize poolSizes[] =
|
||||
{
|
||||
{
|
||||
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = 1000,
|
||||
}, {
|
||||
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1000
|
||||
}, {
|
||||
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = 1000
|
||||
}
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo poolInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.maxSets = 1000,
|
||||
.poolSizeCount = sizeof(poolSizes) / sizeof(*poolSizes),
|
||||
.pPoolSizes = poolSizes,
|
||||
};
|
||||
|
||||
if (vkCreateDescriptorPool(dev(), &poolInfo, nullptr, &m_descriptorPool)) {
|
||||
return RESULT_GPU_DESCRIPTOR_POOL_CREATION_FAILED;
|
||||
}
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
Gpu::Gpu(const Instance* instance, std::optional<Surface*> supportedSurface) :
|
||||
m_instance(instance), m_pAllocator(nullptr) {
|
||||
|
||||
if(choose_gpu(&m_gpu)) {
|
||||
throw std::runtime_error("Failed to choose gpu");
|
||||
}
|
||||
|
||||
if(create_logical_device(supportedSurface)) {
|
||||
throw std::runtime_error("Failed to create logical device");
|
||||
}
|
||||
|
||||
if(create_descriptor_pool()) {
|
||||
throw std::runtime_error("Failed to create descriptor pool");
|
||||
}
|
||||
|
||||
m_pAllocator = std::make_unique<DefaultAllocator>(DefaultAllocator(this));
|
||||
}
|
||||
|
||||
Gpu::~Gpu() {
|
||||
vkDestroyDescriptorPool(m_dev, m_descriptorPool, nullptr);
|
||||
vkDestroyCommandPool(m_dev, m_graphicsCommandPool, nullptr);
|
||||
vkDestroyCommandPool(m_dev, m_transferCommandPool, nullptr);
|
||||
vkDestroyCommandPool(m_dev, m_presentCommandPool, nullptr);
|
||||
vkDestroyDevice(m_dev, nullptr);
|
||||
}
|
||||
|
||||
void Gpu::enqueue_present(VkPresentInfoKHR *pPresentInfo) const {
|
||||
if(vkQueuePresentKHR(m_presentQueue, pPresentInfo)) {
|
||||
throw std::runtime_error("Failed to present");
|
||||
}
|
||||
}
|
||||
|
||||
void Gpu::enqueue_graphics(VkSubmitInfo2 *pSubmitInfo, VkFence fence) const {
|
||||
if(vkQueueSubmit2KHR(m_graphicsQueue, 1, pSubmitInfo, fence)) {
|
||||
throw std::runtime_error("Failed to submit to graphics queue");
|
||||
}
|
||||
}
|
||||
|
||||
void Gpu::enqueue_transfer(VkSubmitInfo *pSubmitInfo, VkFence fence) const {
|
||||
vkQueueSubmit(m_transferQueue, 1, pSubmitInfo, fence);
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <iterator>
|
||||
|
||||
#include "Instance.hpp"
|
||||
#include "result.hpp"
|
||||
#include "debug/Debug.hpp"
|
||||
|
||||
|
||||
#if LOFT_DEBUG && VK_LAYERS_ENABLE
|
||||
static const char* LAYERS[] = {
|
||||
"VK_LAYER_KHRONOS_validation"
|
||||
};
|
||||
|
||||
static const int NUM_LAYERS = sizeof(LAYERS) / sizeof(*LAYERS);
|
||||
#else
|
||||
#define LAYERS nullptr
|
||||
static const int NUM_LAYERS = 0;
|
||||
#endif
|
||||
|
||||
static const char* EXTENSIONS[] = {
|
||||
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
static const int NUM_EXTENSIONS = sizeof(EXTENSIONS) / sizeof(*EXTENSIONS);
|
||||
|
||||
|
||||
static const char *DEVICE_EXTENSIONS[] = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
static const int NUM_DEVICE_EXTENSIONS = sizeof(DEVICE_EXTENSIONS) / sizeof(*DEVICE_EXTENSIONS);
|
||||
|
||||
static bool IS_INITIALIZED = false;
|
||||
|
||||
lft::dbg::lft_log_callback g_logCallback = nullptr;
|
||||
|
||||
VkBool32
|
||||
vk_dbg_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT type,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pData,
|
||||
void *pUserData) {
|
||||
|
||||
if(g_logCallback != nullptr) {
|
||||
g_logCallback(lft::dbg::LogMessageSeverity::error,
|
||||
lft::dbg::LogMessageType::general,
|
||||
pData->pMessage, {});
|
||||
} else {
|
||||
std::cout << pData->pMessage << std::endl;
|
||||
}
|
||||
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
std::string get_unsupported_layers_error_mesg(std::vector<std::string> unsupported_layers) {
|
||||
std::stringstream str;
|
||||
std::copy(unsupported_layers.begin(), unsupported_layers.end(),
|
||||
std::ostream_iterator<std::string>(str, "\n"));
|
||||
return "Unsupported layers: \n" + str.str();
|
||||
}
|
||||
|
||||
std::string get_unsupported_extensions_error_mesg(std::vector<std::string> unsupported_extensions) {
|
||||
std::stringstream str;
|
||||
std::copy(unsupported_extensions.begin(), unsupported_extensions.end(),
|
||||
std::ostream_iterator<std::string>(str, "\n"));
|
||||
return "Unsupported extensions: \n" + str.str();
|
||||
}
|
||||
|
||||
std::vector<char*> transform_strings_to_c_strings(std::vector<std::string> strings) {
|
||||
std::vector<char*> result(strings.size());
|
||||
std::transform(strings.begin(), strings.end(),
|
||||
result.begin(),
|
||||
[](const std::string& str) {
|
||||
return strndup(str.c_str(), str.length());
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Instance::Instance(const std::string applicationName,
|
||||
const std::string engineName,
|
||||
std::vector<std::string> extensions,
|
||||
std::vector<std::string> layers,
|
||||
lft::dbg::lft_log_callback callback) {
|
||||
if(volkInitialize()) {
|
||||
throw std::runtime_error("Failed to initialize volk");
|
||||
}
|
||||
|
||||
// check unsupported extensions
|
||||
auto unsupportedExtensions = check_extensions(extensions);
|
||||
auto unsupportedLayers = find_unsupported_layers(layers);
|
||||
if(!unsupportedExtensions.empty()) {
|
||||
throw std::runtime_error(get_unsupported_extensions_error_mesg(unsupportedExtensions));
|
||||
}
|
||||
|
||||
if(!unsupportedLayers.empty()) {
|
||||
throw std::runtime_error(get_unsupported_layers_error_mesg(unsupportedLayers));
|
||||
}
|
||||
// EXPECT(!unsupportedExtensions.empty(), "Unsupported extensions");
|
||||
|
||||
if(callback) {
|
||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
VkApplicationInfo appInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pApplicationName = "test", // strdup(applicationName.c_str()),
|
||||
.applicationVersion = VK_MAKE_VERSION(1, 0, 0),
|
||||
.pEngineName = "test",// strdup(engineName.c_str()),
|
||||
.apiVersion = VK_API_VERSION_1_1
|
||||
};
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT dbgInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.messageSeverity =
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
|
||||
.messageType =
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
|
||||
.pfnUserCallback = vk_dbg_callback,
|
||||
.pUserData = nullptr
|
||||
};
|
||||
|
||||
std::vector<char*> extension_cstrs = transform_strings_to_c_strings(extensions);
|
||||
std::vector<char*> layer_cstrs = transform_strings_to_c_strings(layers);
|
||||
|
||||
VkInstanceCreateInfo instanceInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
#if LOFT_DEBUG
|
||||
.pNext = &dbgInfo,
|
||||
#endif
|
||||
.pApplicationInfo = &appInfo,
|
||||
#if LOFT_DEBUG
|
||||
.enabledLayerCount = (uint32_t)layer_cstrs.size(),
|
||||
.ppEnabledLayerNames = layer_cstrs.data(),
|
||||
#endif
|
||||
.enabledExtensionCount = (uint32_t)extension_cstrs.size(),
|
||||
.ppEnabledExtensionNames = extension_cstrs.data(),
|
||||
};
|
||||
|
||||
if(callback != nullptr) {
|
||||
g_logCallback = callback;
|
||||
}
|
||||
|
||||
EXPECT(vkCreateInstance(&instanceInfo, nullptr, &m_instance) == VK_SUCCESS,
|
||||
"Failed to create vulkan instance");
|
||||
|
||||
volkLoadInstance(m_instance);
|
||||
|
||||
lft::log::warn("Instance created successfully");
|
||||
|
||||
// cleanup
|
||||
for(char* str : extension_cstrs) {
|
||||
delete [] str;
|
||||
}
|
||||
|
||||
for(char* str : layer_cstrs) {
|
||||
delete [] str;
|
||||
}
|
||||
|
||||
IS_INITIALIZED = true;
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
#include "Recording.hpp"
|
||||
|
||||
namespace lft {
|
||||
|
||||
|
||||
RecordingBindPoint::RecordingBindPoint(
|
||||
const Recording* recording,
|
||||
const Pipeline pipeline,
|
||||
VkPipelineBindPoint bind_point
|
||||
) : m_recording(recording),
|
||||
m_pipeline(pipeline),
|
||||
m_bind_point(bind_point) {
|
||||
vkCmdBindPipeline(m_recording->cmdbuf(), bind_point, pipeline.pipeline());
|
||||
}
|
||||
|
||||
const RecordingBindPoint& RecordingBindPoint::bind_descriptor_set(
|
||||
uint32_t set,
|
||||
VkDescriptorSet descriptor_set
|
||||
) const {
|
||||
vkCmdBindDescriptorSets(m_recording->cmdbuf(),
|
||||
m_bind_point,
|
||||
m_pipeline.pipeline_layout(),
|
||||
set,
|
||||
1, &descriptor_set,
|
||||
0, nullptr);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
const RecordingBindPoint& RecordingBindPoint::bind_descriptor_sets(
|
||||
uint32_t first_set,
|
||||
const std::vector<VkDescriptorSet>& descriptor_sets
|
||||
) const {
|
||||
vkCmdBindDescriptorSets(m_recording->cmdbuf(),
|
||||
m_bind_point,
|
||||
m_pipeline.pipeline_layout(),
|
||||
first_set,
|
||||
descriptor_sets.size(), descriptor_sets.data(),
|
||||
0, nullptr);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
const RecordingBindPoint& RecordingBindPoint::push_constants(
|
||||
VkShaderStageFlags shader_stages,
|
||||
uint32_t offset, uint32_t size, const void* data) const {
|
||||
vkCmdPushConstants(m_recording->cmdbuf(), m_pipeline.pipeline_layout(), shader_stages,
|
||||
offset, size, data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
#include <stdexcept>
|
||||
#include "io/file.hpp"
|
||||
#include "io/ShaderBinary.h"
|
||||
|
||||
ShaderBinary io::file::read_binary(const std::string& path) {
|
||||
FILE *f = fopen(path.c_str(), "rb");
|
||||
|
||||
if(!f) {
|
||||
throw std::runtime_error("Failed to open file");
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t size = ftell(f);
|
||||
std::vector<uint32_t> data(size + 1);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
fread(data.data(), 4, size, f);
|
||||
fclose(f);
|
||||
|
||||
data[size] = '\0';
|
||||
|
||||
return ShaderBinary(data);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by martin on 4/5/24.
|
||||
//
|
||||
|
||||
#include "resources/Buffer.hpp"
|
||||
#include "Gpu.hpp"
|
||||
|
||||
void Buffer::set_debug_name(const Gpu* gpu, const std::string& name) const {
|
||||
#if LOFT_DEBUG && VK_EXT_debug_utils
|
||||
VkDebugUtilsObjectNameInfoEXT nameInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_BUFFER,
|
||||
.objectHandle = (uint64_t)buf,
|
||||
.pObjectName = name.c_str(),
|
||||
};
|
||||
|
||||
vkSetDebugUtilsObjectNameEXT(gpu->dev(), &nameInfo);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
#include "resources/BufferBusWriter.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <volk.h>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
int
|
||||
BufferBusWriter::create_staging_buffer(size_t size) {
|
||||
BufferCreateInfo stagingBufferInfo = {
|
||||
.size = size,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
.isExclusive = true
|
||||
};
|
||||
|
||||
MemoryAllocationInfo memoryAllocationInfo = {
|
||||
.usage = MEMORY_USAGE_AUTO_PREFER_HOST,
|
||||
.requiredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
};
|
||||
|
||||
m_gpu->memory()->create_buffer(&stagingBufferInfo, &memoryAllocationInfo,
|
||||
&m_stagingBuffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
BufferBusWriter::create_staging_command_buffer() {
|
||||
VkCommandBufferAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = m_gpu->transfer_command_pool(),
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
|
||||
vkAllocateCommandBuffers(m_gpu->dev(), &allocInfo, &m_stagingCommandBuffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BufferBusWriter::BufferBusWriter(const Gpu* gpu, size_t size) :
|
||||
m_gpu(gpu), m_unflushedSize(0), m_busSize(size), m_numWrites(0) {
|
||||
create_staging_buffer(size);
|
||||
|
||||
create_staging_command_buffer();
|
||||
|
||||
m_gpu->memory()->map(m_stagingBuffer.allocation, &m_pData);
|
||||
|
||||
VkFenceCreateInfo fenceInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.flags = VK_FENCE_CREATE_SIGNALED_BIT
|
||||
};
|
||||
|
||||
vkCreateFence(m_gpu->dev(), &fenceInfo, nullptr, &m_fence);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void BufferBusWriter::write(Buffer* pTarget, void *pData, size_t offset, size_t size) {
|
||||
char* pUploadData = (char*)pData;
|
||||
|
||||
while(size > 0) {
|
||||
size_t uploadSize = std::min(m_busSize - m_unflushedSize, size);
|
||||
|
||||
memcpy((char*)m_pData + m_unflushedSize, pUploadData, uploadSize);
|
||||
pUploadData += uploadSize;
|
||||
|
||||
VkBufferCopy write = {
|
||||
.srcOffset = m_unflushedSize,
|
||||
.dstOffset = offset,
|
||||
.size = uploadSize,
|
||||
};
|
||||
m_numWrites++;
|
||||
|
||||
if(m_writes.size() <= m_numWrites) {
|
||||
m_writes.resize(m_numWrites * 2);
|
||||
}
|
||||
m_writes[m_numWrites - 1] = std::pair(pTarget, write);
|
||||
m_unflushedSize += uploadSize;
|
||||
|
||||
offset += uploadSize;
|
||||
size -= uploadSize;
|
||||
|
||||
if(m_busSize - m_unflushedSize == 0) {
|
||||
flush();
|
||||
// wait, because we are gonna overwrite the data
|
||||
wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void BufferBusWriter::flush() {
|
||||
if(m_numWrites == 0) {
|
||||
m_unflushedSize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
m_gpu->memory()->flush(m_stagingBuffer.allocation, 0, m_unflushedSize);
|
||||
|
||||
wait();
|
||||
vkResetFences(m_gpu->dev(), 1, &m_fence);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||
};
|
||||
|
||||
vkBeginCommandBuffer(m_stagingCommandBuffer, &beginInfo);
|
||||
|
||||
for(uint32_t i = 0; i < m_numWrites; i++) {
|
||||
vkCmdCopyBuffer(m_stagingCommandBuffer, m_stagingBuffer.buf, m_writes[i].first->buf,
|
||||
1, &m_writes[i].second);
|
||||
}
|
||||
|
||||
vkEndCommandBuffer(m_stagingCommandBuffer);
|
||||
|
||||
VkSubmitInfo submitInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &m_stagingCommandBuffer,
|
||||
};
|
||||
|
||||
m_gpu->enqueue_transfer(&submitInfo, m_fence);
|
||||
|
||||
m_unflushedSize = 0;
|
||||
m_numWrites = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BufferBusWriter::~BufferBusWriter() {
|
||||
flush();
|
||||
wait();
|
||||
|
||||
m_gpu->memory()->destroy_buffer(&m_stagingBuffer);
|
||||
}
|
||||
|
||||
void BufferBusWriter::wait() {
|
||||
vkWaitForFences(m_gpu->dev(), 1, &m_fence, VK_TRUE, UINT64_MAX);
|
||||
// vkDeviceWaitIdle(m_pGpu->dev());
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#include "resources/DefaultAllocator.h"
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include "vk_mem_alloc.h"
|
||||
#include "Gpu.hpp"
|
||||
|
||||
DefaultAllocator::DefaultAllocator(Gpu *pGpu) {
|
||||
VmaVulkanFunctions vma_vulkan_func{};
|
||||
vma_vulkan_func.vkAllocateMemory = vkAllocateMemory;
|
||||
vma_vulkan_func.vkBindBufferMemory = vkBindBufferMemory;
|
||||
vma_vulkan_func.vkBindImageMemory = vkBindImageMemory;
|
||||
vma_vulkan_func.vkCreateBuffer = vkCreateBuffer;
|
||||
vma_vulkan_func.vkCreateImage = vkCreateImage;
|
||||
vma_vulkan_func.vkDestroyBuffer = vkDestroyBuffer;
|
||||
vma_vulkan_func.vkDestroyImage = vkDestroyImage;
|
||||
vma_vulkan_func.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges;
|
||||
vma_vulkan_func.vkFreeMemory = vkFreeMemory;
|
||||
vma_vulkan_func.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements;
|
||||
vma_vulkan_func.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements;
|
||||
vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties;
|
||||
vma_vulkan_func.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties;
|
||||
vma_vulkan_func.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges;
|
||||
vma_vulkan_func.vkMapMemory = vkMapMemory;
|
||||
vma_vulkan_func.vkUnmapMemory = vkUnmapMemory;
|
||||
vma_vulkan_func.vkCmdCopyBuffer = vkCmdCopyBuffer;
|
||||
vma_vulkan_func.vkGetDeviceProcAddr = vkGetDeviceProcAddr;
|
||||
vma_vulkan_func.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
|
||||
|
||||
VmaAllocatorCreateInfo allocatorCreateInfo = {
|
||||
.physicalDevice = pGpu->gpu(),
|
||||
.device = pGpu->dev(),
|
||||
.pVulkanFunctions = &vma_vulkan_func,
|
||||
.instance = pGpu->instance()->instance(),
|
||||
.vulkanApiVersion = VK_API_VERSION_1_0,
|
||||
};
|
||||
|
||||
vmaCreateAllocator(&allocatorCreateInfo, &m_allocator);
|
||||
}
|
||||
|
||||
VmaMemoryUsage get_vma_memory_usage(MemoryUsage memoryUsage) {
|
||||
switch(memoryUsage) {
|
||||
case MEMORY_USAGE_AUTO:
|
||||
return VMA_MEMORY_USAGE_AUTO;
|
||||
case MEMORY_USAGE_AUTO_PREFER_DEVICE:
|
||||
return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||
case MEMORY_USAGE_AUTO_PREFER_HOST:
|
||||
return VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
|
||||
default:
|
||||
return VMA_MEMORY_USAGE_AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
int DefaultAllocator::create_buffer(BufferCreateInfo *pBufferInfo, MemoryAllocationInfo *pAllocInfo, Buffer *pOut) {
|
||||
VkBufferCreateInfo bufferInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = pBufferInfo->size,
|
||||
.usage = pBufferInfo->usage,
|
||||
.sharingMode = pBufferInfo->isExclusive ? VK_SHARING_MODE_EXCLUSIVE : VK_SHARING_MODE_CONCURRENT
|
||||
};
|
||||
|
||||
VmaAllocationCreateInfo allocInfo = {
|
||||
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||
.usage = get_vma_memory_usage(pAllocInfo->usage),
|
||||
.requiredFlags = pAllocInfo->requiredFlags,
|
||||
};
|
||||
|
||||
vmaCreateBuffer(m_allocator, &bufferInfo, &allocInfo, &pOut->buf, &pOut->allocation.allocation, nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DefaultAllocator::create_image(ImageCreateInfo *pImageInfo, MemoryAllocationInfo *pAllocInfo, Image *pOut) {
|
||||
VkImageCreateInfo imageInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = pImageInfo->format,
|
||||
.extent = {
|
||||
pImageInfo->extent.width,
|
||||
pImageInfo->extent.height,
|
||||
1,
|
||||
},
|
||||
.mipLevels = pImageInfo->mipLevels,
|
||||
.arrayLayers = pImageInfo->arrayLayers,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = pImageInfo->usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED
|
||||
};
|
||||
|
||||
VmaAllocationCreateInfo allocInfo = {};
|
||||
allocInfo.usage = get_vma_memory_usage(pAllocInfo->usage);
|
||||
allocInfo.requiredFlags = pAllocInfo->requiredFlags;
|
||||
|
||||
vmaCreateImage(m_allocator, &imageInfo, &allocInfo, &pOut->img, &pOut->allocation.allocation, nullptr);
|
||||
|
||||
pOut->m_layer_count = imageInfo.arrayLayers;
|
||||
pOut->m_level_count = imageInfo.mipLevels;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "resources/Image.hpp"
|
||||
|
||||
#include "Gpu.hpp"
|
||||
|
||||
ImageView
|
||||
Image::create_view(const Gpu* gpu, VkFormat format,
|
||||
VkImageSubresourceRange subresource) {
|
||||
VkImageViewCreateInfo viewInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = img,
|
||||
.viewType = subresource.layerCount == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY,
|
||||
.format = format,
|
||||
.components = {
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY
|
||||
},
|
||||
.subresourceRange = subresource
|
||||
};
|
||||
|
||||
VkImageView result = VK_NULL_HANDLE;
|
||||
vkCreateImageView(gpu->dev(), &viewInfo, nullptr, &result);
|
||||
|
||||
return {result};
|
||||
}
|
||||
|
||||
void Image::set_debug_name(const Gpu* gpu, const std::string& name) const {
|
||||
#if LOFT_DEBUG
|
||||
VkDebugUtilsObjectNameInfoEXT nameInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_IMAGE,
|
||||
.objectHandle = (uint64_t)img,
|
||||
.pObjectName = name.c_str(),
|
||||
};
|
||||
|
||||
vkSetDebugUtilsObjectNameEXT(gpu->dev(), &nameInfo);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
#include "resources/ImageBusWriter.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <volk.h>
|
||||
#include <cmath>
|
||||
|
||||
int ImageBusWriter::create_staging_buffer(size_t size) {
|
||||
BufferCreateInfo stagingBufferInfo = {
|
||||
.size = size,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
.isExclusive = true
|
||||
};
|
||||
|
||||
MemoryAllocationInfo memoryAllocationInfo = {
|
||||
.usage = MEMORY_USAGE_AUTO_PREFER_HOST
|
||||
};
|
||||
|
||||
m_gpu->memory()->create_buffer(&stagingBufferInfo, &memoryAllocationInfo,
|
||||
&m_stagingBuffer);
|
||||
|
||||
m_gpu->memory()->map(m_stagingBuffer.allocation, &m_pMappedData);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ImageBusWriter::create_staging_command_buffer() {
|
||||
VkCommandBufferAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = m_gpu->transfer_command_pool(),
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
|
||||
vkAllocateCommandBuffers(m_gpu->dev(), &allocInfo,
|
||||
&m_stagingCommandBuffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ImageBusWriter::create_fence() {
|
||||
VkFenceCreateInfo fenceInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.flags = VK_FENCE_CREATE_SIGNALED_BIT
|
||||
};
|
||||
|
||||
vkCreateFence(m_gpu->dev(), &fenceInfo, nullptr, &m_fence);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ImageBusWriter::ImageBusWriter(const Gpu* gpu, Image *pTarget,
|
||||
VkExtent2D extent, uint32_t formatSize,
|
||||
size_t maxWrites) :
|
||||
m_gpu(gpu),
|
||||
m_pTarget(pTarget),
|
||||
m_writes(maxWrites),
|
||||
m_numWrites(0),
|
||||
m_formatSize(formatSize),
|
||||
m_imageSize(extent.width * extent.height * formatSize) {
|
||||
create_staging_buffer(extent.width * extent.height * formatSize);
|
||||
create_staging_command_buffer();
|
||||
create_fence();
|
||||
}
|
||||
|
||||
void ImageBusWriter::write(VkBufferImageCopy write, void *pData, size_t size) {
|
||||
write.bufferOffset = m_numWrites * m_imageSize;
|
||||
m_writes[m_numWrites] = write;
|
||||
|
||||
memcpy((char*)m_pMappedData + m_numWrites * m_imageSize, pData, size);
|
||||
|
||||
m_numWrites++;
|
||||
|
||||
if(m_numWrites >= m_writes.size()) {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
void ImageBusWriter::flush() {
|
||||
if(m_numWrites == 0) return;
|
||||
|
||||
vkWaitForFences(m_gpu->dev(), 1, &m_fence, VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(m_gpu->dev(), 1, &m_fence);
|
||||
|
||||
m_gpu->memory()->flush(m_stagingBuffer.allocation, 0,
|
||||
m_imageSize * m_numWrites);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
|
||||
};
|
||||
|
||||
vkBeginCommandBuffer(m_stagingCommandBuffer, &beginInfo);
|
||||
|
||||
VkImageMemoryBarrier barrierInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = m_pTarget->img,
|
||||
};
|
||||
|
||||
std::vector<VkImageMemoryBarrier> barriers(m_writes.size(), barrierInfo);
|
||||
|
||||
uint32_t i = 0;
|
||||
for(auto& write : m_writes) {
|
||||
barriers[i++].subresourceRange = {
|
||||
.aspectMask = write.imageSubresource.aspectMask,
|
||||
.baseMipLevel = write.imageSubresource.mipLevel,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = write.imageSubresource.baseArrayLayer,
|
||||
.layerCount = write.imageSubresource.layerCount,
|
||||
};
|
||||
}
|
||||
|
||||
vkCmdPipelineBarrier(m_stagingCommandBuffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
barriers.size(), barriers.data());
|
||||
|
||||
vkCmdCopyBufferToImage(
|
||||
m_stagingCommandBuffer,
|
||||
m_stagingBuffer.buf,
|
||||
m_pTarget->img,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
m_numWrites,
|
||||
m_writes.data()
|
||||
);
|
||||
|
||||
for(auto& barrier : barriers) {
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
vkCmdPipelineBarrier(m_stagingCommandBuffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
barriers.size(), barriers.data());
|
||||
|
||||
vkEndCommandBuffer(m_stagingCommandBuffer);
|
||||
|
||||
VkSubmitInfo submitInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &m_stagingCommandBuffer
|
||||
};
|
||||
|
||||
m_gpu->enqueue_transfer(&submitInfo, m_fence);
|
||||
|
||||
m_numWrites = 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "resources/ImageView.hpp"
|
||||
|
||||
|
||||
#include "Gpu.hpp"
|
||||
|
||||
void ImageView::set_debug_name(const std::shared_ptr<const Gpu>& gpu, const std::string &name) const {
|
||||
#if LOFT_DEBUG
|
||||
VkDebugUtilsObjectNameInfoEXT nameInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
||||
.objectType = VK_OBJECT_TYPE_IMAGE_VIEW,
|
||||
.objectHandle = (uint64_t)view,
|
||||
.pObjectName = name.c_str(),
|
||||
};
|
||||
|
||||
vkSetDebugUtilsObjectNameEXT(gpu->dev(), &nameInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
#include "resources/MipmapGenerator.h"
|
||||
#include "Gpu.hpp"
|
||||
#include "Recording.hpp"
|
||||
#include "TransferTaskPipeline.hpp"
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
MipmapGenerator::MipmapGenerator(const Gpu* gpu) :
|
||||
m_gpu(gpu), m_commandBuffer(create_command_buffer(gpu)), m_fence(create_fence(gpu)) {
|
||||
|
||||
}
|
||||
|
||||
VkFence MipmapGenerator::create_fence(const Gpu* gpu) {
|
||||
VkFenceCreateInfo fenceInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.flags = VK_FENCE_CREATE_SIGNALED_BIT
|
||||
};
|
||||
|
||||
VkFence fence = VK_NULL_HANDLE;
|
||||
vkCreateFence(gpu->dev(), &fenceInfo, nullptr, &fence);
|
||||
|
||||
return fence;
|
||||
}
|
||||
|
||||
VkCommandBuffer MipmapGenerator::create_command_buffer(const Gpu* gpu) {
|
||||
VkCommandBufferAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = gpu->transfer_command_pool(),
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
|
||||
VkCommandBuffer cmdbuf = VK_NULL_HANDLE;
|
||||
vkAllocateCommandBuffers(gpu->dev(), &allocInfo,
|
||||
&cmdbuf);
|
||||
|
||||
return cmdbuf;
|
||||
}
|
||||
|
||||
uint32_t MipmapGenerator::generate(Image image, VkImageLayout oldLayout, VkExtent2D extent, VkImageSubresourceRange range) {
|
||||
vkWaitForFences(m_gpu->dev(), 1, &m_fence, VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(m_gpu->dev(), 1, &m_fence);
|
||||
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
|
||||
};
|
||||
|
||||
vkBeginCommandBuffer(m_commandBuffer, &beginInfo);
|
||||
|
||||
VkImageMemoryBarrier barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
||||
.oldLayout = oldLayout,
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = image.img,
|
||||
.subresourceRange = {
|
||||
.aspectMask = range.aspectMask,
|
||||
.baseMipLevel = 1,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = range.layerCount,
|
||||
},
|
||||
};
|
||||
|
||||
vkCmdPipelineBarrier(m_commandBuffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
1, &barrier);
|
||||
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
|
||||
int32_t width = extent.width;
|
||||
auto layout = oldLayout;
|
||||
|
||||
for (uint32_t i = 1; i < range.levelCount; i++) {
|
||||
uint32_t from_level = i - 1;
|
||||
uint32_t to_level = i;
|
||||
|
||||
std::vector<VkImageMemoryBarrier> barriers(2, barrier);
|
||||
barriers[0].oldLayout = layout;
|
||||
barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
barriers[0].subresourceRange.baseMipLevel = from_level;
|
||||
|
||||
vkCmdPipelineBarrier(m_commandBuffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
1, barriers.data());
|
||||
|
||||
VkImageBlit blit = {
|
||||
.srcSubresource = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.mipLevel = from_level,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = range.layerCount,
|
||||
},
|
||||
.srcOffsets = {
|
||||
{ 0, 0, 0 },
|
||||
{ width, width, 1 }
|
||||
},
|
||||
.dstSubresource = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.mipLevel = to_level,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = range.layerCount
|
||||
},
|
||||
.dstOffsets = {
|
||||
{ 0, 0, 0 },
|
||||
{
|
||||
width > 1 ? width / 2 : 1,
|
||||
width > 1 ? width / 2 : 1,
|
||||
1
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
vkCmdBlitImage(m_commandBuffer,
|
||||
image.img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
image.img, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1, &blit,
|
||||
VK_FILTER_LINEAR);
|
||||
|
||||
// transfer back to old layout
|
||||
/* barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
barriers[0].newLayout = oldLayout;
|
||||
barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(m_commandBuffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
1, barriers.data()); */
|
||||
|
||||
width /= 2;
|
||||
layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
}
|
||||
|
||||
std::vector<VkImageMemoryBarrier> barriers(2, barrier);
|
||||
|
||||
barriers[0].subresourceRange.baseMipLevel = 0;
|
||||
barriers[0].subresourceRange.levelCount = range.levelCount - 1;
|
||||
|
||||
barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
barriers[0].newLayout = oldLayout;
|
||||
barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
|
||||
barriers[1].subresourceRange.baseMipLevel = range.levelCount - 1;
|
||||
barriers[1].subresourceRange.levelCount = 1;
|
||||
|
||||
barriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
barriers[1].newLayout = oldLayout;
|
||||
barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
barriers[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(m_commandBuffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
2, barriers.data());
|
||||
|
||||
|
||||
vkEndCommandBuffer(m_commandBuffer);
|
||||
|
||||
VkSubmitInfo submitInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &m_commandBuffer
|
||||
};
|
||||
|
||||
m_gpu->enqueue_transfer(&submitInfo, m_fence);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "shaders/ComputePipelineBuilder.hpp"
|
||||
|
||||
namespace lft {
|
||||
|
||||
ComputePipelineBuilder::ComputePipelineBuilder(const Shader* shader, VkPipelineLayout layout) :
|
||||
m_shader(shader),
|
||||
m_layout(layout) {
|
||||
|
||||
}
|
||||
|
||||
Pipeline ComputePipelineBuilder::build(const Gpu* gpu) {
|
||||
VkPipelineShaderStageCreateInfo computeShaderStageInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
.module = m_shader->module(),
|
||||
.pName = "main",
|
||||
};
|
||||
|
||||
VkComputePipelineCreateInfo pipeline_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
|
||||
.stage = computeShaderStageInfo,
|
||||
.layout = m_layout,
|
||||
};
|
||||
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
if (vkCreateComputePipelines(gpu->dev(),
|
||||
VK_NULL_HANDLE, 1, &pipeline_info, nullptr,
|
||||
&pipeline) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create compute pipeline!");
|
||||
}
|
||||
|
||||
return Pipeline(m_layout, pipeline);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// Created by martin on 10/24/23.
|
||||
//
|
||||
|
||||
#include "../../include/shaders/GlslShaderBuilder.hpp"
|
||||
|
||||
Shader GlslShaderBuilder::from_file(std::string path) {
|
||||
Shader shader(VK_NULL_HANDLE);
|
||||
return shader;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
#include "shaders/Pipeline.hpp"
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "shaders/PipelineBuilder.h"
|
||||
#include "shaders/Shader.hpp"
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
PipelineBuilder::PipelineBuilder(const Gpu* gpu, const VkViewport& viewport,
|
||||
VkPipelineLayout layout, VkRenderPass outputLayout,
|
||||
uint32_t numAttachments,
|
||||
const Shader* vertexShader, const Shader* fragmentShader) :
|
||||
m_gpu(gpu),
|
||||
m_viewport(viewport),
|
||||
m_scissor({
|
||||
.offset = {0, 0},
|
||||
.extent = {(uint32_t)viewport.width, (uint32_t)std::abs(viewport.height)}
|
||||
}),
|
||||
m_layout(layout), m_renderpass(outputLayout),
|
||||
m_inputAssemblyInfo({
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||
.primitiveRestartEnable = false
|
||||
}),
|
||||
m_rasterInfo({
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.depthClampEnable = false,
|
||||
.rasterizerDiscardEnable = false,
|
||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||
.cullMode = VK_CULL_MODE_BACK_BIT,
|
||||
.frontFace = VK_FRONT_FACE_CLOCKWISE,
|
||||
.depthBiasEnable = false,
|
||||
.lineWidth = 1.0f
|
||||
}),
|
||||
m_depthStencilInfo({
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||
.depthTestEnable = true,
|
||||
.depthWriteEnable = true,
|
||||
.depthCompareOp = VK_COMPARE_OP_LESS,
|
||||
.depthBoundsTestEnable = false,
|
||||
.stencilTestEnable = false
|
||||
}),
|
||||
m_vertexInputInfo({
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
}),
|
||||
m_blendingInfo(numAttachments)
|
||||
{
|
||||
stages.resize(2);
|
||||
stages[0] = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.module = vertexShader->module(),
|
||||
.pName = "main"
|
||||
};
|
||||
|
||||
stages[1] = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.module = fragmentShader->module(),
|
||||
.pName = "main",
|
||||
};
|
||||
|
||||
for(uint32_t i = 0; i < num_attachments(); i++) {
|
||||
m_blendingInfo[i] = {
|
||||
.blendEnable = false,
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
|
||||
VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT |
|
||||
VK_COLOR_COMPONENT_A_BIT
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Pipeline PipelineBuilder::build() {
|
||||
m_vertexInputInfo.vertexBindingDescriptionCount = m_vertexBindings.size();
|
||||
m_vertexInputInfo.pVertexBindingDescriptions = (VkVertexInputBindingDescription*)m_vertexBindings.data();
|
||||
m_vertexInputInfo.vertexAttributeDescriptionCount = m_vertexAttributes.size();
|
||||
m_vertexInputInfo.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription*)m_vertexAttributes.data();
|
||||
|
||||
/* Multisampling disabled. Use TTA */
|
||||
VkPipelineMultisampleStateCreateInfo multisampling = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.sampleShadingEnable = VK_FALSE,
|
||||
.minSampleShading = 1.0f,
|
||||
.pSampleMask = nullptr,
|
||||
.alphaToCoverageEnable = VK_FALSE,
|
||||
.alphaToOneEnable = VK_FALSE,
|
||||
};
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.viewportCount = 1,
|
||||
.pViewports = &m_viewport,
|
||||
.scissorCount = 1,
|
||||
.pScissors = &m_scissor
|
||||
};
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo colorBlending = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.logicOpEnable = VK_FALSE,
|
||||
.logicOp = VK_LOGIC_OP_COPY,
|
||||
.attachmentCount = (unsigned)m_blendingInfo.size(),
|
||||
.pAttachments = m_blendingInfo.data(),
|
||||
.blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f}
|
||||
};
|
||||
|
||||
std::vector<VkDynamicState> dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
||||
|
||||
VkPipelineDynamicStateCreateInfo dynamicState = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.dynamicStateCount = (uint32_t)dynamicStates.size(),
|
||||
.pDynamicStates = dynamicStates.data()
|
||||
};
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.stageCount = (uint32_t)stages.size(),
|
||||
.pStages = stages.data(),
|
||||
.pVertexInputState = &m_vertexInputInfo,
|
||||
.pInputAssemblyState = &m_inputAssemblyInfo,
|
||||
.pViewportState = &viewportState,
|
||||
.pRasterizationState = &m_rasterInfo,
|
||||
.pMultisampleState = &multisampling,
|
||||
.pDepthStencilState = &m_depthStencilInfo,
|
||||
.pColorBlendState = &colorBlending,
|
||||
.pDynamicState = &dynamicState,
|
||||
.layout = m_layout,
|
||||
.renderPass = m_renderpass,
|
||||
.subpass = 0,
|
||||
.basePipelineHandle = VK_NULL_HANDLE,
|
||||
.basePipelineIndex = -1,
|
||||
};
|
||||
|
||||
VkPipeline pipeline;
|
||||
if(vkCreateGraphicsPipelines(m_gpu->dev(), VK_NULL_HANDLE, 1,
|
||||
&pipelineInfo, nullptr, &pipeline)) {
|
||||
throw std::runtime_error("Failed to create graphics pipeline");
|
||||
}
|
||||
|
||||
return Pipeline(m_layout, pipeline);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// Created by martin on 10/24/23.
|
||||
//
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "shaders/SpirvShaderBuilder.hpp"
|
||||
#include "io/file.hpp"
|
||||
|
||||
SpirvShaderBuilder::SpirvShaderBuilder(const Gpu* gpu) :
|
||||
m_gpu(gpu) {
|
||||
|
||||
}
|
||||
|
||||
Shader SpirvShaderBuilder::from_binary(const std::vector<uint32_t>& code) const {
|
||||
VkShaderModuleCreateInfo moduleInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = code.size(),
|
||||
.pCode = code.data(),
|
||||
};
|
||||
|
||||
VkShaderModule module = VK_NULL_HANDLE;
|
||||
if(vkCreateShaderModule(m_gpu->dev(), &moduleInfo, nullptr, &module)) {
|
||||
throw std::runtime_error(std::format("Failed to create shader module from binary. Length was {}", code.size() * sizeof(uint32_t)));
|
||||
}
|
||||
|
||||
return Shader(module);
|
||||
}
|
||||
|
||||
Shader SpirvShaderBuilder::from_file(std::string path) {
|
||||
auto shaderBinary = io::file::read_binary(path);
|
||||
|
||||
VkShaderModuleCreateInfo moduleInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = shaderBinary.code_size(),
|
||||
.pCode = shaderBinary.data().data(),
|
||||
};
|
||||
|
||||
VkShaderModule module = VK_NULL_HANDLE;
|
||||
if(vkCreateShaderModule(m_gpu->dev(), &moduleInfo, nullptr, &module)) {
|
||||
throw std::runtime_error("Failed to create shader module");
|
||||
}
|
||||
|
||||
auto shader = Shader(module);
|
||||
shader.set_name(m_gpu, path);
|
||||
|
||||
return shader;
|
||||
}
|
||||
Reference in New Issue
Block a user