From 356e6058fe3edd1b577386f17c2b7ce14c3b4839 Mon Sep 17 00:00:00 2001 From: Dynamitos Date: Tue, 2 Jun 2020 11:46:18 +0200 Subject: [PATCH] Redo of render paths --- .gitmodules | 6 + .vscode/launch.json | 4 +- .vscode/settings.json | 76 ++- CMakeLists.txt | 71 ++- CMakeSettings.json | 9 +- README.md | 3 +- cmake-variants.json | 20 + cmake/FindAssimp.cmake | 95 ++++ cmake/FindGLFW.cmake | 112 ++++ cmake/FindJSON.cmake | 41 ++ cmake/SuperBuild.cmake | 66 ++- external/assimp | 1 + external/stb | 1 + res/shaders/ComputeFrustums.slang | 59 +++ res/shaders/DepthPrepass.slang | 33 ++ res/shaders/FluidForward.slang | 39 ++ res/shaders/Forward.slang | 80 +++ res/shaders/ForwardPlus.slang | 92 ++++ res/shaders/LightCulling.slang | 149 ++++++ res/shaders/Placeholder.semat | 75 +++ res/shaders/lib/BRDF.slang | 152 ++++++ res/shaders/lib/Common.slang | 62 +++ res/shaders/lib/FlatColorMaterial.slang | 27 + res/shaders/lib/InputGeometry.slang | 70 +++ res/shaders/lib/LightEnv.slang | 70 +++ res/shaders/lib/Material.slang | 9 + res/shaders/lib/ParallaxMaterial.slang | 21 + res/shaders/lib/ParticlesCommon.slang | 12 + res/shaders/lib/TexturedMaterial.slang | 42 ++ res/shaders/shaders.slang | 485 ++++++++++++++++++ res/textures/placeholder.png | Bin 0 -> 1619 bytes src/Engine/Asset/Asset.cpp | 56 ++ src/Engine/Asset/Asset.h | 39 +- src/Engine/Asset/AssetRegistry.cpp | 89 ++++ src/Engine/Asset/AssetRegistry.h | 47 ++ src/Engine/Asset/CMakeLists.txt | 14 +- src/Engine/Asset/FileAsset.cpp | 62 --- src/Engine/Asset/FileAsset.h | 24 - src/Engine/Asset/MaterialLoader.cpp | 22 + src/Engine/Asset/MaterialLoader.h | 22 + src/Engine/Asset/MeshAsset.cpp | 17 + src/Engine/Asset/MeshAsset.h | 22 + src/Engine/Asset/MeshLoader.cpp | 61 +++ src/Engine/Asset/MeshLoader.h | 23 + src/Engine/Asset/TextureAsset.cpp | 17 + src/Engine/Asset/TextureAsset.h | 25 + src/Engine/Asset/TextureLoader.cpp | 61 +++ src/Engine/Asset/TextureLoader.h | 24 + src/Engine/CMakeLists.txt | 2 +- src/Engine/Containers/Array.h | 5 + src/Engine/Containers/List.h | 18 + src/Engine/Containers/Map.h | 1 + src/Engine/Graphics/CMakeLists.txt | 4 +- src/Engine/Graphics/ForwardPlusRenderPath.cpp | 43 -- src/Engine/Graphics/ForwardPlusRenderPath.h | 17 - src/Engine/Graphics/Graphics.h | 16 + src/Engine/Graphics/GraphicsInitializer.h | 60 ++- src/Engine/Graphics/GraphicsResources.cpp | 85 ++- src/Engine/Graphics/GraphicsResources.h | 159 ++++-- src/Engine/Graphics/Mesh.cpp | 12 + src/Engine/Graphics/Mesh.h | 5 +- src/Engine/Graphics/MeshBatch.h | 97 ++++ src/Engine/Graphics/RenderPass/BasePass.cpp | 0 src/Engine/Graphics/RenderPass/BasePass.h | 15 + src/Engine/Graphics/RenderPass/CMakeLists.txt | 10 + .../Graphics/RenderPass/DepthPrepass.cpp | 0 src/Engine/Graphics/RenderPass/DepthPrepass.h | 0 .../Graphics/RenderPass/MeshProcessor.cpp | 54 ++ .../Graphics/RenderPass/MeshProcessor.h | 32 ++ .../Graphics/RenderPass/VertexFactory.cpp | 28 + .../Graphics/RenderPass/VertexFactory.h | 92 ++++ src/Engine/Graphics/RenderPath.h | 1 + src/Engine/Graphics/SceneRenderPath.cpp | 33 +- src/Engine/Graphics/SceneRenderPath.h | 8 +- src/Engine/Graphics/SceneView.cpp | 4 +- .../Graphics/Vulkan/VulkanAllocator.cpp | 36 +- src/Engine/Graphics/Vulkan/VulkanAllocator.h | 3 + src/Engine/Graphics/Vulkan/VulkanBuffer.cpp | 77 ++- .../Graphics/Vulkan/VulkanCommandBuffer.cpp | 5 +- .../Graphics/Vulkan/VulkanCommandBuffer.h | 2 +- .../Graphics/Vulkan/VulkanDescriptorSets.cpp | 7 + .../Graphics/Vulkan/VulkanDescriptorSets.h | 1 + src/Engine/Graphics/Vulkan/VulkanGraphics.cpp | 63 ++- src/Engine/Graphics/Vulkan/VulkanGraphics.h | 14 +- .../Vulkan/VulkanGraphicsResources.cpp | 41 -- .../Graphics/Vulkan/VulkanGraphicsResources.h | 94 ++-- src/Engine/Graphics/Vulkan/VulkanPipeline.cpp | 5 +- src/Engine/Graphics/Vulkan/VulkanPipeline.h | 1 - .../Graphics/Vulkan/VulkanPipelineCache.cpp | 40 +- src/Engine/Graphics/Vulkan/VulkanShader.cpp | 100 +++- src/Engine/Graphics/Vulkan/VulkanShader.h | 14 +- src/Engine/Graphics/Vulkan/VulkanTexture.cpp | 108 +++- src/Engine/Graphics/Vulkan/VulkanViewport.cpp | 10 +- src/Engine/Graphics/WindowManager.cpp | 2 + src/Engine/Graphics/WindowManager.h | 4 +- src/Engine/Material/CMakeLists.txt | 5 +- src/Engine/Material/Material.cpp | 75 ++- src/Engine/Material/Material.h | 36 +- src/Engine/Material/MaterialAsset.cpp | 21 + src/Engine/Material/MaterialAsset.h | 19 + src/Engine/Material/MaterialInstance.cpp | 4 +- src/Engine/Material/MaterialInstance.h | 4 +- src/Engine/Material/ShaderExpression.h | 79 +++ src/Engine/Math/CMakeLists.txt | 1 + src/Engine/Math/Math.h | 1 + src/Engine/Math/Transform.cpp | 5 +- src/Engine/Math/Transform.h | 2 +- src/Engine/Math/Vector.cpp | 17 + src/Engine/Math/Vector.h | 2 + src/Engine/MinimalEngine.h | 36 +- src/Engine/Scene/Components/CMakeLists.txt | 3 +- .../Scene/Components/PrimitiveComponent.h | 9 +- .../Components/PrimitiveUniformBufferLayout.h | 12 + src/Engine/Scene/Scene.cpp | 13 +- src/Engine/Scene/Scene.h | 8 +- src/Engine/main.cpp | 3 + test.mat | 3 - test/CMakeLists.txt | 17 +- test/Engine/CMakeLists.txt | 3 +- test/Engine/Math/CMakeLists.txt | 4 + test/Engine/Math/Vector.cpp | 45 ++ 121 files changed, 3890 insertions(+), 572 deletions(-) create mode 100644 cmake/FindAssimp.cmake create mode 100644 cmake/FindGLFW.cmake create mode 100644 cmake/FindJSON.cmake create mode 160000 external/assimp create mode 160000 external/stb create mode 100644 res/shaders/ComputeFrustums.slang create mode 100644 res/shaders/DepthPrepass.slang create mode 100644 res/shaders/FluidForward.slang create mode 100644 res/shaders/Forward.slang create mode 100644 res/shaders/ForwardPlus.slang create mode 100644 res/shaders/LightCulling.slang create mode 100644 res/shaders/Placeholder.semat create mode 100644 res/shaders/lib/BRDF.slang create mode 100644 res/shaders/lib/Common.slang create mode 100644 res/shaders/lib/FlatColorMaterial.slang create mode 100644 res/shaders/lib/InputGeometry.slang create mode 100644 res/shaders/lib/LightEnv.slang create mode 100644 res/shaders/lib/Material.slang create mode 100644 res/shaders/lib/ParallaxMaterial.slang create mode 100644 res/shaders/lib/ParticlesCommon.slang create mode 100644 res/shaders/lib/TexturedMaterial.slang create mode 100644 res/shaders/shaders.slang create mode 100644 res/textures/placeholder.png create mode 100644 src/Engine/Asset/AssetRegistry.cpp create mode 100644 src/Engine/Asset/AssetRegistry.h delete mode 100644 src/Engine/Asset/FileAsset.cpp delete mode 100644 src/Engine/Asset/FileAsset.h create mode 100644 src/Engine/Asset/MaterialLoader.cpp create mode 100644 src/Engine/Asset/MaterialLoader.h create mode 100644 src/Engine/Asset/MeshAsset.cpp create mode 100644 src/Engine/Asset/MeshAsset.h create mode 100644 src/Engine/Asset/MeshLoader.cpp create mode 100644 src/Engine/Asset/MeshLoader.h create mode 100644 src/Engine/Asset/TextureAsset.cpp create mode 100644 src/Engine/Asset/TextureAsset.h create mode 100644 src/Engine/Asset/TextureLoader.cpp create mode 100644 src/Engine/Asset/TextureLoader.h delete mode 100644 src/Engine/Graphics/ForwardPlusRenderPath.cpp delete mode 100644 src/Engine/Graphics/ForwardPlusRenderPath.h create mode 100644 src/Engine/Graphics/MeshBatch.h create mode 100644 src/Engine/Graphics/RenderPass/BasePass.cpp create mode 100644 src/Engine/Graphics/RenderPass/BasePass.h create mode 100644 src/Engine/Graphics/RenderPass/CMakeLists.txt create mode 100644 src/Engine/Graphics/RenderPass/DepthPrepass.cpp create mode 100644 src/Engine/Graphics/RenderPass/DepthPrepass.h create mode 100644 src/Engine/Graphics/RenderPass/MeshProcessor.cpp create mode 100644 src/Engine/Graphics/RenderPass/MeshProcessor.h create mode 100644 src/Engine/Graphics/RenderPass/VertexFactory.cpp create mode 100644 src/Engine/Graphics/RenderPass/VertexFactory.h create mode 100644 src/Engine/Material/MaterialAsset.cpp create mode 100644 src/Engine/Material/MaterialAsset.h create mode 100644 src/Engine/Material/ShaderExpression.h create mode 100644 src/Engine/Math/Vector.cpp create mode 100644 src/Engine/Scene/Components/PrimitiveUniformBufferLayout.h delete mode 100644 test.mat create mode 100644 test/Engine/Math/CMakeLists.txt create mode 100644 test/Engine/Math/Vector.cpp diff --git a/.gitmodules b/.gitmodules index c9c9f25..47e3454 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,9 @@ [submodule "external/json"] path = external/json url = https://github.com/nlohmann/json.git +[submodule "external/assimp"] + path = external/assimp + url = https://github.com/assimp/assimp.git +[submodule "external/stb"] + path = external/stb + url = https://github.com/nothings/stb.git diff --git a/.vscode/launch.json b/.vscode/launch.json index fc3ad8b..fa21275 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -27,10 +27,10 @@ "name": "Test", "type": "cppvsdbg", "request": "launch", - "program": "${workspaceRoot}/bin/Debug/test/Seele_unit_tests.exe", + "program": "${workspaceRoot}/bin/Debug/Seele_unit_tests.exe", "args": [], "stopAtEntry": false, - "cwd": "${workspaceRoot}/bin/Debug/test", + "cwd": "${workspaceRoot}/bin/Debug", "environment": [], "externalConsole": false }, diff --git a/.vscode/settings.json b/.vscode/settings.json index 23a7428..4284d51 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,4 @@ { - "C_Cpp.default.configurationProvider": "go2sh.cmake-integration", "telemetry.enableTelemetry": false, "cmake.buildDirectory": "${workspaceFolder}/bin/${buildType}", "git.autofetch": false, @@ -17,9 +16,82 @@ "memory": "cpp", "*.ipp": "cpp", "iostream": "cpp", - "initializer_list": "cpp" + "initializer_list": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "exception": "cpp", + "forward_list": "cpp", + "fstream": "cpp", + "functional": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "map": "cpp", + "mutex": "cpp", + "new": "cpp", + "numeric": "cpp", + "ostream": "cpp", + "ratio": "cpp", + "set": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "system_error": "cpp", + "thread": "cpp", + "tuple": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "utility": "cpp", + "valarray": "cpp", + "xfacet": "cpp", + "xlocale": "cpp", + "xlocinfo": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xstddef": "cpp", + "xtr1common": "cpp", + "xutility": "cpp", + "filesystem": "cpp", + "bitset": "cpp", + "complex": "cpp", + "csignal": "cpp", + "deque": "cpp", + "locale": "cpp", + "optional": "cpp", + "typeindex": "cpp", + "variant": "cpp", + "xlocbuf": "cpp", + "xlocmes": "cpp", + "codecvt": "cpp", + "regex": "cpp", + "strstream": "cpp", + "resumable": "cpp", + "future": "cpp" }, "C_Cpp.default.browse.limitSymbolsToIncludedHeaders": false, "C_Cpp.default.intelliSenseMode": "msvc-x64", "C_Cpp.errorSquiggles": "Disabled", + "cmake.generator": "Visual Studio 16 2019", + "cmake.skipConfigureIfCachePresent": false, + "cmake.configureArgs": ["-Wno-dev"], + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools" } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cba8ca..5d24e25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,30 +1,25 @@ cmake_minimum_required(VERSION 3.15) -set(CMAKE_CXX_STANDARD_REQUIRED 20) +set(CMAKE_CXX_STANDARD 17) # Handle superbuild first option (USE_SUPERBUILD "Whether or not a superbuild should be invoked" ON) set(ENGINE_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/src/Engine) set(EXTERNAL_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/external) -set(SLANG_ROOT ${EXTERNAL_ROOT}/slang) +set(ASSIMP_ROOT ${EXTERNAL_ROOT}/assimp) set(BOOST_ROOT ${EXTERNAL_ROOT}/boost) +set(SLANG_ROOT ${EXTERNAL_ROOT}/slang) set(GLM_ROOT ${EXTERNAL_ROOT}/glm) set(GLFW_ROOT ${EXTERNAL_ROOT}/glfw) set(JSON_ROOT ${EXTERNAL_ROOT}/json) -set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}) -set(RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}) +set(STB_ROOT ${EXTERNAL_ROOT}/stb) + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/) set(Boost_USE_STATIC_LIBS ON) set(Boost_LIB_PREFIX lib) -set(ENKITS_BUILD_EXAMPLES OFF CACHE BOOL "Build basic example applications" ) -set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "GLFW lib only" ) -set(GLFW_BUILD_TESTS OFF CACHE BOOL "GLFW lib only" ) -set(GLFW_BUILD_DOCS OFF CACHE BOOL "GLFW lib only" ) -set(GLFW_BUILD_INSTALL OFF CACHE BOOL "GLFW lib only" ) - if (USE_SUPERBUILD) project (SUPERBUILD NONE) # execute the superbuild (this script will be invoked again without the @@ -35,17 +30,27 @@ else() project (Seele) endif() +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin/Debug) +#Workaround for vs, because it places artifacts into an additional subfolder +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/bin/Debug) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/bin/Release) + find_package(Vulkan REQUIRED) find_package(Boost REQUIRED COMPONENTS serialization) -find_package(Threads) -include(${JSON_IMPORT}) -include(${GLFW_IMPORT}) +find_package(Threads REQUIRED) +find_package(assimp REQUIRED ${ASSIMP_ROOT}) +find_package(JSON REQUIRED) +find_package(GLFW REQUIRED) -include_directories(${GLFW_ROOT}/include) include_directories(${GLM_INCLUDE_DIRS}) +include_directories(${STB_INCLUDE_DIRS}) include_directories(${Vulkan_INCLUDE_DIR}) include_directories(${Boost_INCLUDE_DIRS}) +include_directories(${GLFW_INCLUDE_DIRS}) include_directories(${SLANG_INCLUDE_DIRS}) +include_directories(${ASSIMP_INCLUDE_DIRS}) +include_directories(${JSON_INCLUDE_DIRS}) +include_directories(${ENGINE_ROOT}) include_directories(src/Engine) add_definitions(${GLM_DEFINITIONS}) add_definitions(${Vulkan_DEFINITIONS}) @@ -55,20 +60,44 @@ if(WIN32) add_compile_definitions(USE_EXTENSIONS) endif() add_executable(SeeleEngine "") -target_link_libraries(SeeleEngine glfw) -target_link_libraries(SeeleEngine nlohmann_json::nlohmann_json) -target_link_libraries(SeeleEngine ${Boost_LIBRARIES}) target_link_libraries(SeeleEngine ${Vulkan_LIBRARY}) +target_link_libraries(SeeleEngine ${Boost_LIBRARIES}) +target_link_libraries(SeeleEngine ${GLFW_LIBRARIES}) target_link_libraries(SeeleEngine ${SLANG_LIBRARY}) +target_link_libraries(SeeleEngine ${ASSIMP_LIBRARIES}) +target_link_libraries(SeeleEngine ${JSON_LIBRARY}) + +target_precompile_headers(SeeleEngine + PRIVATE + + + + + + + + + + + + ) + add_subdirectory(src/) if(MSVC) - target_compile_options(SeeleEngine PRIVATE /DEBUG:FASTLINK /Zi /W4) + set(_CRT_SECURE_NO_WARNINGS) + target_compile_options(SeeleEngine PRIVATE /DEBUG:FASTLINK /Zi) else() target_compile_options(SeeleEngine PRIVATE -Wall -Wextra -pedantic) endif() +add_executable(Seele_unit_tests "") add_subdirectory(test/) -add_custom_command(TARGET SeeleEngine POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DEPENDENT_BINARIES} $) - +add_custom_target(copy-runtime-files ALL + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/res $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SLANG_ROOT}/${SLANG_BINARY} $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SLANG_ROOT}/${SLANG_GLSLANG} $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GLFW_BINARY} $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ASSIMP_BINARY} $ + DEPENDS SeeleEngine) \ No newline at end of file diff --git a/CMakeSettings.json b/CMakeSettings.json index 00a8e6e..85715ee 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -2,13 +2,8 @@ "configurations": [ { "name": "Debug", - "generator": "Ninja", - "configurationType": "Debug", - "inheritEnvironments": [ "msvc_x64_x64" ], - "buildRoot": "${projectDir}\\bin\\${name}", - "installRoot": "${projectDir}\\install\\${name}", - "cmakeCommandArgs": "-DUSE_SUPERBUILD=TRUE", - "buildCommandArgs": "-v", + "cmakeCommandArgs": "-DUSE_SUPERBUILD=OFF", + "buildCommandArgs": "", "ctestCommandArgs": "", "variables": [] } diff --git a/README.md b/README.md index 6136a83..c98123b 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,7 @@ but keeping it simple to use, with lots of additional and optional parameters. The project is built using standard CMake 3.15, so that and a modern C++17 compiler should be the only prerequisites. Clone the repository and initialize the dependencies with `git submodule update --init --recursive` - -*SLang library hasn't been included in the automatic build yet, so you have to manually compile that project, found in external/slang* +~~*SLang library hasn't been included in the automatic build yet, so you have to manually compile that project, found in external/slang*~~ This has been fixed, but not extensively tested ## Linux notes: diff --git a/cmake-variants.json b/cmake-variants.json index 2abdaa6..0b3c911 100644 --- a/cmake-variants.json +++ b/cmake-variants.json @@ -34,5 +34,25 @@ } } } + }, + "superbuild": { + "default": "off", + "description": "Use Superbuild", + "choices": { + "off": { + "short": "off", + "long": "Don't rebuild superbuild", + "settings": { + "USE_SUPERBUILD": "OFF" + } + }, + "on": { + "short": "on", + "long": "Rebuild dependencies", + "settings": { + "USE_SUPERBUILD": "ON" + } + } + } } } \ No newline at end of file diff --git a/cmake/FindAssimp.cmake b/cmake/FindAssimp.cmake new file mode 100644 index 0000000..4639ce1 --- /dev/null +++ b/cmake/FindAssimp.cmake @@ -0,0 +1,95 @@ +# +# Find Assimp +# +# Try to find Assimp : Open Asset Import Library. +# This module defines the following variables: +# - ASSIMP_INCLUDE_DIRS +# - ASSIMP_LIBRARIES +# - ASSIMP_FOUND +# +# The following variables can be set as arguments for the module. +# - ASSIMP_ROOT : Root library directory of Assimp +# + +# Additional modules +include(FindPackageHandleStandardArgs) + +if (WIN32) + # Find include files + find_path( + ASSIMP_INCLUDE_DIR + NAMES assimp/scene.h + PATHS + $ENV{PROGRAMFILES}/include + ${ASSIMP_ROOT}/include + DOC "The directory where assimp/scene.h resides") + + # Find library files + find_library( + ASSIMP_LIBRARY + NAMES assimp${LIBRARY_SUFFIX}.lib + PATHS + $ENV{PROGRAMFILES}/lib + ${ASSIMP_ROOT}/lib/ + PATH_SUFFIXES Debug Release) + + find_file( + ASSIMP_BINARY + NAMES assimp${LIBRARY_SUFFIX}.dll + PATHS + $ENV{PROGRAMFILES}/bin + ${ASSIMP_ROOT}/bin/ + PATH_SUFFIXES Debug Release) +else() + # Find include files + find_path( + ASSIMP_INCLUDE_DIR + NAMES assimp/scene.h + PATHS + /usr/include + /usr/local/include + /sw/include + /opt/local/include + DOC "The directory where assimp/scene.h resides") + + # Find library files + find_library( + ASSIMP_LIBRARY + NAMES assimp + PATHS + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + /sw/lib + /opt/local/lib + ${ASSIMP_ROOT}/lib + DOC "The Assimp library") + + find_file( + ASSIMP_BINARY + NAMES assimp.so + PATHS + /usr/bin64 + /usr/bin + /usr/local/bin64 + /usr/local/bin + /sw/bin + /opt/local/bin + ${ASSIMP_ROOT}/lib + DOC "The Assimp binary") +endif() + +# Handle REQUIRD argument, define *_FOUND variable +find_package_handle_standard_args(assimp DEFAULT_MSG ASSIMP_INCLUDE_DIR ASSIMP_LIBRARY ASSIMP_BINARY) + +# Define GLFW_LIBRARIES and GLFW_INCLUDE_DIRS +if (ASSIMP_FOUND) + set(ASSIMP_LIBRARIES ${ASSIMP_LIBRARY}) + set(ASSIMP_INCLUDE_DIRS ${ASSIMP_INCLUDE_DIR}) +endif() + +message(STATUS BINARY: ${ASSIMP_BINARY}) + +# Hide some variables +mark_as_advanced(ASSIMP_INCLUDE_DIR ASSIMP_LIBRARY) \ No newline at end of file diff --git a/cmake/FindGLFW.cmake b/cmake/FindGLFW.cmake new file mode 100644 index 0000000..03d9242 --- /dev/null +++ b/cmake/FindGLFW.cmake @@ -0,0 +1,112 @@ +# +# Find GLFW +# +# Try to find GLFW library. +# This module defines the following variables: +# - GLFW_INCLUDE_DIRS +# - GLFW_LIBRARIES +# - GLFW_FOUND +# +# The following variables can be set as arguments for the module. +# - GLFW_ROOT : Root library directory of GLFW +# - GLFW_USE_STATIC_LIBS : Specifies to use static version of GLFW library (Windows only) +# +# References: +# - https://github.com/progschj/OpenGL-Examples/blob/master/cmake_modules/FindGLFW.cmake +# - https://bitbucket.org/Ident8/cegui-mk2-opengl3-renderer/src/befd47200265/cmake/FindGLFW.cmake +# + +# Additional modules +include(FindPackageHandleStandardArgs) + +if (WIN32) + # Find include files + find_path( + GLFW_INCLUDE_DIR + NAMES GLFW/glfw3.h + PATHS + $ENV{PROGRAMFILES}/include + ${GLFW_ROOT}/include + DOC "The directory where GLFW/glfw.h resides") + + # Use glfw3.lib for static library + if (GLFW_USE_STATIC_LIBS) + set(GLFW_LIBRARY_NAME glfw3) + else() + set(GLFW_LIBRARY_NAME glfw3dll) + endif() + + # Find library files + find_library( + GLFW_LIBRARY + NAMES ${GLFW_LIBRARY_NAME}.lib + PATHS + $ENV{PROGRAMFILES}/lib + ${GLFW_ROOT}/lib + ${GLFW_ROOT}/src + PATH_SUFFIXES Debug Release) + + message(STATUS cant find ${GLFW_LIBRARY_NAME} in ${GLFW_ROOT}/src) + + unset(GLFW_LIBRARY_NAME) + + find_file( + GLFW_BINARY + NAMES glfw3.dll + PATHS + $ENV{PROGRAMFILES}/bin + ${GLFW_ROOT}/src + ${GLFW_ROOT}/bin + PATH_SUFFIXES Debug Release) +else() + # Find include files + find_path( + GLFW_INCLUDE_DIR + NAMES GLFW/glfw.h + PATHS + /usr/include + /usr/local/include + /sw/include + /opt/local/include + DOC "The directory where GL/glfw.h resides") + + # Find library files + # Try to use static libraries + find_library( + GLFW_LIBRARY + NAMES glfw3 + PATHS + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + /sw/lib + /opt/local/lib + ${GLFW_ROOT}/lib + DOC "The GLFW library") + + find_file( + GLFW_BINARY + NAMES glfw3.so + PATHS + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + /sw/lib + /opt/local/lib + ${GLFW_ROOT}/lib + ) +endif() + +# Handle REQUIRD argument, define *_FOUND variable +find_package_handle_standard_args(GLFW DEFAULT_MSG GLFW_INCLUDE_DIR GLFW_LIBRARY GLFW_BINARY) + +# Define GLFW_LIBRARIES and GLFW_INCLUDE_DIRS +if (GLFW_FOUND) + set(GLFW_LIBRARIES ${OPENGL_LIBRARIES} ${GLFW_LIBRARY}) + set(GLFW_INCLUDE_DIRS ${GLFW_INCLUDE_DIR}) +endif() + +# Hide some variables +mark_as_advanced(GLFW_INCLUDE_DIR GLFW_LIBRARY) \ No newline at end of file diff --git a/cmake/FindJSON.cmake b/cmake/FindJSON.cmake new file mode 100644 index 0000000..4d39726 --- /dev/null +++ b/cmake/FindJSON.cmake @@ -0,0 +1,41 @@ +# +# Find nlohmann_json +# +# Try to find nlohmann_json library +# This module defines the following variables: +# - JSON_INCLUDE_DIRS +# - JSON_FOUND +# +# The following variables can be set as arguments for the module. +# - JSON_ROOT : Root library directory of json +# + +# Additional modules +include(FindPackageHandleStandardArgs) + +if(JSON_MultipleHeaders) + find_path( + JSON_INCLUDE_DIR + NAMES nlohmann/json.hpp + PATHS + $ENV{PROGRAMFILES}/include + ${JSON_ROOT}/single_include + DOC "The directory where nlohmann/json.hpp resides") +else() + find_path( + JSON_INCLUDE_DIR + NAMES nlohmann/json.hpp + PATHS + $ENV{PROGRAMFILES}/include + ${JSON_ROOT}/include + DOC "The directory where nlohmann/json.hpp resides") +endif() + +find_package_handle_standard_args(JSON DEFAULT_MSG JSON_INCLUDE_DIR) + +if(JSON_FOUND) + set(JSON_INCLUDE_DIRS ${JSON_INCLUDE_DIR}) +endif() + +# Hide some variables +mark_as_advanced(JSON_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index 8faf438..2a90fd9 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -1,12 +1,19 @@ include (ExternalProject) -set_property(DIRECTORY PROPERTY EP_BASE external) - set(DEPENDENCIES) set(EXTRA_CMAKE_ARGS) -set(DEPENDENT_BINARIES "") execute_process(COMMAND git submodule update --init --recursive -- ${CMAKE_SOURCE_DIR}) +#------------ASSIMP--------------- +list(APPEND DEPENDENCIES assimp) +set(ASSIMP_BUILD_TESTS OFF CACHE INTERNAL "") +set(ASSIMP_BUILD_ASSIMP_TOOLS OFF CACHE INTERNAL "") +set(ASSIMP_INSTALL OFF CACHE INTERNAL "") +set(ASSIMP_INJECT_DEBUG_POSTFIX OFF CACHE INTERNAL "") + +add_subdirectory(${ASSIMP_ROOT} ${ASSIMP_ROOT}) +target_compile_definitions(assimp PRIVATE _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING) + #-------------BOOST---------------- list(APPEND DEPENDENCIES boost) if(WIN32) @@ -38,48 +45,41 @@ list(APPEND EXTRA_CMAKE_ARGS ) #--------------------JSON------------------ -#list(APPEND DEPENDENCIES nlohmann_json) +list(APPEND DEPENDENCIES nlohmann_json) set(JSON_MultipleHeaders ON CACHE INTERNAL "") set(JSON_BuildTests OFF CACHE INTERNAL "") set(JSON_Install OFF CACHE INTERNAL "") add_subdirectory(${JSON_ROOT}) -export(TARGETS nlohmann_json - NAMESPACE nlohmann_json:: - FILE ${nlohmann_json_BINARY_DIR}/json_target.cmake) - -list(APPEND EXTRA_CMAKE_ARGS - -DJSON_IMPORT=${nlohmann_json_BINARY_DIR}/json_target.cmake - ) - #--------------GLFW------------------------------ list(APPEND DEPENDENCIES glfw) -set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) -set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) -set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +set(ENKITS_BUILD_EXAMPLES OFF CACHE BOOL "Build basic example applications" ) +set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "GLFW lib only" ) +set(GLFW_BUILD_TESTS OFF CACHE BOOL "GLFW lib only" ) +set(GLFW_BUILD_DOCS OFF CACHE BOOL "GLFW lib only" ) +set(GLFW_BUILD_INSTALL OFF CACHE BOOL "GLFW lib only" ) -add_subdirectory(${GLFW_ROOT}) -export(TARGETS glfw - FILE ${GLFW_BINARY_DIR}/glfw.cmake) +add_subdirectory(${GLFW_ROOT} ${GLFW_ROOT}) +#---------------STB_IMAGE------------------------ list(APPEND EXTRA_CMAKE_ARGS - -DGLFW_IMPORT=${GLFW_BINARY_DIR}/glfw.cmake - ) + -DSTB_INCLUDE_DIRS=${STB_ROOT}) #--------------SLang------------------------------ list(APPEND DEPENDENCIES slang) -string(TOLOWER ${CMAKE_BUILD_TYPE}_${CMAKE_PLATFORM} SLANG_CONFIG) +string(TOLOWER release_${CMAKE_PLATFORM} SLANG_CONFIG) if(WIN32) ExternalProject_Add(slang SOURCE_DIR ${SLANG_ROOT} BINARY_DIR ${CMAKE_BINARY_DIR}/lib CONFIGURE_COMMAND devenv /upgrade ${SLANG_ROOT}/source/slang/slang.vcxproj - BUILD_COMMAND msbuild -p:Configuration=${CMAKE_BUILD_TYPE} -p:Platform=${CMAKE_PLATFORM} -p:WindowsTargetPlatformVersion=10.0 ${SLANG_ROOT}/source/slang/slang.vcxproj + BUILD_COMMAND msbuild -p:Configuration=Release -p:Platform=${CMAKE_PLATFORM} -p:WindowsTargetPlatformVersion=10.0 ${SLANG_ROOT}/source/slang/slang.vcxproj INSTALL_COMMAND "") - string(TOLOWER bin/windows-${CMAKE_PLATFORM}/${CMAKE_BUILD_TYPE}/slang.dll SLANG_BINARY) - string(TOLOWER bin/windows-${CMAKE_PLATFORM}/${CMAKE_BUILD_TYPE}/slang.lib SLANG_LIB_PATH) + string(TOLOWER bin/windows-${CMAKE_PLATFORM}/Release/slang.dll SLANG_BINARY) + string(TOLOWER bin/windows-${CMAKE_PLATFORM}/Release/slang-glslang.dll SLANG_GLSLANG) + string(TOLOWER bin/windows-${CMAKE_PLATFORM}/Release/slang.lib SLANG_LIB_PATH) set(SLANG_LIB_PATH ${SLANG_ROOT}/${SLANG_LIB_PATH}) elseif(UNIX) ExternalProject_Add(slang @@ -89,24 +89,22 @@ ExternalProject_Add(slang BUILD_COMMAND make -C ${CMAKE_SOURCE_DIR}/external/slang/build.linux config=${SLANG_CONFIG} INSTALL_COMMAND "") - string(TOLOWER bin/linux-${CMAKE_PLATFORM}/${CMAKE_BUILD_TYPE}/libslang.so SLANG_BINARY) + string(TOLOWER bin/linux-${CMAKE_PLATFORM}/Release/libslang.so SLANG_BINARY) + string(TOLOWER bin/linux-${CMAKE_PLATFORM}/Release/libslang-glslang.so SLANG_GLSLANG) set(SLANG_LIB_PATH) endif() - - list(APPEND EXTRA_CMAKE_ARGS -DSLANG_INCLUDE_DIRS=${EXTERNAL_ROOT}/slang - -DSLANG_LIBRARY=${SLANG_LIB_PATH}) - -list(APPEND DEPENDENT_BINARIES ${SLANG_ROOT}/${SLANG_BINARY}) + -DSLANG_LIBRARY=${SLANG_LIB_PATH} + -DSLANG_BINARY=${SLANG_BINARY} + -DSLANG_GLSLANG=${SLANG_GLSLANG}) -list(APPEND EXTRA_CMAKE_ARGS - -DDEPENDENT_BINARIES=${DEPENDENT_BINARIES}) #-----------------SeeleEngine-------------------- ExternalProject_Add(SeeleEngine DEPENDS ${DEPENDENCIES} SOURCE_DIR ${PROJECT_SOURCE_DIR} + PREFIX ${CMAKE_BINARY_DIR} + BINARY_DIR ${CMAKE_BINARY_DIR} CMAKE_ARGS -DUSE_SUPERBUILD=OFF ${EXTRA_CMAKE_ARGS} - INSTALL_COMMAND "" - BINARY_DIR ${CMAKE_BINARY_DIR}) + INSTALL_COMMAND "") diff --git a/external/assimp b/external/assimp new file mode 160000 index 0000000..110f884 --- /dev/null +++ b/external/assimp @@ -0,0 +1 @@ +Subproject commit 110f8845a2aa72f0712269dfbeeee91d4849590c diff --git a/external/stb b/external/stb new file mode 160000 index 0000000..f54acd4 --- /dev/null +++ b/external/stb @@ -0,0 +1 @@ +Subproject commit f54acd4e13430c5122cab4ca657705c84aa61b08 diff --git a/res/shaders/ComputeFrustums.slang b/res/shaders/ComputeFrustums.slang new file mode 100644 index 0000000..9dd8b45 --- /dev/null +++ b/res/shaders/ComputeFrustums.slang @@ -0,0 +1,59 @@ + +import LightEnv; +import Common; + +struct ComputeShaderInput +{ + uint3 groupID : SV_GroupID; + uint3 groupThreadID : SV_GroupThreadID; + uint3 dispatchThreadID : SV_DispatchThreadID; + uint groupIndex : SV_GroupIndex; +}; + +layout(set = 0, binding = 0) +cbuffer DispatchParams +{ + uint3 numThreadGroups; + uint pad0; + uint3 numThreads; + uint pad1; +} +layout(set = 0, binding = 2) +RWStructuredBuffer out_Frustums; + + +[numthreads(BLOCK_SIZE, BLOCK_SIZE, 1)] +[shader("compute")] +void computeFrustums(ComputeShaderInput in) +{ + const float3 eyePos = float3(0,0,0); + + float4 screenSpace[4]; + + screenSpace[0] = float4(in.dispatchThreadID.xy * BLOCK_SIZE, 1.0f, 1.0f); + screenSpace[1] = float4(float2(in.dispatchThreadID.x + 1, in.dispatchThreadID.y) * BLOCK_SIZE, 1.0f, 1.0f); + screenSpace[2] = float4(float2(in.dispatchThreadID.x, in.dispatchThreadID.y + 1) * BLOCK_SIZE, 1.0f, 1.0f); + screenSpace[3] = float4(float2(in.dispatchThreadID.x + 1, in.dispatchThreadID.y + 1) * BLOCK_SIZE, 1.0f, 1.0f); + + //Convert to viewSpace + float3 viewSpace[4]; + + for(int i = 0; i < 4; i++) + { + viewSpace[i] = screenToView(screenSpace[i]).xyz; + } + + //Compute frustum + Frustum frustum; + + frustum.planes[0] = computePlane(eyePos, viewSpace[0], viewSpace[2]); + frustum.planes[1] = computePlane(eyePos, viewSpace[3], viewSpace[1]); + frustum.planes[2] = computePlane(eyePos, viewSpace[1], viewSpace[0]); + frustum.planes[3] = computePlane(eyePos, viewSpace[2], viewSpace[3]); + + if(in.dispatchThreadID.x < numThreads.x && in.dispatchThreadID.y < numThreads.y) + { + uint index = in.dispatchThreadID.x + (in.dispatchThreadID.y * numThreads.x); + out_Frustums[index] = frustum; + } +} diff --git a/res/shaders/DepthPrepass.slang b/res/shaders/DepthPrepass.slang new file mode 100644 index 0000000..cf7f6f1 --- /dev/null +++ b/res/shaders/DepthPrepass.slang @@ -0,0 +1,33 @@ +import InputGeometry; + +struct ViewParams +{ + float4x4 viewMatrix; + float4x4 projectionMatrix; + float4 cameraPos_WS; +}; + +layout(set = 0, binding = 0) +ParameterBlock gViewParams; + +struct ModelParameter +{ + float4x4 modelMatrix; +} + +[[vk::push_constant]] +ConstantBuffer gModelParams; + +struct VertexShaderOutput +{ + float4 out_Position : SV_Position; +} +[shader("vertex")] +VertexShaderOutput depthPrepass(PositionOnlyVertexInput input) +{ + VertexShaderOutput out; + float4 worldPos = mul(gModelParams.modelMatrix, float4(input.getVertexPosition(), 1)); + float4 viewPos = mul(gViewParams.viewMatrix, worldPos); + out.out_Position = mul(gViewParams.projectionMatrix, viewPos); + return out; +} \ No newline at end of file diff --git a/res/shaders/FluidForward.slang b/res/shaders/FluidForward.slang new file mode 100644 index 0000000..c7d083f --- /dev/null +++ b/res/shaders/FluidForward.slang @@ -0,0 +1,39 @@ +import LightEnv; + +struct VertexInput +{ + float3 basePosition; + float3 position; + float3 velocity; +} + +struct ViewParameter +{ + float4 cameraPos_WS; + float4x4 viewMatrix; + float4x4 projectionMatrix; + PointLight light; +} +layout(set = 0, std430) +ParameterBlock gViewParams; + +struct VertexToPixel +{ + float4 position_CS : SV_Position; +} + +VertexToPixel vertexMain(VertexInput input) +{ + VertexToPixel output = (VertexToPixel)0; + float3 cameraRight_WS = float3(gViewParams.viewMatrix[0][0], gViewParams.viewMatrix[0][1], gViewParams.viewMatrix[0][2]); + float3 cameraUp_WS = float3(gViewParams.viewMatrix[1][0], gViewParams.viewMatrix[1][1], gViewParams.viewMatrix[1][2]); + float3 worldPosition = input.position + cameraRight_WS * input.basePosition.x + cameraUp_WS * input.basePosition.y; + float4 viewPosition = mul(gViewParams.viewMatrix, float4(worldPosition, 1)); + output.position_CS = mul(gViewParams.projectionMatrix, viewPosition); + return output; +} + +float4 fragMain(VertexToPixel input) : SV_Target +{ + return float4(0, 1, 0, 0.001f); +} \ No newline at end of file diff --git a/res/shaders/Forward.slang b/res/shaders/Forward.slang new file mode 100644 index 0000000..97cb810 --- /dev/null +++ b/res/shaders/Forward.slang @@ -0,0 +1,80 @@ +import InputGeometry; +import LightEnv; +import BRDF; +import Material; +import TexturedMaterial; +import FlatColorMaterial; + +struct ViewParameter +{ + float4x4 viewMatrix; + float4x4 projectionMatrix; + float4 cameraPos_WS; +} +layout(set = 0, binding = 0, std430) +ConstantBuffer gViewParams; + +layout(set = 0, binding = 1, std430) +ConstantBuffer gLightEnv; + +layout(set = 1, std430) +type_param TMaterial : IMaterial; +ParameterBlock gMaterial; + +struct ModelParameter +{ + float4x4 modelMatrix; +} + +[[vk::push_constant]] +ConstantBuffer gModelParams; + +struct VertexStageOutput +{ + MaterialPixelParameter materialParameter : MaterialParameter; + float4 sv_position : SV_Position; +}; + +[shader("vertex")] +VertexStageOutput vertexMain( + InputGeometry inputGeometry) +{ + VertexStageOutput output; + MaterialPixelParameter pixelParams; + float4 worldPosition = mul(gModelParams.modelMatrix, float4(inputGeometry.getVertexPosition(), 1)); + pixelParams.position = worldPosition.xyz; + pixelParams.texCoord = inputGeometry.texCoord; + + float4 viewPosition = mul(gViewParams.viewMatrix, worldPosition); + pixelParams.viewDir = gViewParams.cameraPos_WS.xyz - worldPosition.xyz; + + pixelParams.normal = mul(gModelParams.modelMatrix, float4(inputGeometry.getNormal(), 0)).xyz; + pixelParams.tangent = mul(gModelParams.modelMatrix, float4(inputGeometry.getTangent(), 0)).xyz; + pixelParams.biTangent = mul(gModelParams.modelMatrix, float4(inputGeometry.getBiTangent(), 0)).xyz; + pixelParams.clipPosition = mul(gViewParams.projectionMatrix, viewPosition); + + output.materialParameter = pixelParams; + output.sv_position = pixelParams.clipPosition; + + return output; +} + +[shader("fragment")] +float4 fragmentMain(MaterialPixelParameter input : MaterialParameter) : SV_Target +{ + TMaterial.BRDF brdf = gMaterial.prepare(input); + + float3 viewDir = normalize(input.viewDir); + + float3 result = float3(0, 0, 0); + for (int i = 0; i < gLightEnv.numDirectionalLights; ++i) + { + result += gLightEnv.directionalLights[i].illuminate(input, brdf, viewDir); + } + for (int i = 0; i < gLightEnv.numPointLights; ++i) + { + result += gLightEnv.pointLights[i].illuminate(input, brdf, viewDir); + } + + return float4(result, 0); +} diff --git a/res/shaders/ForwardPlus.slang b/res/shaders/ForwardPlus.slang new file mode 100644 index 0000000..d4911f1 --- /dev/null +++ b/res/shaders/ForwardPlus.slang @@ -0,0 +1,92 @@ +import InputGeometry; +import LightEnv; +import BRDF; +import Material; +import TexturedMaterial; +import FlatColorMaterial; +import Common; + +struct ViewParameter +{ + float4x4 viewMatrix; + float4x4 projectionMatrix; + float4 cameraPos_WS; +} +layout(set = 0, binding = 0, std430) +ConstantBuffer gViewParams; + +layout(set = 0, binding = 1, std430) +ConstantBuffer gLightEnv; +layout(set = 0, binding = 2) +StructuredBuffer lightIndexList; +layout(set = 0, binding = 3) +RWTexture2D lightGrid; + +layout(set = 1, std430) +type_param TMaterial : IMaterial; +ParameterBlock gMaterial; + +struct ModelParameter +{ + float4x4 modelMatrix; +} + +layout(set = 2) +ConstantBuffer gModelParams; + +struct VertexStageOutput +{ + MaterialPixelParameter materialParameter : MaterialParameter; + float4 sv_position : SV_Position; +}; + +[shader("vertex")] +VertexStageOutput vertexMain( + InputGeometry inputGeometry) +{ + VertexStageOutput output; + MaterialPixelParameter pixelParams; + float4 worldPosition = mul(gModelParams.modelMatrix, float4(inputGeometry.getVertexPosition(), 1)); + pixelParams.position = worldPosition.xyz; + pixelParams.texCoord = inputGeometry.texCoord; + + float4 viewPosition = mul(gViewParams.viewMatrix, worldPosition); + pixelParams.viewDir = gViewParams.cameraPos_WS.xyz - worldPosition.xyz; + + pixelParams.normal = mul(gModelParams.modelMatrix, float4(inputGeometry.getNormal(), 0)).xyz; + pixelParams.tangent = mul(gModelParams.modelMatrix, float4(inputGeometry.getTangent(), 0)).xyz; + pixelParams.biTangent = mul(gModelParams.modelMatrix, float4(inputGeometry.getBiTangent(), 0)).xyz; + pixelParams.clipPosition = mul(gViewParams.projectionMatrix, viewPosition); + + output.materialParameter = pixelParams; + output.sv_position = pixelParams.clipPosition; + + return output; +} + +[shader("fragment")] +float4 fragmentMain(MaterialPixelParameter input : MaterialParameter) : SV_Target +{ + TMaterial.BRDF brdf = gMaterial.prepare(input); + + float3 viewDir = normalize(input.viewDir); + + float3 result = float3(0, 0, 0); + for (int i = 0; i < gLightEnv.numDirectionalLights; ++i) + { + result += gLightEnv.directionalLights[i].illuminate(input, brdf, viewDir); + } + uint2 tileIndex = uint2(floor(input.clipPosition.xy) / BLOCK_SIZE); + + uint startOffset = lightGrid[tileIndex].x; + uint lightCount = lightGrid[tileIndex].y; + + for (int j = 0; j < lightCount; ++j) + { + uint lightIndex = lightIndexList[startOffset + j]; + PointLight pointLight = gLightEnv.pointLights[lightIndex]; + result += pointLight.illuminate(input, brdf, viewDir); + } + + return float4(result, 1); +} diff --git a/res/shaders/LightCulling.slang b/res/shaders/LightCulling.slang new file mode 100644 index 0000000..945badf --- /dev/null +++ b/res/shaders/LightCulling.slang @@ -0,0 +1,149 @@ +import LightEnv; +import Common; + +struct ComputeShaderInput +{ + uint3 groupID : SV_GroupID; + uint3 groupThreadID : SV_GroupThreadID; + uint3 dispatchThreadID : SV_DispatchThreadID; + uint groupIndex : SV_GroupIndex; +}; +layout(binding = 0) +cbuffer DispatchParams +{ + uint3 numThreadGroups; + uint pad0; + uint3 numThreads; + uint pad1; +} + +layout(binding = 2) +RWTexture2D depthTextureVS; +layout(binding = 3) +ConstantBuffer lights; +layout(binding = 4) +StructuredBuffer frustums; + +layout(binding = 5) +RWStructuredBuffer oLightIndexCounter; +layout(binding = 6) +RWStructuredBuffer tLightIndexCounter; + +layout(binding = 7) +RWStructuredBuffer oLightIndexList; +layout(binding = 8) +RWStructuredBuffer tLightIndexList; +layout(binding = 9) +RWTexture2D oLightGrid; +layout(binding = 10) +RWTexture2D tLightGrid; + +groupshared uint uMinDepth; +groupshared uint uMaxDepth; + +groupshared Frustum groupFrustum; + +groupshared uint oLightCount; +groupshared uint oLightIndexStartOffset; +groupshared uint oLightList[1024]; + +groupshared uint tLightCount; +groupshared uint tLightIndexStartOffset; +groupshared uint tLightList[1024]; + + +void oAppendLight(uint lightIndex) +{ + uint index; + InterlockedAdd(oLightCount, 1, index); + if(index < 1024) + { + oLightList[index] = lightIndex; + } +} + +void tAppendLight(uint lightIndex) +{ + uint index; + InterlockedAdd(tLightCount, 1, index); + if(index < 1024) + { + tLightList[index] = lightIndex; + } +} + +[numthreads(BLOCK_SIZE, BLOCK_SIZE, 1)] +void cullLights(ComputeShaderInput in) +{ + int2 texCoord = in.dispatchThreadID.xy; + float fDepth = depthTextureVS.Load(texCoord).r; + + uint uDepth = asuint(fDepth); + if(in.groupIndex == 0) + { + uMinDepth = 0xffffffff; + uMaxDepth = 0x0; + oLightCount = 0; + tLightCount = 0; + groupFrustum = frustums[in.groupID.x + (in.groupID.y * numThreadGroups.x)]; + } + + GroupMemoryBarrierWithGroupSync(); + InterlockedMin(uMinDepth, uDepth); + InterlockedMax(uMaxDepth, uDepth); + + GroupMemoryBarrierWithGroupSync(); + + float fMinDepth = asfloat(uMinDepth); + float fMaxDepth = asfloat(uMaxDepth); + + float minDepthVS = clipToView(float4(0, 0, fMinDepth, 1)).z; + float maxDepthVS = clipToView(float4(0, 0, fMaxDepth, 1)).z; + float nearClipVS = clipToView(float4(0, 0, 0, 1.0f)).z; + + Plane minPlane = {float3(0, 0, -1), -minDepthVS}; + + for ( uint i = in.groupIndex; i < lights.numPointLights; i += BLOCK_SIZE * BLOCK_SIZE ) + { + PointLight light = lights.pointLights[i]; + //if(light.insideFrustum(groupFrustum, nearClipVS, maxDepthVS)) + { + //InterlockedAdd(tLightCount, 1, index); + //if(index < 1024) + //{ + // tLightList[index] = i; + //} + //if(!light.insidePlane(minPlane)) + //{ + oAppendLight(i); + //} + } + } + + GroupMemoryBarrierWithGroupSync(); + + if(in.groupIndex == 0) + { + InterlockedAdd(oLightIndexCounter[0], (uint)oLightCount, oLightIndexStartOffset); + oLightGrid[in.groupID.xy] = uint2(oLightIndexStartOffset, oLightCount); + + InterlockedAdd(tLightIndexCounter[0], (uint)tLightCount, tLightIndexStartOffset); + tLightGrid[in.groupID.xy] = uint2(tLightIndexStartOffset, tLightCount); + } + GroupMemoryBarrierWithGroupSync(); + + if(in.groupIndex == 0) + { + for (uint j = 0; j < (uint)oLightCount; j += 1/*BLOCK_SIZE * BLOCK_SIZE*/) + { + oLightIndexList[oLightIndexStartOffset + j] = oLightList[j]; + } + } + + + // For transparent geometry. + for ( uint k = in.groupIndex; k < (uint)tLightCount; k += BLOCK_SIZE * BLOCK_SIZE ) + { + tLightIndexList[tLightIndexStartOffset + k] = tLightList[k]; + } +} \ No newline at end of file diff --git a/res/shaders/Placeholder.semat b/res/shaders/Placeholder.semat new file mode 100644 index 0000000..cc97e34 --- /dev/null +++ b/res/shaders/Placeholder.semat @@ -0,0 +1,75 @@ +{ + "name": "Placeholder", + "profile": "BlinnPhong", + "params": { + "diffuseTexture": { + "type": "Texture2D" + }, + "specularTexture": { + "type": "Texture2D" + }, + "normalTexture": { + "type": "Texture2D" + }, + "uvScale": { + "type": "float", + "default": "0.0f" + }, + "metallic": { + "type": "float", + "default": "0.0f" + }, + "subsurface": { + "type": "float", + "default": "0.0f" + }, + "roughness": { + "type": "float", + "default": "0.5f" + }, + "specularTint": { + "type": "float", + "default": "0.0f" + }, + "anisotropic": { + "type": "float", + "default": "0.0f" + }, + "sheen": { + "type": "float", + "default": "0.0f" + }, + "sheenTint": { + "type": "float", + "default": "0.5f" + }, + "clearCoat": { + "type": "float", + "default": "0.0f" + }, + "clearCoatGloss": { + "type": "float", + "default": "1.0f" + }, + "textureSampler": { + "type": "SamplerState" + } + }, + "code": [ + "result.baseColor = diffuseTexture.Sample(textureSampler, geometry.texCoord * uvScale).xyz;", + "result.metallic = 0;", + "float3 bumpMapNormal = normalTexture.Sample(textureSampler, geometry.texCoord * uvScale).xyz;", + "bumpMapNormal = 2.0 * bumpMapNormal - float3(1.0, 1.0, 1.0);", + "result.normal = geometry.transformLocalToWorld(bumpMapNormal);", + "result.specular = specularTexture.Sample(textureSampler, geometry.texCoord * uvScale).x;", + "result.roughness = roughness;", + "result.specularTint = specularTint;", + "result.anisotropic = anisotropic;", + "result.sheen = sheen;", + "result.sheenTint = sheenTint;", + "result.clearCoat = clearCoat;", + "result.clearCoatGloss = clearCoatGloss;", + "return result;" + ] + +} \ No newline at end of file diff --git a/res/shaders/lib/BRDF.slang b/res/shaders/lib/BRDF.slang new file mode 100644 index 0000000..815235a --- /dev/null +++ b/res/shaders/lib/BRDF.slang @@ -0,0 +1,152 @@ +import Common; + +interface IBRDF +{ + float3 evaluate(float3 view, float3 light, float3 normal, float3 tangent, float3 biTangent, float3 lightColor); +}; + +struct BlinnPhong : IBRDF +{ + float3 baseColor; + float metallic = 0; + float3 normal = float3(0, 1, 0); + float subsurface = 0; + float specular = 0.5; + float roughness = 0.5; + float specularTint = 0; + float anisotropic = 0; + float sheen = 0; + float sheenTint = 0.5f; + float clearCoat = 0; + float clearCoatGloss = 1; + + float3 evaluate(float3 view, float3 light, float3 surfaceNormal, float3 tangent, float3 biTangent, float3 lightColor) + { + float nDotL = saturate(dot(normal, light)); + float3 h = normalize(light + view); + float nDotH = saturate(dot(normal, h)); + + return baseColor * nDotL + lightColor * specular * pow(nDotH, sheen); + } +}; + +struct DisneyBRDF : IBRDF +{ + float3 baseColor; + float metallic = 0; + float3 normal = float3(0, 1, 0); + float subsurface = 0; + float specular = 0.5; + float roughness = 0.5; + float specularTint = 0; + float anisotropic = 0; + float sheen = 0; + float sheenTint = 0.5f; + float clearCoat = 0; + float clearCoatGloss = 1; + + float sqr(float x) + { + return x * x; + } + + float SchlickFresnel(float u) + { + float m = clamp(1 - u, 0, 1); + float m2 = m * m; + return m2 * m2 * m; // pow(m,5) + } + + float GTR1(float NdotH, float a) + { + if (a >= 1) + return 1 / PI; + float a2 = a * a; + float t = 1 + (a2 - 1) * NdotH * NdotH; + return (a2 - 1) / (PI * log(a2) * t); + } + + float GTR2(float NdotH, float a) + { + float a2 = a * a; + float t = 1 + (a2 - 1) * NdotH * NdotH; + return a2 / (PI * t * t); + } + + float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay) + { + return 1 / (PI * ax * ay * sqr(sqr(HdotX / ax) + sqr(HdotY / ay) + NdotH * NdotH)); + } + + float smithG_GGX(float NdotV, float alphaG) + { + float a = alphaG * alphaG; + float b = NdotV * NdotV; + return 1 / (NdotV + sqrt(a + b - a * b)); + } + + float smithG_GGX_aniso(float NdotV, float VdotX, float VdotY, float ax, float ay) + { + return 1 / (NdotV + sqrt(sqr(VdotX * ax) + sqr(VdotY * ay) + sqr(NdotV))); + } + + float3 mon2lin(float3 x) + { + return float3(pow(x[0], 2.2), pow(x[1], 2.2), pow(x[2], 2.2)); + } + + + float3 evaluate(float3 V, float3 L, float3 surfaceNormal, float3 X, float3 Y, float3 lightColor) + { + float3 N = normal; + float NdotL = dot(N, L); + float NdotV = dot(N, V); + if (NdotL < 0 || NdotV < 0) + return float3(0); + float3 H = normalize(L + V); + + float NdotH = dot(N, H); + float LdotH = dot(L, H); + float3 Cdlin = mon2lin(baseColor); + float Cdlum = .3 * Cdlin[0] + .6 * Cdlin[1] + .1 * Cdlin[2]; // luminance approx. + float3 Ctint = Cdlum > 0 ? Cdlin / Cdlum : float3(1); // normalize lum. to isolate hue+sat + float3 Cspec0 = lerp(specular * .08 * lerp(float3(1), Ctint, specularTint), Cdlin, metallic); + float3 Csheen = lerp(float3(1), Ctint, sheenTint); + + // Diffuse fresnel - go from 1 at normal incidence to .5 at grazing + // and mix in diffuse retro-reflection based on roughness + float FL = SchlickFresnel(NdotL), FV = SchlickFresnel(NdotV); + float Fd90 = 0.5 + 2 * LdotH * LdotH * roughness; + float Fd = lerp(1.0, Fd90, FL) * lerp(1.0, Fd90, FV); + + // Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf + // 1.25 scale is used to (roughly) preserve albedo + // Fss90 used to "flatten" retroreflection based on roughness + float Fss90 = LdotH * LdotH * roughness; + float Fss = lerp(1.0, Fss90, FL) * lerp(1.0, Fss90, FV); + float ss = 1.25 * (Fss * (1 / (NdotL + NdotV) - .5) + .5); + + // specular + float aspect = sqrt(1 - anisotropic * .9); + float ax = max(.001, sqr(roughness) / aspect); + float ay = max(.001, sqr(roughness) * aspect); + float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay); + float FH = SchlickFresnel(LdotH); + float3 Fs = lerp(Cspec0, float3(1), FH); + float Gs; + Gs = smithG_GGX_aniso(NdotL, dot(L, X), dot(L, Y), ax, ay); + Gs *= smithG_GGX_aniso(NdotV, dot(V, X), dot(V, Y), ax, ay); + + // sheen + float3 Fsheen = FH * sheen * Csheen; + + // clearcoat (ior = 1.5 -> F0 = 0.04) + float Dr = GTR1(NdotH, lerp(.1, .001, clearCoatGloss)); + float Fr = lerp(.04, 1.0, FH); + float Gr = smithG_GGX(NdotL, .25) * smithG_GGX(NdotV, .25); + + return ((1 / PI) * lerp(Fd, ss, subsurface) * Cdlin + Fsheen) + * (1 - metallic) + + Gs * Fs * Ds + .25 * clearCoat * Gr * Fr * Dr; + } +}; diff --git a/res/shaders/lib/Common.slang b/res/shaders/lib/Common.slang new file mode 100644 index 0000000..086f79b --- /dev/null +++ b/res/shaders/lib/Common.slang @@ -0,0 +1,62 @@ +const static float PI = 3.1415926535897932f; +const static uint MAX_PARTICLES = 65536; +const static uint BLOCK_SIZE = 8; + +cbuffer ScreenToViewParams +{ + float4x4 inverseProjection; + float2 screenDimensions; +} + +// Convert clip space coordinates to view space +float4 clipToView( float4 clip ) +{ + // View space position. + float4 view = mul( inverseProjection, clip ); + // Perspective projection. + view = view / view.w; + + return view; +} + +// Convert screen space coordinates to view space. +float4 screenToView( float4 screen ) +{ + // Convert to normalized texture coordinates + float2 texCoord = screen.xy / screenDimensions; + + // Convert to clip space + float4 clip = float4( float2( texCoord.x, -texCoord.y ) * 2.0f - 1.0f, screen.z, screen.w ); + + return clipToView( clip ); +} + +struct Plane +{ + float3 n; + float d; + float3 p0; + float3 p1; + float3 p2; +}; + +struct Frustum +{ + Plane planes[4]; +}; +Plane computePlane(float3 p0, float3 p1, float3 p2) +{ + Plane plane; + + float3 v0 = p2 - p0; + float3 v2 = p1 - p0; + + plane.n = normalize(cross(v0, v2)); + + plane.d = dot(plane.n, p0); + plane.p0 = p0; + plane.p1 = p1; + plane.p2 = p2; + + return plane; +} diff --git a/res/shaders/lib/FlatColorMaterial.slang b/res/shaders/lib/FlatColorMaterial.slang new file mode 100644 index 0000000..8a44cdb --- /dev/null +++ b/res/shaders/lib/FlatColorMaterial.slang @@ -0,0 +1,27 @@ +import LightEnv; +import Material; +import BRDF; +import InputGeometry; + +struct FlatColorMaterial : IMaterial +{ + float3 diffuseColor; + float specularity; + + typedef BlinnPhong BRDF; + BlinnPhong prepare(MaterialPixelParameter input) + { + BlinnPhong result; + result.baseColor = diffuseColor; + result.specular = specularity; + result.normal = normalize(input.normal); + result.roughness = 0.5; + result.specularTint = 0; + result.anisotropic = 1; + result.sheen = 1; + result.sheenTint = 0.5; + result.clearCoat = 0; + result.clearCoatGloss = 0; + return result; + } +}; diff --git a/res/shaders/lib/InputGeometry.slang b/res/shaders/lib/InputGeometry.slang new file mode 100644 index 0000000..a5cbb45 --- /dev/null +++ b/res/shaders/lib/InputGeometry.slang @@ -0,0 +1,70 @@ +interface IVertexShaderInput +{ +//internally, the vertex layout is stored in vec4 for faster access, +//but here we unwrap them for convenience + float3 getVertexPosition(); + float2 getTexCoords(); + float3 getNormal(); + float3 getTangent(); + float3 getBiTangent(); +}; + +struct PositionOnlyVertexInput : IVertexShaderInput +{ + float4 position; + + float3 getVertexPosition() { return position.xyz; } + float2 getTexCoords() { return float2(0, 0); } + float3 getNormal() { return float3(0, 1, 0); } + float3 getTangent() { return float3(1, 0, 0); } + float3 getBiTangent() { return float3(0, 0, 1); } +}; + +struct PositionAndNormalVertexInput : IVertexShaderInput +{ + float4 position; + float4 normal; + + float3 getVertexPosition() { return position.xyz; } + float2 getTexCoords() { return float2(0, 0); } + float3 getNormal() { return normal.xyz; } + float3 getTangent() { return float3(1, 0, 0); } + float3 getBiTangent() { return float3(0, 0, 1); } +}; + +struct InputGeometry : IVertexShaderInput +{ + float4 position; + float2 texCoord; + float4 normal; + float4 tangent; + float4 bitangent; + + float3 getVertexPosition() { return position.xyz; } + float2 getTexCoords() { return texCoord; } + float3 getNormal() { return normal.xyz; } + float3 getTangent() { return tangent.xyz; } + float3 getBiTangent() { return bitangent.xyz; } +}; + +struct MaterialPixelParameter +{ + float3 position; + float2 texCoord; + float3 viewDir; + float3 normal; + float3 tangent; + float3 biTangent; + float4 clipPosition; + float3 transformLocalToWorld(float3 input) + { + float3 unitNormal = normalize(normal); + float3 unitTangent = normalize(tangent); + unitTangent = normalize(unitTangent - dot(unitTangent, unitNormal) * unitNormal); + float3 unitBitangent = cross(unitTangent, unitNormal); + float3x3 tbn = float3x3(unitTangent, unitBitangent, unitNormal); + float3 result = mul(tbn, input); + result = normalize(result); + return result; + } +}; \ No newline at end of file diff --git a/res/shaders/lib/LightEnv.slang b/res/shaders/lib/LightEnv.slang new file mode 100644 index 0000000..a43fb52 --- /dev/null +++ b/res/shaders/lib/LightEnv.slang @@ -0,0 +1,70 @@ +import InputGeometry; +import BRDF; +import Common; + +interface ILightEnv +{ + float3 illuminate(InputGeometry input, B brdf, float3 wo); +}; + +struct DirectionalLight : ILightEnv +{ + float4 color; + float4 direction; + float4 intensity; + + float3 illuminate(MaterialPixelParameter input, B brdf, float3 wo) + { + return intensity.xyz * brdf.evaluate(wo, direction.xyz, input.normal, input.tangent, input.biTangent, color.xyz); + } +}; + +struct PointLight : ILightEnv +{ + float4 positionWS; + float4 positionVS; + float3 color; + float range; + + float3 illuminate(MaterialPixelParameter input, B brdf, float3 viewDir) + { + float3 lightVec = positionWS.xyz - input.position; + float d = length(lightVec); + float3 direction = normalize(lightVec); + float illuminance = max(1 - d / range, 0); + return illuminance * brdf.evaluate(viewDir, direction, input.normal, input.tangent, input.biTangent, color); + } + + bool insidePlane(Plane plane) + { + return dot(plane.n, positionVS.xyz) - plane.d < -range; + } + + bool insideFrustum(Frustum frustum, float zNear, float zFar) + { + bool result = true; + + //if(positionVS.z - range > zNear || positionVS.z + range < zFar) + { + // result = false; + } + for(int i = 0; i < 4 && result; ++i) + { + if(insidePlane(frustum.planes[i])) + { + result = false; + } + } + return result; + } +}; + +#define MAX_DIRECTIONAL_LIGHTS 4 +#define MAX_POINT_LIGHTS 256 +struct Lights +{ + DirectionalLight directionalLights[MAX_DIRECTIONAL_LIGHTS]; + PointLight pointLights[MAX_POINT_LIGHTS]; + uint numDirectionalLights; + uint numPointLights; +}; diff --git a/res/shaders/lib/Material.slang b/res/shaders/lib/Material.slang new file mode 100644 index 0000000..ec2bc1c --- /dev/null +++ b/res/shaders/lib/Material.slang @@ -0,0 +1,9 @@ +import Common; +import BRDF; +import InputGeometry; + +interface IMaterial +{ + associatedtype BRDF : IBRDF; + BRDF prepare(MaterialPixelParameter geometry); +}; diff --git a/res/shaders/lib/ParallaxMaterial.slang b/res/shaders/lib/ParallaxMaterial.slang new file mode 100644 index 0000000..bbe8ec9 --- /dev/null +++ b/res/shaders/lib/ParallaxMaterial.slang @@ -0,0 +1,21 @@ +import Material; +import InputGeometry; + +struct ParallaxMaterial : IMaterial +{ + Texture2D diffuseTexture; + Texture2D specularTexture; + Texture2D displacementTexture; + SamplerState textureSampler; + float specularity; + + typedef BlinnPhong BRDF; + BlinnPhong prepare(InputGeometry geometry) + { + BlinnPhong blinn; + blinn.baseColor = diffuseTexture.Sample(textureSampler, geometry.getTexCoords()).xyz; + blinn.specularColor = specularTexture.Sample(textureSampler, geometry.getTexCoords()).xyz; + blinn.specular = specularity; + return blinn; + } +}; diff --git a/res/shaders/lib/ParticlesCommon.slang b/res/shaders/lib/ParticlesCommon.slang new file mode 100644 index 0000000..7bcd817 --- /dev/null +++ b/res/shaders/lib/ParticlesCommon.slang @@ -0,0 +1,12 @@ + +struct Particle +{ + float3 position; + float mass; + float3 velocity; + float age; + float3 forceAccumulator; + float life; + float color; + float3 pad; +}; \ No newline at end of file diff --git a/res/shaders/lib/TexturedMaterial.slang b/res/shaders/lib/TexturedMaterial.slang new file mode 100644 index 0000000..dd94d70 --- /dev/null +++ b/res/shaders/lib/TexturedMaterial.slang @@ -0,0 +1,42 @@ +import LightEnv; +import Material; +import BRDF; +import InputGeometry; + +struct TexturedMaterial : IMaterial +{ + Texture2D diffuseTexture; + Texture2D specularTexture; + Texture2D normalTexture; + float uvScale; + float metallic = 0; + float subsurface = 0; + float roughness = 0.5; + float specularTint = 0; + float anisotropic = 0; + float sheen = 0; + float sheenTint = 0.5f; + float clearCoat = 0; + float clearCoatGloss = 1; + SamplerState textureSampler; + + typedef BlinnPhong BRDF; + BlinnPhong prepare(MaterialPixelParameter geometry) + { + BlinnPhong result; + result.baseColor = diffuseTexture.Sample(textureSampler, geometry.texCoord * uvScale).xyz; + result.metallic = 0; + float3 bumpMapNormal = normalTexture.Sample(textureSampler, geometry.texCoord * uvScale).xyz; + bumpMapNormal = 2.0 * bumpMapNormal - float3(1.0, 1.0, 1.0); + result.normal = geometry.transformLocalToWorld(bumpMapNormal); + result.specular = specularTexture.Sample(textureSampler, geometry.texCoord * uvScale).x; + result.roughness = roughness; + result.specularTint = specularTint; + result.anisotropic = anisotropic; + result.sheen = sheen; + result.sheenTint = sheenTint; + result.clearCoat = clearCoat; + result.clearCoatGloss = clearCoatGloss; + return result; + } +}; \ No newline at end of file diff --git a/res/shaders/shaders.slang b/res/shaders/shaders.slang new file mode 100644 index 0000000..15ce012 --- /dev/null +++ b/res/shaders/shaders.slang @@ -0,0 +1,485 @@ +// shaders.slang + +// +// This example builds on the simplistic shaders presented in the +// "Hello, World" example by adding support for (intentionally +// simplistic) surface materil and light shading. +// +// The code here is not meant to exemplify state-of-the-art material +// and lighting techniques, but rather to show how a shader +// library can be developed in a modular fashion without reliance +// on the C preprocessor manual parameter-binding decorations. +// + +// We are going to define a simple model for surface material shading. +// +// The first building block in our model will be the representation of +// the geometry attributes of a surface as fed into the material. +// +struct SurfaceGeometry +{ + float3 position; + float3 normal; + + // TODO: tangent vectors would be the natural next thing to add here, + // and would be required for anisotropic materials. However, the + // simplistic model loading code we are currently using doesn't + // produce tangents... + // + // float3 tangentU; + // float3 tangentV; + + // We store a single UV parameterization in these geometry attributes. + // A more complex renderer might need support for multiple UV sets, + // and indeed it might choose to use interfaces and generics to capture + // the different requirements that different materials impose on + // the available surface attributes. We won't go to that kind of + // trouble for such a simple example. + // + float2 uv; +}; +// +// Next, we want to define the fundamental concept of a refletance +// function, so that we can use it as a building block for other +// parts of the system. This is a case where we are trying to +// show how a proper physically-based renderer (PBR) might +// decompose the problem using Slang, even though our simple +// example is *not* physically based. +// +interface IBRDF +{ + // Technically, a BRDF is only a function of the incident + // (`wi`) and exitant (`wo`) directions, but for simplicity + // we are passing in the surface normal (`N`) as well. + // + float3 evaluate(float3 wo, float3 wi, float3 N); +}; +// +// We can now define various implemntations of the `IBRDF` interface +// that represent different reflectance functions we want to support. +// For now we keep things simple by defining about the simplest +// reflectance function we can think of: the Blinn-Phong reflectance +// model: +// +struct BlinnPhong : IBRDF +{ + // Blinn-Phong needs diffuse and specular reflectances, plus + // a specular exponent value (which relates to "roughness" + // in more modern physically-based models). + // + float3 kd; + float3 ks; + float specularity; + + // Here we implement the one requirement of the `IBRDF` interface + // for our concrete implementation, using a textbook definition + // of Blinng-Phong shading. + // + // Note: our "BRDF" definition here folds the N-dot-L term into + // the evlauation of the reflectance function in case there are + // useful algebraic simplifications this enables. + // + float3 evaluate(float3 V, float3 L, float3 N) + { + float nDotL = saturate(dot(N, L)); + float3 H = normalize(L + V); + float nDotH = saturate(dot(N, H)); + + return kd*nDotL + ks*pow(nDotH, specularity); + } +}; +// +// It is important to note that a reflectance function is *not* +// a "material." In most cases, a material will have spatially-varying +// properties so that it cannot be summarized as a single `IBRDF` +// instance. +// +// Thus a "material" is a value that can produce a BRDF for any point +// on a surface (e.g., by sampling texture maps, etc.). +// +interface IMaterial +{ + // Different concrete material implementations might yield BRDF + // values with different types. E.g., one material might yield + // reflectance functions using `BlinnPhong` while another uses + // a much more complicated/accurate representation. + // + // We encapsulate the choice of BRDF parameters/evaluation in + // our material interface with an "associated type." In the + // simplest terms, think of this as an interface requirement + // that is a type, instead of a method. + // + // (If you are C++-minded, you might think of this as akin to + // how every container provided an `iterator` type, but different + // containers may have different types of iterators) + // + associatedtype BRDF : IBRDF; + + // For our simple example program, it is enough for a material to + // be able to return a BRDF given a point on the surface. + // + // A more complex implementation of material shading might also + // have the material return updated surface geometry to reflect + // the result of normal mapping, occlusion mapping, etc. or + // return an opacity/coverage value for partially transparent + // surfaces. + // + BRDF prepare(SurfaceGeometry geometry); +}; + +// We will now define a trivial first implementation of the material +// interface, which uses our Blinn-Phong BRDF with uniform values +// for its parameters. +// +// Note that this implemetnation is being provided *after* the +// shader parameter `gMaterial` is declared, so that there is no +// assumption in the shader code that `gMaterial` will be plugged +// in using an instance of `SimpleMaterial` +// +// +struct SimpleMaterial : IMaterial +{ + // We declare the properties we need as fields of the material type. + // When `SimpleMaterial` is used for `TMaterial` above, then + // `gMaterial` will be a `ParameterBlock`, and these + // parameters will be allocated to a constant buffer that is part of + // that parameter block. + // + // TODO: A future version of this example will include texture parameters + // here to show that they are declared just like simple uniforms. + // + float3 diffuseColor; + float3 specularColor; + float specularity; + + // To satisfy the requirements of the `IMaterial` interface, our + // material type needs to provide a suitable `BRDF` type. We + // do this by using a simple `typedef`, although a nested + // `struct` type can also satisfy an associated type requirement. + // + // A future version of the Slang compiler may allow the "right" + // associated type definition to be inferred from the signature + // of the `prepare()` method below. + // + typedef BlinnPhong BRDF; + + BlinnPhong prepare(SurfaceGeometry geometry) + { + BlinnPhong brdf; + brdf.kd = diffuseColor; + brdf.ks = specularColor; + brdf.specularity = specularity; + return brdf; + } +}; +// +// Note that no other code in this file statically +// references the `SimpleMaterial` type, and instead +// it is up to the application to "plug in" this type, +// or another `IMaterial` implementation for the +// `TMaterial` parameter. +// + +// A light, or an entire lighting *environment* is an object +// that can illuminate a surface using some BRDF implemented +// with our abstractions above. +// +interface ILightEnv +{ + // The `illuminate` method is intended to integrate incoming + // illumination from this light (environment) incident at the + // surface point given by `g` (which has the reflectance function + // `brdf`) and reflected into the outgoing direction `wo`. + // + float3 illuminate(SurfaceGeometry g, B brdf, float3 wo); + // + // Note that the `illuminate()` method is allowed as an interface + // requirement in Slang even though it is a generic. Constract that + // with C++ where a `template` method cannot be `virtual`. +}; + +// Given the `ILightEnv` interface, we can write up almost textbook +// definition of directional and point lights. + +struct DirectionalLight : ILightEnv +{ + float3 direction; + float3 intensity; + + float3 illuminate(SurfaceGeometry g, B brdf, float3 wo) + { + return intensity * brdf.evaluate(wo, direction, g.normal); + } +}; +struct PointLight : ILightEnv +{ + float3 position; + float3 intensity; + + float3 illuminate(SurfaceGeometry g, B brdf, float3 wo) + { + float3 delta = position - g.position; + float d = length(delta); + float3 direction = normalize(delta); + float3 illuminance = intensity / (d*d); + return illuminance * brdf.evaluate(wo, direction, g.normal); + } +}; + +// In most cases, a shader entry point will only be specialized for a single +// material, but interesting rendering almost always needs multiple lights. +// For that reason we will next define types to represent *composite* lighting +// environment with multiple lights. +// +// A naive approach might be to have a single undifferntiated list of lights +// where any type of light may appear at any index, but this would lose all +// of the benefits of static specialization: we would have to perform dynamic +// branching to determine what kind of light is stored at each index. +// +// Instead, we will start with a type for *homogeneous* arrays of lights: +// +struct LightArray : ILightEnv +{ + // The `LightArray` type has two generic parameters: + // + // - `L` is a type parameter, representing the type of lights that will be in our array + // - `N` is a generic *value* parameter, representing the maximum number of lights allowed + // + // Slang's support for generic value parameters is currently experimental, + // and the syntax might change. + + int count; + L lights[N]; + + float3 illuminate(SurfaceGeometry g, B brdf, float3 wo) + { + // Our light array integrates illumination by naively summing + // contributions from all the lights in the array (up to `count`). + // + // A more advanced renderer might try apply sampling techniques + // to pick a subset of lights to sample. + // + float3 sum = 0; + for( int ii = 0; ii < count; ++ii ) + { + sum += lights[ii].illuminate(g, brdf, wo); + } + return sum; + } +}; + +// `LightArray` can handle multiple lights as long as they have the +// same type, but we need a way to have a scene with multiple lights +// of different types *without* losing static specialization. +// +// The `LightPair` type supports this in about the simplest way +// possible, by aggregating a light (environment) of type `T` and +// one of type `U`. Those light environments might themselves be +// `LightArray`s or `LightPair`s, so that arbitrarily complex +// environments can be created from just these two composite types. +// +// This is probably a good place to insert a reminder the Slang's +// generics are *not* C++ templates, so that the error messages +// produced when working with these types are in general reasonable, +// and this is *not* any form of "template metaprogramming." +// +// That said, we expect that future versions of Slang will make +// defining composite types light this a bit less cumbersome. +// +struct LightPair : ILightEnv +{ + T first; + U second; + + float3 illuminate(SurfaceGeometry g, B brdf, float3 wo) + { + return first.illuminate(g, brdf, wo) + + second.illuminate(g, brdf, wo); + } +}; + +// As a final (degenerate) case, we will define a light +// environment with *no* lights, which contributes no illumination. +// +struct EmptyLightEnv : ILightEnv +{ + float3 illuminate(SurfaceGeometry g, B brdf, float3 wo) + { + return 0; + } +}; + +// The code above constitutes the "shader library" for our +// application, while the code below this point is the +// implementation of a simple forward rendering pass +// using that library. +// +// While the shader library has used many of Slang's advanced +// mechanisms, the vertex and fragment shaders will be +// much more modest, and hopefully easier to follow. + + +// We will start with a `struct` for per-view parameters that +// will be allocated into a `ParameterBlock`. +// +// As written, this isn't very different from using an HLSL +// `cbuffer` declaration, but importantly this code will +// continue to work if we add one or more resources (e.g., +// an enironment map texture) to the `PerView` type. +// +struct PerView +{ + float4x4 viewProjection; + float3 eyePosition; +}; +ParameterBlock gViewParams; + +// Declaring a block for per-model parameter data is +// similarly simple. +// +struct PerModel +{ + float4x4 modelTransform; + float4x4 inverseTransposeModelTransform; +}; +ParameterBlock gModelParams; + +// We want our shader to work with any kind of lighting environment +// - that is, and type that implements `ILightEnv`. Furthermore, +// we want the parameters of that lighting environment to be passed +// as parameter block - `ParameterBlock` for some type `L`. +// +// We handle this by defining a global generic type parameter for +// our shader, and constrainting it to implement `ILightEnv`... +// +type_param TLightEnv : ILightEnv; +// +// ... and then defining a parameter block that uses that type +// parameter as the "element type" of the block: +// +ParameterBlock gLightEnv; + +// Our handling of the material parameter for our shader +// is quite similar to the case for the lighting environment: +// +type_param TMaterial : IMaterial; +ParameterBlock gMaterial; + +// Our vertex shader entry point is only marginally more +// complicated than the Hello World example. We will +// start by declaring the various "connector" `struct`s. +// +struct AssembledVertex +{ + float3 position : POSITION; + float3 normal : NORMAL; + float2 uv : UV; +}; +struct CoarseVertex +{ + float3 worldPosition; + float3 worldNormal; + float2 uv; +}; +struct VertexStageOutput +{ + CoarseVertex coarseVertex : CoarseVertex; + float4 sv_position : SV_Position; +}; + +// Perhaps most interesting new feature of the entry +// point decalrations is that we use a `[shader(...)]` +// attribute (as introduced in HLSL Shader Model 6.x) +// in order to tag our entry points. +// +// This attribute informs the Slang compiler which +// functions are intended to be compiled as shader +// entry points (and what stage they target), so that +// the programmer no longer needs to specify the +// entry point name/stage through the API (or on +// the command line when using `slangc`). +// +// While HLSL added this feature only in newer versions, +// the Slang compiler supports this attribute across +// *all* targets, so that it is okay to use whether you +// want DXBC, DXIL, or SPIR-V output. +// +[shader("vertex")] +VertexStageOutput vertexMain( + AssembledVertex assembledVertex) +{ + VertexStageOutput output; + + float3 position = assembledVertex.position; + float3 normal = assembledVertex.normal; + float2 uv = assembledVertex.uv; + + float3 worldPosition = mul(gModelParams.modelTransform, float4(position, 1.0)).xyz; + float3 worldNormal = mul(gModelParams.inverseTransposeModelTransform, float4(normal, 0.0)).xyz; + + output.coarseVertex.worldPosition = worldPosition; + output.coarseVertex.worldNormal = worldNormal; + output.coarseVertex.uv = uv; + + output.sv_position = mul(gViewParams.viewProjection, float4(worldPosition, 1.0)); + + return output; +} + +// Our fragment shader is almost trivial, with the most interesting +// thing being how it uses the `TMaterial` type parameter (through the +// value stored in the `gMaterial` parameter block) to dispatch to +// the correct implementation of the `getDiffuseColor()` method +// in the `IMaterial` interface. +// +// The `gMaterial` parameter block declaration thus serves not only +// to group certain shader parameters for efficient CPU-to-GPU +// communication, but also to select the code that will execute +// in specialized versions of the `fragmentMain` entry point. +// +[shader("fragment")] +float4 fragmentMain( + CoarseVertex coarseVertex : CoarseVertex) : SV_Target +{ + // We start by using our interpolated vertex attributes + // to construct the local surface geometry that we will + // use for material evaluation. + // + SurfaceGeometry g; + g.position = coarseVertex.worldPosition; + g.normal = normalize(coarseVertex.worldNormal); + g.uv = coarseVertex.uv; + + float3 V = normalize(gViewParams.eyePosition - g.position); + + // Next we prepare the material, which involves running + // any "pattern generation" logic of the material (e.g., + // sampling and blending texture layers), to produce + // a BRDF suitable for evaluating under illumination + // from different light sources. + // + // Note that the return type here is `TMaterial.BRDF`, + // which is the `BRDF` type *associated* with the (unknown) + // `TMaterial` type. When `TMaterial` gets substituted for + // a concrete type later (e.g., `SimpleMaterial`) this + // will resolve to a concrete type too (e.g., `SimpleMaterial.BRDF` + // which is an alias for `BlinnPhong`). + // + TMaterial.BRDF brdf = gMaterial.prepare(g); + + // Now that we've done the first step of material evaluation + // and sampled texture maps, etc., it is time to start + // integrating incident light at our surface point. + // + // Because we've wrapped up the lighting environment as + // a single (composite) object, this is as simple as calling + // its `illuminate()` method. Our particular fragment shader + // is thus abstracted from how the renderer chooses to structure + // this integration step, somewhat similar to how an + // `illuminance` loop in RenderMan Shading Language works. + // + + float3 color = gLightEnv.illuminate(g, brdf, V); + + return float4(color, 1); +} diff --git a/res/textures/placeholder.png b/res/textures/placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..c0a5c62195572d04482191e75e4086a373b013af GIT binary patch literal 1619 zcmc&#X*8P&6#YkQ@AVMXLeP5acojCJ%e$V{4@16Vp-Sh6dFWJe#MoHng0ssI?cD7b7 z;+}8_IT>;7wD9W_H;Hf;8%v<}y~ezl90|O3;~D_GN>kkPlNNJ%jIC!l04R4JLV}Ja z`2&FToSoG**ZYWN;()!IqeeHMByXL3=TWiV14U@>U{apR(Vr=pW6Kwrdi|k!Atw^2K|FJilO6#38qiPxl%;_uk_p!(I*Ng5Cjj#wjlWy^qDE_N4P^`r z%twZXR#U=eAD0#GspRJ7z8V`H#hMu!I&*nE&&I~aopx7yH6YV1~=< z%YLVx&*l1y7RTxuCd_|ehA)nu-+i5xnb~XLL2Dl(BO_f;%$iU1J(N}HT3f3}^&P*OnwqLU<`VJTn~qZ>`qG=)+K}kbP#9w` zd}qniji|YRMxQ$>$s?t7^!D1BojKE+6UZp&JrzSIlgZ!Gg?%g*iw2Dh3<~OjIl>V< zO5KRpkXkYYX%J5!5Mn+_r^F7=;SQK=Hj>EyT_}t;oouxxnXaFo-d*L~!Q6#iEtiuiT+_4= z4MGXCI(0dU@bV?(uK>+mZtqu7-Y8Vn^1);MEb+wNzK8aiAv+PTeq(l?>P=6k$pZ25F1E_;HwfSxL!V&S$o> z55s6+6Ff{Patfa`Nwg%K3uRN+OcHx$mn3+Ta7iCL#_pD)I%B9yLuT^H5y+hwm z-rn9G^m~Ghfc>2OeB@r~1y%7K3k|ikJNNT9@~gE*nrZk4l<4ismNHyQvx=6*hlQK) zq-gg1{QQ#^x|aSQ!;+h;oeasIWc&9pO|X9Y1xSir82%*; Rq%D2~fF0bys@Bps@o$rs{fYnp literal 0 HcmV?d00001 diff --git a/src/Engine/Asset/Asset.cpp b/src/Engine/Asset/Asset.cpp index 36a4537..d8c4e4d 100644 --- a/src/Engine/Asset/Asset.cpp +++ b/src/Engine/Asset/Asset.cpp @@ -3,9 +3,65 @@ using namespace Seele; Asset::Asset() + : fullPath("") + , name("") + , parentDir("") + , extension("") + , status(Status::Uninitialized) +{ +} +Asset::Asset(const std::filesystem::path& path) + : fullPath(std::filesystem::absolute(path)) + , status(Status::Uninitialized) +{ + fullPath.make_preferred(); + parentDir = fullPath.parent_path(); + name = fullPath.stem(); + extension = fullPath.extension(); +} +Asset::Asset(const std::string &fullPath) + : Asset(std::filesystem::path(fullPath)) +{ +} + +Asset::Asset(const std::string &directory, const std::string &fileName) + : Asset(std::filesystem::path(directory + fileName)) { } Asset::~Asset() { +} + +std::ifstream &Asset::getReadStream() +{ + if(inStream.is_open()) + { + return inStream; + } + inStream.open(fullPath); + return inStream; +} + +std::ofstream &Asset::getWriteStream() +{ + if(outStream.is_open()) + { + return outStream; + } + outStream.open(fullPath); + return outStream; +} + +std::string Asset::getFileName() +{ + return name.generic_string(); +} +std::string Asset::getFullPath() +{ + return fullPath.generic_string(); +} +std::string Asset::getExtension() +{ + return extension.generic_string(); } \ No newline at end of file diff --git a/src/Engine/Asset/Asset.h b/src/Engine/Asset/Asset.h index 6139c30..31169d0 100644 --- a/src/Engine/Asset/Asset.h +++ b/src/Engine/Asset/Asset.h @@ -6,10 +6,47 @@ namespace Seele class Asset { public: + enum class Status + { + Uninitialized, + Loading, + Ready + }; Asset(); + Asset(const std::filesystem::path& path); + Asset(const std::string& directory, const std::string& name); + Asset(const std::string& fullPath); virtual ~Asset(); - + std::ifstream& getReadStream(); + std::ofstream& getWriteStream(); + + // returns the name of the file, without extension + std::string getFileName(); + // returns the full absolute path, from root to extension + std::string getFullPath(); + // returns the file extension, without preceding dot + std::string getExtension(); + inline Status getStatus() + { + std::scoped_lock lck(lock); + return status; + } + inline void setStatus(Status status) + { + std::scoped_lock lck(lock); + this->status = status; + } +protected: + std::mutex lock; private: + Status status; + std::filesystem::path fullPath; + std::filesystem::path parentDir; + std::filesystem::path name; + std::filesystem::path extension; + uint32 byteSize; + std::ifstream inStream; + std::ofstream outStream; }; DEFINE_REF(Asset); } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Asset/AssetRegistry.cpp b/src/Engine/Asset/AssetRegistry.cpp new file mode 100644 index 0000000..e6f9feb --- /dev/null +++ b/src/Engine/Asset/AssetRegistry.cpp @@ -0,0 +1,89 @@ +#include "AssetRegistry.h" +#include "MeshAsset.h" +#include "TextureAsset.h" +#include "TextureLoader.h" +#include "MaterialLoader.h" +#include "MeshLoader.h" +#include "Material/Material.h" +#include "Graphics/Graphics.h" +#include "graphics/WindowManager.h" + +using namespace Seele; + +AssetRegistry::~AssetRegistry() +{ +} + +void AssetRegistry::init(const std::string& rootFolder) +{ + get().init(rootFolder, WindowManager::getGraphics()); +} + +void AssetRegistry::importFile(const std::string &filePath) +{ + std::string extension = filePath.substr(filePath.find_last_of(".") + 1); + std::cout << extension << std::endl; + if (extension.compare("fbx") == 0 + || extension.compare("obj") == 0) + { + get().registerMesh(filePath); + } + if (extension.compare("png") == 0 + || extension.compare("jpg") == 0) + { + get().registerTexture(filePath); + } + if (extension.compare("semat") == 0) + { + get().registerMaterial(filePath); + } +} + +PMeshAsset AssetRegistry::findMesh(const std::string &filePath) +{ + return get().meshes[filePath]; +} + +PMaterialAsset AssetRegistry::findMaterial(const std::string &filePath) +{ + return get().materials[filePath]; +} + +PTextureAsset AssetRegistry::findTexture(const std::string &filePath) +{ + return get().textures[filePath]; +} + +AssetRegistry &AssetRegistry::get() +{ + static AssetRegistry instance; + return instance; +} + +AssetRegistry::AssetRegistry() +{ +} + +void AssetRegistry::init(const std::string &rootFolder, Gfx::PGraphics graphics) +{ + AssetRegistry ® = get(); + reg.rootFolder = rootFolder; + reg.meshLoader = new MeshLoader(graphics); + reg.textureLoader = new TextureLoader(graphics); + reg.materialLoader = new MaterialLoader(graphics); +} + +void AssetRegistry::registerMesh(const std::string &filePath) +{ + meshLoader->importAsset(filePath); +} + +void AssetRegistry::registerTexture(const std::string &filePath) +{ + textureLoader->importAsset(filePath); +} + +void AssetRegistry::registerMaterial(const std::string &filePath) +{ + materialLoader->queueAsset(filePath); +} \ No newline at end of file diff --git a/src/Engine/Asset/AssetRegistry.h b/src/Engine/Asset/AssetRegistry.h new file mode 100644 index 0000000..69a094a --- /dev/null +++ b/src/Engine/Asset/AssetRegistry.h @@ -0,0 +1,47 @@ +#pragma once +#include "MinimalEngine.h" +#include "Asset.h" +#include + +namespace Seele +{ +DECLARE_REF(TextureLoader); +DECLARE_REF(MeshLoader); +DECLARE_REF(MaterialLoader); +DECLARE_REF(TextureAsset); +DECLARE_REF(MeshAsset); +DECLARE_REF(MaterialAsset); +DECLARE_NAME_REF(Gfx, Graphics); +class AssetRegistry +{ +public: + ~AssetRegistry(); + static void init(const std::string& rootFolder); + + static void importFile(const std::string& filePath); + + static PMeshAsset findMesh(const std::string& filePath); + static PTextureAsset findTexture(const std::string& filePath); + static PMaterialAsset findMaterial(const std::string& filePath); +private: + static AssetRegistry& get(); + + AssetRegistry(); + void init(const std::string& rootFolder, Gfx::PGraphics graphics); + + void registerMesh(const std::string& filePath); + void registerTexture(const std::string& filePath); + void registerMaterial(const std::string& filePath); + + std::string rootFolder; + Map textures; + Map meshes; + Map materials; + UPTextureLoader textureLoader; + UPMeshLoader meshLoader; + UPMaterialLoader materialLoader; + friend class TextureLoader; + friend class MaterialLoader; + friend class MeshLoader; +}; +} \ No newline at end of file diff --git a/src/Engine/Asset/CMakeLists.txt b/src/Engine/Asset/CMakeLists.txt index b6522dc..b7305e3 100644 --- a/src/Engine/Asset/CMakeLists.txt +++ b/src/Engine/Asset/CMakeLists.txt @@ -2,5 +2,15 @@ target_sources(SeeleEngine PRIVATE Asset.h Asset.cpp - FileAsset.h - FileAsset.cpp) \ No newline at end of file + AssetRegistry.h + AssetRegistry.cpp + MaterialLoader.h + MaterialLoader.cpp + MeshAsset.h + MeshAsset.cpp + MeshLoader.h + MeshLoader.cpp + TextureAsset.h + TextureAsset.cpp + TextureLoader.h + TextureLoader.cpp) \ No newline at end of file diff --git a/src/Engine/Asset/FileAsset.cpp b/src/Engine/Asset/FileAsset.cpp deleted file mode 100644 index ae0c58c..0000000 --- a/src/Engine/Asset/FileAsset.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "FileAsset.h" - -using namespace Seele; - -FileAsset::FileAsset() - : path("") - , name("") -{ -} - -FileAsset::FileAsset(const std::string &fullPath) - : path(fullPath) -{ - name = fullPath.substr(fullPath.find_last_of('\\')+1); -} - -FileAsset::FileAsset(const std::string &directory, const std::string &name) - : path(directory+name) - , name(name) -{ -} - -FileAsset::~FileAsset() -{ -} - -std::ifstream &FileAsset::getReadStream() -{ - if(inStream.is_open()) - { - return inStream; - } - inStream.open(path); - return inStream; -} - -std::ofstream &FileAsset::getWriteStream() -{ - if(outStream.is_open()) - { - return outStream; - } - outStream.open(path); - return outStream; -} - -void FileAsset::rename(const std::string& newName) -{ - if(inStream.is_open()) - { - inStream.close(); - } - if(outStream.is_open()) - { - outStream.flush(); - outStream.close(); - } - path.replace(path.find_last_of(name), name.size(), newName); - name = newName; - inStream.open(path); - outStream.open(path); -} \ No newline at end of file diff --git a/src/Engine/Asset/FileAsset.h b/src/Engine/Asset/FileAsset.h deleted file mode 100644 index 3dc96fe..0000000 --- a/src/Engine/Asset/FileAsset.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include "Asset.h" -#include - -namespace Seele -{ -class FileAsset -{ -public: - FileAsset(); - FileAsset(const std::string& directory, const std::string& name); - FileAsset(const std::string& fullPath); - virtual ~FileAsset(); - std::ifstream& getReadStream(); - std::ofstream& getWriteStream(); - void rename(const std::string& newName); -private: - std::string name; - std::string path; - uint32 byteSize; - std::ifstream inStream; - std::ofstream outStream; -}; -} \ No newline at end of file diff --git a/src/Engine/Asset/MaterialLoader.cpp b/src/Engine/Asset/MaterialLoader.cpp new file mode 100644 index 0000000..b200cf6 --- /dev/null +++ b/src/Engine/Asset/MaterialLoader.cpp @@ -0,0 +1,22 @@ +#include "MaterialLoader.h" +#include "Material/Material.h" +#include "Graphics/Graphics.h" + +using namespace Seele; + +MaterialLoader::MaterialLoader(Gfx::PGraphics graphics) +{ + placeholderMaterial = new Material("shaders/Placeholder.semat"); + placeholderMaterial->compile(); +} + +MaterialLoader::~MaterialLoader() +{ +} + +PMaterial MaterialLoader::queueAsset(const std::string& filePath) +{ + PMaterial result = new Material(filePath); + //TODO + return result; +} diff --git a/src/Engine/Asset/MaterialLoader.h b/src/Engine/Asset/MaterialLoader.h new file mode 100644 index 0000000..37aa30f --- /dev/null +++ b/src/Engine/Asset/MaterialLoader.h @@ -0,0 +1,22 @@ +#pragma once +#include "MinimalEngine.h" +#include "Containers/List.h" +#include +#include + +namespace Seele +{ +DECLARE_REF(Material) +DECLARE_NAME_REF(Gfx, Graphics); +class MaterialLoader +{ +public: + MaterialLoader(Gfx::PGraphics graphic); + ~MaterialLoader(); + PMaterial queueAsset(const std::string& filePath); +private: + List> futures; + PMaterial placeholderMaterial; +}; +DEFINE_REF(MaterialLoader); +} // namespace Seele \ No newline at end of file diff --git a/src/Engine/Asset/MeshAsset.cpp b/src/Engine/Asset/MeshAsset.cpp new file mode 100644 index 0000000..80c6e29 --- /dev/null +++ b/src/Engine/Asset/MeshAsset.cpp @@ -0,0 +1,17 @@ +#include "MeshAsset.h" +#include "Graphics/Mesh.h" + +using namespace Seele; + + +MeshAsset::MeshAsset() +{ +} +MeshAsset::MeshAsset(const std::string& directory, const std::string& name) + : Asset(directory, name) +{ +} +MeshAsset::MeshAsset(const std::string& fullPath) + : Asset(fullPath) +{ +} \ No newline at end of file diff --git a/src/Engine/Asset/MeshAsset.h b/src/Engine/Asset/MeshAsset.h new file mode 100644 index 0000000..faf148f --- /dev/null +++ b/src/Engine/Asset/MeshAsset.h @@ -0,0 +1,22 @@ +#pragma once +#include "Asset.h" + +namespace Seele +{ +DECLARE_REF(Mesh); +class MeshAsset : public Asset +{ +public: + MeshAsset(); + MeshAsset(const std::string& directory, const std::string& name); + MeshAsset(const std::string& fullPath); + void setMesh(PMesh mesh) + { + std::scoped_lock lck(lock); + this->mesh = mesh; + } +private: + PMesh mesh; +}; +DEFINE_REF(MeshAsset); +} // namespace Seele \ No newline at end of file diff --git a/src/Engine/Asset/MeshLoader.cpp b/src/Engine/Asset/MeshLoader.cpp new file mode 100644 index 0000000..a478927 --- /dev/null +++ b/src/Engine/Asset/MeshLoader.cpp @@ -0,0 +1,61 @@ +#include "MeshLoader.h" +#include "Graphics/Graphics.h" +#include "MeshAsset.h" +#include "Graphics/Mesh.h" +#include +#include +#include + +using namespace Seele; + +MeshLoader::MeshLoader(Gfx::PGraphics graphics) + : graphics(graphics) +{ +} + +MeshLoader::~MeshLoader() +{ +} + +void MeshLoader::importAsset(const std::string& path) +{ + futures.add(std::async(std::launch::async, &MeshLoader::import, this, path)); +} + +void findMeshRoots(aiNode* node, List& meshNodes) +{ + if(node->mNumMeshes > 0) + { + meshNodes.add(node); + return; + } + for(uint32 i = 0; i < node->mNumChildren; ++i) + { + findMeshRoots(node->mChildren[i], meshNodes); + } +} + +void MeshLoader::import(const std::string& path) +{ + PMeshAsset asset = new MeshAsset(path); + asset->setStatus(Asset::Status::Loading); + Assimp::Importer importer; + const aiScene* scene = importer.ReadFile(path.c_str(), + aiProcess_CalcTangentSpace | + aiProcess_FlipUVs | + aiProcess_ImproveCacheLocality | + aiProcess_OptimizeMeshes | + aiProcess_GenBoundingBoxes | + aiProcessPreset_TargetRealtime_Fast); + + List meshNodes; + findMeshRoots(scene->mRootNode, meshNodes); + for(auto meshNode : meshNodes) + { + std::cout << "Test:" << meshNode->mNumMeshes << std::endl; + } + + PMesh mesh = new Mesh(nullptr, nullptr); + asset->setMesh(mesh); + asset->setStatus(Asset::Status::Ready); +} diff --git a/src/Engine/Asset/MeshLoader.h b/src/Engine/Asset/MeshLoader.h new file mode 100644 index 0000000..4d6c62a --- /dev/null +++ b/src/Engine/Asset/MeshLoader.h @@ -0,0 +1,23 @@ +#pragma once +#include "MinimalEngine.h" +#include "Containers/List.h" +#include +#include + +namespace Seele +{ +DECLARE_REF(MeshAsset) +DECLARE_NAME_REF(Gfx, Graphics); +class MeshLoader +{ +public: + MeshLoader(Gfx::PGraphics graphic); + ~MeshLoader(); + void importAsset(const std::string& filePath); +private: + void import(const std::string& path); + List> futures; + Gfx::PGraphics graphics; +}; +DEFINE_REF(MeshLoader); +} // namespace Seele \ No newline at end of file diff --git a/src/Engine/Asset/TextureAsset.cpp b/src/Engine/Asset/TextureAsset.cpp new file mode 100644 index 0000000..7c39ced --- /dev/null +++ b/src/Engine/Asset/TextureAsset.cpp @@ -0,0 +1,17 @@ +#include "TextureAsset.h" +#include "Graphics/GraphicsResources.h" + +using namespace Seele; + + +TextureAsset::TextureAsset() +{ +} +TextureAsset::TextureAsset(const std::string& directory, const std::string& name) + : Asset(directory, name) +{ +} +TextureAsset::TextureAsset(const std::string& fullPath) + : Asset(fullPath) +{ +} \ No newline at end of file diff --git a/src/Engine/Asset/TextureAsset.h b/src/Engine/Asset/TextureAsset.h new file mode 100644 index 0000000..4c41067 --- /dev/null +++ b/src/Engine/Asset/TextureAsset.h @@ -0,0 +1,25 @@ +#include "Asset.h" + +namespace Seele +{ +DECLARE_NAME_REF(Gfx, Texture); +class TextureAsset : public Asset +{ +public: + TextureAsset(); + TextureAsset(const std::string& directory, const std::string& name); + TextureAsset(const std::string& fullPath); + void setTexture(Gfx::PTexture texture) + { + std::scoped_lock lck(lock); + this->texture = texture; + } + Gfx::PTexture getTexture() + { + return texture; + } +private: + Gfx::PTexture texture; +}; +DEFINE_REF(TextureAsset); +} // namespace Seele diff --git a/src/Engine/Asset/TextureLoader.cpp b/src/Engine/Asset/TextureLoader.cpp new file mode 100644 index 0000000..1ad11e2 --- /dev/null +++ b/src/Engine/Asset/TextureLoader.cpp @@ -0,0 +1,61 @@ +#include "TextureLoader.h" +#include "TextureAsset.h" +#include "Graphics/Graphics.h" +#include "AssetRegistry.h" +#define STB_IMAGE_IMPLEMENTATION +#include + +using namespace Seele; + +TextureLoader::TextureLoader(Gfx::PGraphics graphics) + : graphics(graphics) +{ + import("./textures/placeholder.png"); + placeholderTexture = AssetRegistry::findTexture("./textures/placeholder.png"); +} + +TextureLoader::~TextureLoader() +{ +} + +void TextureLoader::importAsset(const std::string& filePath) +{ + futures.add(std::async(std::launch::async, &TextureLoader::import, this, filePath)); +} + +void TextureLoader::import(const std::string& path) +{ + PTextureAsset asset = new TextureAsset(path); + AssetRegistry::get().textures[path] = asset; + asset->setStatus(Asset::Status::Loading); + int x, y, n; + const std::string fullPath = std::string(asset->getFullPath()); + unsigned char* data = stbi_load(fullPath.c_str(), &x, &y, &n, 0); + TextureCreateInfo createInfo; + createInfo.resourceData.data = data; + createInfo.resourceData.size = x * y * n * sizeof(unsigned char); + createInfo.width = x; + createInfo.height = y; + switch (n) + { + case 1: + createInfo.format = Gfx::SE_FORMAT_R8_UINT; + break; + case 2: + createInfo.format = Gfx::SE_FORMAT_R8G8_UINT; + break; + case 3: + createInfo.format = Gfx::SE_FORMAT_R8G8B8_UINT; + break; + case 4: + createInfo.format = Gfx::SE_FORMAT_R8G8B8A8_UINT; + break; + default: + break; + } + createInfo.resourceData.owner = Gfx::QueueType::DEDICATED_TRANSFER; + Gfx::PTexture2D texture = graphics->createTexture2D(createInfo); + texture->transferOwnership(Gfx::QueueType::GRAPHICS); + asset->setTexture(texture); + asset->setStatus(Asset::Status::Ready); +} \ No newline at end of file diff --git a/src/Engine/Asset/TextureLoader.h b/src/Engine/Asset/TextureLoader.h new file mode 100644 index 0000000..b84acab --- /dev/null +++ b/src/Engine/Asset/TextureLoader.h @@ -0,0 +1,24 @@ +#pragma once +#include "MinimalEngine.h" +#include "Containers/List.h" +#include +#include + +namespace Seele +{ +DECLARE_REF(TextureAsset); +DECLARE_NAME_REF(Gfx, Graphics); +class TextureLoader +{ +public: + TextureLoader(Gfx::PGraphics graphic); + ~TextureLoader(); + void importAsset(const std::string& filePath); +private: + void import(const std::string& path); + Gfx::PGraphics graphics; + List> futures; + PTextureAsset placeholderTexture; +}; +DEFINE_REF(TextureLoader); +} // namespace Seele \ No newline at end of file diff --git a/src/Engine/CMakeLists.txt b/src/Engine/CMakeLists.txt index a542c96..58ae880 100644 --- a/src/Engine/CMakeLists.txt +++ b/src/Engine/CMakeLists.txt @@ -9,4 +9,4 @@ add_subdirectory(Containers/) add_subdirectory(Graphics/) add_subdirectory(Material/) add_subdirectory(Math/) -add_subdirectory(Scene/) \ No newline at end of file +add_subdirectory(Scene/) diff --git a/src/Engine/Containers/Array.h b/src/Engine/Containers/Array.h index 9d9e327..fe17291 100644 --- a/src/Engine/Containers/Array.h +++ b/src/Engine/Containers/Array.h @@ -385,6 +385,11 @@ public: assert(index >= 0 && index < N); return _data[index]; } + const T &operator[](int index) const + { + assert(index >= 0 && index < N); + return _data[index]; + } template class IteratorBase diff --git a/src/Engine/Containers/List.h b/src/Engine/Containers/List.h index 39796f4..7bbb97f 100644 --- a/src/Engine/Containers/List.h +++ b/src/Engine/Containers/List.h @@ -132,6 +132,24 @@ public: size++; return insertedElement; } + Iterator add(T&& value) + { + if (root == nullptr) + { + root = new Node(); + tail = root; + } + tail->data = std::move(value); + Node *newTail = new Node(); + newTail->prev = tail; + newTail->next = nullptr; + tail->next = newTail; + Iterator insertedElement(tail); + tail = newTail; + refreshIterators(); + size++; + return insertedElement; + } Iterator remove(Iterator pos) { size--; diff --git a/src/Engine/Containers/Map.h b/src/Engine/Containers/Map.h index d3db5de..84db3ef 100644 --- a/src/Engine/Containers/Map.h +++ b/src/Engine/Containers/Map.h @@ -141,6 +141,7 @@ public: Node *node; Array traversal; }; + V &operator[](const K &key) { root = splay(root, key); diff --git a/src/Engine/Graphics/CMakeLists.txt b/src/Engine/Graphics/CMakeLists.txt index ae599af..96d1029 100644 --- a/src/Engine/Graphics/CMakeLists.txt +++ b/src/Engine/Graphics/CMakeLists.txt @@ -1,7 +1,5 @@ target_sources(SeeleEngine PRIVATE - ForwardPlusRenderPath.h - ForwardPlusRenderPath.cpp GraphicsResources.h GraphicsResources.cpp GraphicsInitializer.h @@ -10,6 +8,7 @@ target_sources(SeeleEngine Graphics.cpp Mesh.h Mesh.cpp + MeshBatch.h RenderCore.h RenderCore.cpp RenderPath.h @@ -25,4 +24,5 @@ target_sources(SeeleEngine WindowManager.h WindowManager.cpp) +add_subdirectory(RenderPass/) add_subdirectory(Vulkan/) \ No newline at end of file diff --git a/src/Engine/Graphics/ForwardPlusRenderPath.cpp b/src/Engine/Graphics/ForwardPlusRenderPath.cpp deleted file mode 100644 index 39267f0..0000000 --- a/src/Engine/Graphics/ForwardPlusRenderPath.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "ForwardPlusRenderPath.h" -#include "Scene/Scene.h" -#include "Material/MaterialInstance.h" -#include "Material/Material.h" -#include "GraphicsResources.h" - -using namespace Seele; - -Seele::ForwardPlusRenderPath::ForwardPlusRenderPath(Gfx::PGraphics graphics, Gfx::PViewport viewport) - : SceneRenderPath(graphics, viewport) -{ - PMaterial material = new Material("D:\\Private\\Programming\\C++\\Seele\\test.mat"); - material->compile(); -} - -Seele::ForwardPlusRenderPath::~ForwardPlusRenderPath() -{ -} - -void Seele::ForwardPlusRenderPath::beginFrame() -{ -} - -void Seele::ForwardPlusRenderPath::render() -{ - for (auto entry : scene->getMeshBatches()) - { - PMaterial material = entry.key; - Gfx::PRenderCommand renderCommand = graphics->createRenderCommand(); - renderCommand->bindPipeline(material->getPipeline()); - for (auto drawState : entry.value.instances) - { - renderCommand->bindVertexBuffer(drawState.vertexBuffer); - renderCommand->bindIndexBuffer(drawState.indexBuffer); - renderCommand->bindDescriptor(drawState.instance->getDescriptor()); - renderCommand->draw(drawState); - } - } -} - -void Seele::ForwardPlusRenderPath::endFrame() -{ -} diff --git a/src/Engine/Graphics/ForwardPlusRenderPath.h b/src/Engine/Graphics/ForwardPlusRenderPath.h deleted file mode 100644 index 13b08bc..0000000 --- a/src/Engine/Graphics/ForwardPlusRenderPath.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "SceneRenderPath.h" - -namespace Seele -{ -class ForwardPlusRenderPath : public SceneRenderPath -{ -public: - ForwardPlusRenderPath(Gfx::PGraphics graphics, Gfx::PViewport target); - virtual ~ForwardPlusRenderPath(); - virtual void beginFrame() override; - virtual void render() override; - virtual void endFrame() override; - -private: -}; -} // namespace Seele \ No newline at end of file diff --git a/src/Engine/Graphics/Graphics.h b/src/Engine/Graphics/Graphics.h index 41945ba..7a2b603 100644 --- a/src/Engine/Graphics/Graphics.h +++ b/src/Engine/Graphics/Graphics.h @@ -13,6 +13,12 @@ public: Graphics(); virtual ~Graphics(); virtual void init(GraphicsInitializer initializer) = 0; + + const QueueFamilyMapping getFamilyMapping() const + { + return queueMapping; + } + virtual PWindow createWindow(const WindowCreateInfo &createInfo) = 0; virtual PViewport createViewport(PWindow owner, const ViewportCreateInfo &createInfo) = 0; @@ -28,8 +34,18 @@ public: virtual PVertexBuffer createVertexBuffer(const VertexBufferCreateInfo &bulkData) = 0; virtual PIndexBuffer createIndexBuffer(const IndexBufferCreateInfo &bulkData) = 0; virtual PRenderCommand createRenderCommand() = 0; + virtual PVertexShader createVertexShader(const ShaderCreateInfo& createInfo) = 0; + virtual PControlShader createControlShader(const ShaderCreateInfo& createInfo) = 0; + virtual PEvaluationShader createEvaluationShader(const ShaderCreateInfo& createInfo) = 0; + virtual PGeometryShader createGeometryShader(const ShaderCreateInfo& createInfo) = 0; + virtual PFragmentShader createFragmentShader(const ShaderCreateInfo& createInfo) = 0; virtual PGraphicsPipeline createGraphicsPipeline(const GraphicsPipelineCreateInfo& createInfo) = 0; + + virtual Gfx::PDescriptorLayout createDescriptorLayout() = 0; + virtual Gfx::PPipelineLayout createPipelineLayout() = 0; + protected: + QueueFamilyMapping queueMapping; friend class Window; }; DEFINE_REF(Graphics); diff --git a/src/Engine/Graphics/GraphicsInitializer.h b/src/Engine/Graphics/GraphicsInitializer.h index e6c2ce5..8e40661 100644 --- a/src/Engine/Graphics/GraphicsInitializer.h +++ b/src/Engine/Graphics/GraphicsInitializer.h @@ -1,3 +1,4 @@ +#pragma once #include "GraphicsEnums.h" namespace Seele @@ -42,8 +43,20 @@ struct ViewportCreateInfo uint32 offsetX; uint32 offsetY; }; +// doesnt own the data, only proxy it +struct BulkResourceData +{ + uint32 size; + uint8 *data; + Gfx::QueueType owner; + BulkResourceData() + : size(0), data(nullptr), owner(Gfx::QueueType::GRAPHICS) + { + } +}; struct TextureCreateInfo { + BulkResourceData resourceData; uint32 width; uint32 height; uint32 depth; @@ -53,20 +66,10 @@ struct TextureCreateInfo uint32 samples; Gfx::SeFormat format; Gfx::SeImageUsageFlagBits usage; - Gfx::QueueType queueType; TextureCreateInfo() - : width(1), height(1), depth(1), bArray(false), arrayLayers(1), mipLevels(1), samples(1), format(Gfx::SE_FORMAT_R32G32B32A32_SFLOAT), queueType(Gfx::QueueType::GRAPHICS), usage(Gfx::SE_IMAGE_USAGE_SAMPLED_BIT) - { - } -}; -// doesnt own the data, only proxy it -struct BulkResourceData -{ - uint32 size; - uint8 *data; - Gfx::QueueType owner; - BulkResourceData() - : size(0), data(nullptr), owner(Gfx::QueueType::GRAPHICS) + : resourceData(), width(1), height(1), depth(1), bArray(false), arrayLayers(1) + , mipLevels(1), samples(1), format(Gfx::SE_FORMAT_R32G32B32A32_SFLOAT) + , usage(Gfx::SE_IMAGE_USAGE_SAMPLED_BIT) { } }; @@ -90,6 +93,15 @@ struct IndexBufferCreateInfo { } }; +struct ShaderCreateInfo +{ + std::string code; + std::string entryPoint; + Array typeParameter; + ShaderCreateInfo(const std::string& code) + : code(code) + {} +}; namespace Gfx { @@ -101,6 +113,10 @@ struct SePushConstantRange }; struct VertexElement { + VertexElement(){} + VertexElement(uint32 location, SeFormat vertexFormat, uint32 offset) + : location(location), vertexFormat(vertexFormat), offset(offset) + {} uint32 location; SeFormat vertexFormat; uint32 offset; @@ -173,7 +189,6 @@ struct GraphicsPipelineCreateInfo Gfx::PEvaluationShader evalShader; Gfx::PGeometryShader geometryShader; Gfx::PFragmentShader fragmentShader; - Gfx::PPipelineLayout pipelineLayout; Gfx::PRenderPass renderPass; Gfx::SePrimitiveTopology topology; Gfx::RasterizationState rasterizationState; @@ -183,6 +198,23 @@ struct GraphicsPipelineCreateInfo GraphicsPipelineCreateInfo() { std::memset(this, 0, sizeof(*this)); + topology = Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + rasterizationState.cullMode = Gfx::SE_CULL_MODE_BACK_BIT; + rasterizationState.polygonMode = Gfx::SE_POLYGON_MODE_FILL; + rasterizationState.frontFace = Gfx::SE_FRONT_FACE_COUNTER_CLOCKWISE; + depthStencilState.depthCompareOp = Gfx::SE_COMPARE_OP_LESS; + depthStencilState.minDepthBounds = 0.0f; + depthStencilState.maxDepthBounds = 1.0f; + depthStencilState.stencilTestEnable = false; + depthStencilState.depthWriteEnable = true; + depthStencilState.depthTestEnable = true; + multisampleState.samples = 1; + colorBlend.attachmentCount = 0; + colorBlend.logicOpEnable = false; + colorBlend.blendConstants[0] = 1.0f; + colorBlend.blendConstants[1] = 1.0f; + colorBlend.blendConstants[2] = 1.0f; + colorBlend.blendConstants[3] = 1.0f; } }; } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Graphics/GraphicsResources.cpp b/src/Engine/Graphics/GraphicsResources.cpp index dfee69b..50e3983 100644 --- a/src/Engine/Graphics/GraphicsResources.cpp +++ b/src/Engine/Graphics/GraphicsResources.cpp @@ -1,5 +1,6 @@ #include "GraphicsResources.h" #include "Material/MaterialInstance.h" +#include "Graphics.h" using namespace Seele; using namespace Seele::Gfx; @@ -56,22 +57,60 @@ void PipelineLayout::addPushConstants(const SePushConstantRange &pushConstant) pushConstants.add(pushConstant); } -UniformBuffer::UniformBuffer() +QueueOwnedResource::QueueOwnedResource(PGraphics graphics, QueueType startQueueType) + : graphics(graphics) + , currentOwner(startQueueType) +{ +} + +QueueOwnedResource::~QueueOwnedResource() +{ +} + +void QueueOwnedResource::transferOwnership(QueueType newOwner) +{ + if(graphics->getFamilyMapping().needsTransfer(currentOwner, newOwner)) + { + executeOwnershipBarrier(newOwner); + currentOwner = newOwner; + } +} + +Buffer::Buffer(PGraphics graphics, QueueType startQueue) + : QueueOwnedResource(graphics, startQueue) +{ +} + +Buffer::~Buffer() +{ +} + +UniformBuffer::UniformBuffer(PGraphics graphics, QueueType startQueueType) + : Buffer(graphics, startQueueType) { } UniformBuffer::~UniformBuffer() { } -VertexBuffer::VertexBuffer(uint32 numVertices, uint32 vertexSize) - : numVertices(numVertices), vertexSize(vertexSize) +StructuredBuffer::StructuredBuffer(PGraphics graphics, QueueType startQueueType) + : Buffer(graphics, startQueueType) +{ +} +StructuredBuffer::~StructuredBuffer() +{ +} +VertexBuffer::VertexBuffer(PGraphics graphics, uint32 numVertices, uint32 vertexSize, QueueType startQueueType) + : Buffer(graphics, startQueueType) + , numVertices(numVertices), vertexSize(vertexSize) { } VertexBuffer::~VertexBuffer() { } -IndexBuffer::IndexBuffer(uint32 size, Gfx::SeIndexType indexType) - : indexType(indexType) +IndexBuffer::IndexBuffer(PGraphics graphics, uint32 size, Gfx::SeIndexType indexType, QueueType startQueueType) + : Buffer(graphics, startQueueType) + , indexType(indexType) { switch (indexType) { @@ -87,9 +126,8 @@ IndexBuffer::IndexBuffer(uint32 size, Gfx::SeIndexType indexType) IndexBuffer::~IndexBuffer() { } -VertexStream::VertexStream(PVertexBuffer buffer, uint8 instanced) - : buffer(buffer) - , instanced(instanced) +VertexStream::VertexStream(uint32 stride, uint8 instanced) + : stride(stride), instanced(instanced) { } VertexStream::~VertexStream() @@ -103,11 +141,6 @@ const Array VertexStream::getVertexDescriptions() const { return vertexDescription; } -Gfx::PVertexBuffer VertexStream::getVertexBuffer() -{ - return buffer; -} - VertexDeclaration::VertexDeclaration() { } @@ -125,6 +158,32 @@ const Array &VertexDeclaration::getVertexStreams() const return vertexStreams; } +Texture::Texture(PGraphics graphics, Gfx::QueueType startQueueType) + : QueueOwnedResource(graphics, startQueueType) +{ +} + +Texture::~Texture() +{ +} + +Texture2D::Texture2D(PGraphics graphics, Gfx::QueueType startQueueType) + : Texture(graphics, startQueueType) +{ +} + +Texture2D::~Texture2D() +{ +} + +RenderCommand::RenderCommand() +{ +} + +RenderCommand::~RenderCommand() +{ +} + RenderTargetLayout::RenderTargetLayout() : inputAttachments(), colorAttachments(), depthAttachment() { diff --git a/src/Engine/Graphics/GraphicsResources.h b/src/Engine/Graphics/GraphicsResources.h index 9366385..5648f4c 100644 --- a/src/Engine/Graphics/GraphicsResources.h +++ b/src/Engine/Graphics/GraphicsResources.h @@ -5,6 +5,7 @@ #include "Math/MemCRC.h" #include "Material/MaterialInstance.h" #include "GraphicsInitializer.h" +#include "MeshBatch.h" #ifdef _DEBUG #define ENABLE_VALIDATION @@ -13,34 +14,10 @@ namespace Seele { -DECLARE_NAME_REF(Gfx, VertexBuffer); -DECLARE_NAME_REF(Gfx, IndexBuffer); -struct DrawInstance -{ - Matrix4 modelMatrix; - PMaterialInstance instance; - Gfx::PIndexBuffer indexBuffer; - Gfx::PVertexBuffer vertexBuffer; - - uint32 numInstances; - uint32 baseVertexIndex; - uint32 minVertexIndex; - uint32 firstInstance; - DrawInstance() - : instance(nullptr), indexBuffer(nullptr), vertexBuffer(nullptr), modelMatrix(1), numInstances(1), baseVertexIndex(0), minVertexIndex(0), firstInstance(0) - { - } -}; -struct DrawState -{ - Array instances; - - DrawState() - { - } -}; namespace Gfx { +DECLARE_REF(Graphics); + class SamplerState { public: @@ -182,6 +159,7 @@ public: PipelineLayout() {} virtual ~PipelineLayout() {} virtual void create() = 0; + virtual void reset() = 0; void addDescriptorLayout(uint32 setIndex, PDescriptorLayout layout); void addPushConstants(const SePushConstantRange &pushConstants); virtual uint32 getHash() const = 0; @@ -191,17 +169,79 @@ protected: Array pushConstants; }; DEFINE_REF(PipelineLayout); -class UniformBuffer + +struct QueueFamilyMapping +{ + uint32 graphicsFamily; + uint32 computeFamily; + uint32 transferFamily; + uint32 dedicatedTransferFamily; + uint32 getQueueTypeFamilyIndex(Gfx::QueueType type) const + { + switch (type) + { + case Gfx::QueueType::GRAPHICS: + return graphicsFamily; + case Gfx::QueueType::COMPUTE: + return computeFamily; + case Gfx::QueueType::TRANSFER: + return transferFamily; + case Gfx::QueueType::DEDICATED_TRANSFER: + return dedicatedTransferFamily; + default: + return 0x7fff; + } + } + bool needsTransfer(Gfx::QueueType src, Gfx::QueueType dst) const + { + uint32 srcIndex = getQueueTypeFamilyIndex(src); + uint32 dstIndex = getQueueTypeFamilyIndex(dst); + return srcIndex != dstIndex; + } +}; + +class QueueOwnedResource { public: - UniformBuffer(); + QueueOwnedResource(PGraphics graphics, QueueType startQueueType); + virtual ~QueueOwnedResource(); + + //Preliminary checks to see if the barrier should be executed at all + void transferOwnership(QueueType newOwner); + +protected: + virtual void executeOwnershipBarrier(QueueType newOwner) = 0; + Gfx::QueueType currentOwner; + PGraphics graphics; +}; +DEFINE_REF(QueueOwnedResource); + +class Buffer : public QueueOwnedResource +{ +public: + Buffer(PGraphics graphics, QueueType startQueueType); + virtual ~Buffer(); + +protected: + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(QueueType newOwner) = 0; +}; + +class UniformBuffer : public Buffer +{ +public: + UniformBuffer(PGraphics graphics, QueueType startQueueType); virtual ~UniformBuffer(); +protected: + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(QueueType newOwner) = 0; }; DEFINE_REF(UniformBuffer); -class VertexBuffer + +class VertexBuffer : public Buffer { public: - VertexBuffer(uint32 numVertices, uint32 vertexSize); + VertexBuffer(PGraphics graphics, uint32 numVertices, uint32 vertexSize, QueueType startQueueType); virtual ~VertexBuffer(); inline uint32 getNumVertices() { @@ -214,14 +254,17 @@ public: } protected: + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(QueueType newOwner) = 0; uint32 numVertices; uint32 vertexSize; }; DEFINE_REF(VertexBuffer); -class IndexBuffer + +class IndexBuffer : public Buffer { public: - IndexBuffer(uint32 size, Gfx::SeIndexType index); + IndexBuffer(PGraphics graphics, uint32 size, Gfx::SeIndexType index, QueueType startQueueType); virtual ~IndexBuffer(); inline uint32 getNumIndices() const { @@ -233,34 +276,41 @@ public: } protected: + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(QueueType newOwner) = 0; Gfx::SeIndexType indexType; uint32 numIndices; }; DEFINE_REF(IndexBuffer); -class StructuredBuffer + +class StructuredBuffer : public Buffer { public: - virtual ~StructuredBuffer() - { - } + StructuredBuffer(PGraphics graphics, QueueType startQueueType); + virtual ~StructuredBuffer(); +protected: + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(QueueType newOwner) = 0; }; DEFINE_REF(StructuredBuffer); + class VertexStream { public: VertexStream() {} - VertexStream(PVertexBuffer buffer, uint8 instanced); + VertexStream(uint32 stride, uint8 instanced); ~VertexStream(); void addVertexElement(VertexElement element); const Array getVertexDescriptions() const; - PVertexBuffer getVertexBuffer(); inline uint8 isInstanced() const { return instanced; } -private: - PVertexBuffer buffer; + uint32 stride; + uint32 offset; Array vertexDescription; uint8 instanced; + PVertexBuffer vertexBuffer; }; +DEFINE_REF(VertexStream); class VertexDeclaration { public: @@ -276,41 +326,46 @@ DEFINE_REF(VertexDeclaration); class GraphicsPipeline { public: - GraphicsPipeline(const GraphicsPipelineCreateInfo& createInfo) : createInfo(createInfo) {} + GraphicsPipeline(const GraphicsPipelineCreateInfo& createInfo, PPipelineLayout layout) : createInfo(createInfo) , layout(layout) {} virtual ~GraphicsPipeline(){} const GraphicsPipelineCreateInfo& getCreateInfo() const {return createInfo;} + PPipelineLayout getPipelineLayout() const { return layout; } protected: + PPipelineLayout layout; GraphicsPipelineCreateInfo createInfo; }; DEFINE_REF(GraphicsPipeline); -class Texture +class Texture : public QueueOwnedResource { public: - virtual ~Texture() - { - } + Texture(PGraphics graphics, QueueType startQueueType); + virtual ~Texture(); +protected: + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(QueueType newOwner) = 0; }; DEFINE_REF(Texture); class Texture2D : public Texture { public: - virtual ~Texture2D() - { - } + Texture2D(PGraphics graphics, QueueType startQueueType); + virtual ~Texture2D(); +protected: + //Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(QueueType newOwner) = 0; }; DEFINE_REF(Texture2D); class RenderCommand { public: - virtual ~RenderCommand() - { - } + RenderCommand(); + virtual ~RenderCommand(); virtual void bindPipeline(Gfx::PGraphicsPipeline pipeline) = 0; virtual void bindDescriptor(Gfx::PDescriptorSet set) = 0; virtual void bindVertexBuffer(Gfx::PVertexBuffer vertexBuffer) = 0; virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) = 0; - virtual void draw(DrawInstance data) = 0; + virtual void draw(const MeshBatchElement& data) = 0; }; DEFINE_REF(RenderCommand); diff --git a/src/Engine/Graphics/Mesh.cpp b/src/Engine/Graphics/Mesh.cpp index 49582af..36082dd 100644 --- a/src/Engine/Graphics/Mesh.cpp +++ b/src/Engine/Graphics/Mesh.cpp @@ -1 +1,13 @@ #include "Mesh.h" + +using namespace Seele; + +Mesh::Mesh(Gfx::PVertexBuffer vertexBuffer, Gfx::PIndexBuffer indexBuffer) + : vertexBuffer(vertexBuffer) + , indexBuffer(indexBuffer) +{ +} + +Mesh::~Mesh() +{ +} \ No newline at end of file diff --git a/src/Engine/Graphics/Mesh.h b/src/Engine/Graphics/Mesh.h index d94a27c..14fa4ff 100644 --- a/src/Engine/Graphics/Mesh.h +++ b/src/Engine/Graphics/Mesh.h @@ -10,7 +10,8 @@ public: ~Mesh(); private: - Gfx::VertexBuffer vertexBuffer; - Gfx::IndexBuffer indexBuffer; + Gfx::PVertexBuffer vertexBuffer; + Gfx::PIndexBuffer indexBuffer; }; +DEFINE_REF(Mesh); } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Graphics/MeshBatch.h b/src/Engine/Graphics/MeshBatch.h new file mode 100644 index 0000000..282f395 --- /dev/null +++ b/src/Engine/Graphics/MeshBatch.h @@ -0,0 +1,97 @@ +#pragma once + +namespace Seele +{ +DECLARE_NAME_REF(Gfx, VertexBuffer); +DECLARE_NAME_REF(Gfx, IndexBuffer); +DECLARE_NAME_REF(Gfx, UniformBuffer); +DECLARE_REF(Material); +DECLARE_REF(VertexFactory); +struct MeshBatchElement +{ +public: + Gfx::PUniformBuffer uniformBuffer; + Gfx::PIndexBuffer indexBuffer; + + union + { + uint32* instanceRuns; + }; + + + uint32 firstIndex; + uint32 numPrimitives; + + uint32 numInstances; + uint32 baseVertexIndex; + uint32 minVertexIndex; + uint32 maxVertexIndex; + + uint8 isInstanced : 1; + Gfx::PVertexBuffer indirectArgsBuffer; + MeshBatchElement() + : uniformBuffer(nullptr) + , indexBuffer(nullptr) + , indirectArgsBuffer(nullptr) + , firstIndex(0) + , numPrimitives(0) + , numInstances(1) + , baseVertexIndex(0) + , minVertexIndex(0) + , maxVertexIndex(0) + {} +}; +struct MeshBatch +{ + Array elements; + + uint8 useReverseCulling : 1; + uint8 isBackfaceCullingDisabled : 1; + uint8 isCastingShadow : 1; + uint8 useWireframe : 1; + + const Gfx::SePrimitiveTopology topology; + + const PVertexFactory vertexFactory; + + const PMaterial material; + + inline int32 getNumPrimitives() const + { + int32 count = 0; + for(uint32 index = 0; index < elements.size(); ++index) + { + if(elements[index].isInstanced && elements[index].instanceRuns) + { + for(uint32 run = 0; run < elements[index].numInstances; ++run) + { + count += elements[index].numPrimitives * (elements[index].instanceRuns[run * 2 + 1] - elements[index].instanceRuns[run * 2] - 1); + } + } + else + { + count += elements[index].numPrimitives * elements[index].numInstances; + } + } + return count; + } + + MeshBatch() + : useReverseCulling(false) + , isBackfaceCullingDisabled(false) + , isCastingShadow(true) + , useWireframe(false) + , vertexFactory(nullptr) + , material(nullptr) + , topology(Gfx::SE_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) + { + elements.add(); + } +}; +DECLARE_REF(PrimitiveComponent); +struct StaticMeshBatch : public MeshBatch +{ + uint32 index; + PPrimitiveComponent primitiveComponent; +}; +} // namespace Seele diff --git a/src/Engine/Graphics/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/Engine/Graphics/RenderPass/BasePass.h b/src/Engine/Graphics/RenderPass/BasePass.h new file mode 100644 index 0000000..b6661be --- /dev/null +++ b/src/Engine/Graphics/RenderPass/BasePass.h @@ -0,0 +1,15 @@ +#pragma once +#include "MinimalEngine.h" + +namespace Seele +{ +class BasePass +{ +public: + BasePass(); + ~BasePass(); + +private: + +}; +} // namespace Seele diff --git a/src/Engine/Graphics/RenderPass/CMakeLists.txt b/src/Engine/Graphics/RenderPass/CMakeLists.txt new file mode 100644 index 0000000..bb588ce --- /dev/null +++ b/src/Engine/Graphics/RenderPass/CMakeLists.txt @@ -0,0 +1,10 @@ +target_sources(SeeleEngine + PRIVATE + BasePass.h + BasePass.cpp + DepthPrepass.h + DepthPrepass.cpp + MeshProcessor.h + MeshProcessor.cpp + VertexFactory.h + VertexFactory.cpp) \ No newline at end of file diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.cpp b/src/Engine/Graphics/RenderPass/DepthPrepass.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.h b/src/Engine/Graphics/RenderPass/DepthPrepass.h new file mode 100644 index 0000000..e69de29 diff --git a/src/Engine/Graphics/RenderPass/MeshProcessor.cpp b/src/Engine/Graphics/RenderPass/MeshProcessor.cpp new file mode 100644 index 0000000..1a9e41c --- /dev/null +++ b/src/Engine/Graphics/RenderPass/MeshProcessor.cpp @@ -0,0 +1,54 @@ +#include "MeshProcessor.h" +#include "Graphics/Graphics.h" +#include "VertexFactory.h" + +using namespace Seele; + +MeshProcessor::MeshProcessor(const PScene scene, Gfx::PGraphics graphics) + : scene(scene) + , graphics(graphics) +{ + +} + +MeshProcessor::~MeshProcessor() +{ +} + +void MeshProcessor::buildMeshDrawCommands( + const MeshBatch& meshBatch, + const PPrimitiveComponent primitiveComponent, + PMaterial material, + Gfx::PVertexShader vertexShader, + Gfx::PControlShader controlShader, + Gfx::PEvaluationShader evaluationShader, + Gfx::PGeometryShader geometryShader, + Gfx::PFragmentShader fragmentShader, + bool positionOnly) +{ + const PVertexFactory vertexFactory = meshBatch.vertexFactory; + + GraphicsPipelineCreateInfo pipelineInitializer; + pipelineInitializer.topology = meshBatch.topology; + Gfx::PVertexDeclaration vertexDecl = positionOnly ? vertexFactory->getPositionDeclaration() : vertexFactory->getDeclaration(); + pipelineInitializer.vertexDeclaration = vertexDecl; + pipelineInitializer.vertexShader = vertexShader; + pipelineInitializer.controlShader = controlShader; + pipelineInitializer.evalShader = evaluationShader; + pipelineInitializer.geometryShader = geometryShader; + pipelineInitializer.fragmentShader = fragmentShader; + + VertexInputStreamArray vertexStreams; + if(positionOnly) + { + vertexFactory->getPositionOnlyStream(vertexStreams); + } + else + { + vertexFactory->getStreams(vertexStreams); + } + if(vertexShader != nullptr) + { + + } +} \ No newline at end of file diff --git a/src/Engine/Graphics/RenderPass/MeshProcessor.h b/src/Engine/Graphics/RenderPass/MeshProcessor.h new file mode 100644 index 0000000..4025071 --- /dev/null +++ b/src/Engine/Graphics/RenderPass/MeshProcessor.h @@ -0,0 +1,32 @@ +#pragma once +#include "MinimalEngine.h" +#include "Scene/Scene.h" +#include "Graphics/GraphicsResources.h" +#include "Graphics/MeshBatch.h" + +namespace Seele +{ +class MeshProcessor +{ +public: + MeshProcessor(const PScene scene, Gfx::PGraphics graphics); + virtual ~MeshProcessor(); +private: + PScene scene; + Gfx::PGraphics graphics; + virtual void addMeshBatch( + const MeshBatch& meshBatch, + const PPrimitiveComponent primitiveComponent, + int32 staticMeshId = -1) = 0; + void buildMeshDrawCommands( + const MeshBatch& meshBatch, + const PPrimitiveComponent primitiveComponent, + PMaterial material, + Gfx::PVertexShader vertexShader, + Gfx::PControlShader controlShader, + Gfx::PEvaluationShader evaluationShader, + Gfx::PGeometryShader geometryShader, + Gfx::PFragmentShader fragmentShader, + bool positionOnly); +}; +} // namespace Seele diff --git a/src/Engine/Graphics/RenderPass/VertexFactory.cpp b/src/Engine/Graphics/RenderPass/VertexFactory.cpp new file mode 100644 index 0000000..e143a7a --- /dev/null +++ b/src/Engine/Graphics/RenderPass/VertexFactory.cpp @@ -0,0 +1,28 @@ +#include "VertexFactory.h" + +using namespace Seele; + +void VertexFactory::getStreams(VertexInputStreamArray& outVertexStreams) const +{ + for(uint32 i = 0; i < streams.size(); ++i) + { + const Gfx::VertexStream& stream = streams[i]; + if(stream.vertexBuffer == nullptr) + { + outVertexStreams.add(VertexInputStream(i, 0, nullptr)); + } + else + { + outVertexStreams.add(VertexInputStream(i, stream.offset, stream.vertexBuffer)); + } + } +} + +void VertexFactory::getPositionOnlyStream(VertexInputStreamArray& outVertexStreams) const +{ + for (uint32 i = 0; i < positionStream.size(); ++i) + { + const Gfx::VertexStream& stream = positionStream[i]; + outVertexStreams.add(VertexInputStream(i, stream.offset, stream.vertexBuffer)); + } +} \ No newline at end of file diff --git a/src/Engine/Graphics/RenderPass/VertexFactory.h b/src/Engine/Graphics/RenderPass/VertexFactory.h new file mode 100644 index 0000000..d3f0393 --- /dev/null +++ b/src/Engine/Graphics/RenderPass/VertexFactory.h @@ -0,0 +1,92 @@ +#pragma once +#include "MinimalEngine.h" +#include "Graphics/GraphicsResources.h" + +namespace Seele +{ +struct VertexInputStream +{ + uint32 streamIndex : 4; + uint32 offset : 28; + Gfx::PVertexBuffer vertexBuffer; + + VertexInputStream() + : streamIndex(0), offset(0), vertexBuffer(nullptr) + { + } + + VertexInputStream(uint32 streamIndex, uint32 offset, Gfx::PVertexBuffer vertexBuffer) + : streamIndex(streamIndex), offset(offset), vertexBuffer(vertexBuffer) + { + assert(this->streamIndex == streamIndex && this->offset == offset); + } + + inline bool operator==(const VertexInputStream &rhs) const + { + if (streamIndex != rhs.streamIndex || offset != rhs.offset || vertexBuffer != rhs.vertexBuffer) + { + return false; + } + return true; + } + inline bool operator!=(const VertexInputStream &rhs) const + { + return !(*this == rhs); + } +}; + +struct VertexStreamComponent +{ + const Gfx::PVertexBuffer vertexBuffer = nullptr; + + uint32 streamOffset = 0; + + uint8 offset = 0; + + uint8 stride; + + Gfx::SeFormat type; + + VertexStreamComponent() + { + } + + VertexStreamComponent(const Gfx::PVertexBuffer vertexBuffer, uint32 offset, uint32 stride, Gfx::SeFormat type) + : vertexBuffer(vertexBuffer) + , streamOffset(0) + , offset(offset) + , stride(stride) + , type(type) + { + } + + VertexStreamComponent(const Gfx::PVertexBuffer vertexBuffer, uint32 streamOffset, uint32 offset, uint32 stride, Gfx::SeFormat type) + : vertexBuffer(vertexBuffer) + , streamOffset(streamOffset) + , offset(offset) + , stride(stride) + , type(type) + { + } +}; + +typedef Array VertexInputStreamArray; +class VertexFactory +{ +public: + VertexFactory() + { + } + void getStreams(VertexInputStreamArray& outVertexStreams) const; + void getPositionOnlyStream(VertexInputStreamArray& outVertexStreams) const; + virtual bool supportsTesselation() { return false; } + Gfx::PVertexDeclaration getDeclaration() const {return declaration;} + Gfx::PVertexDeclaration getPositionDeclaration() const {return positionDeclaration;} +private: + StaticArray streams; + StaticArray positionStream; + Gfx::PVertexDeclaration declaration; + Gfx::PVertexDeclaration positionDeclaration; +}; +DEFINE_REF(VertexFactory); +} // namespace Seele diff --git a/src/Engine/Graphics/RenderPath.h b/src/Engine/Graphics/RenderPath.h index b8e337b..6b57205 100644 --- a/src/Engine/Graphics/RenderPath.h +++ b/src/Engine/Graphics/RenderPath.h @@ -9,6 +9,7 @@ public: RenderPath(Gfx::PGraphics graphics, Gfx::PViewport target); virtual ~RenderPath(); virtual void applyArea(URect area); + virtual void init() = 0; virtual void beginFrame() = 0; virtual void render() = 0; virtual void endFrame() = 0; diff --git a/src/Engine/Graphics/SceneRenderPath.cpp b/src/Engine/Graphics/SceneRenderPath.cpp index a3e3f1d..849be00 100644 --- a/src/Engine/Graphics/SceneRenderPath.cpp +++ b/src/Engine/Graphics/SceneRenderPath.cpp @@ -1,12 +1,39 @@ #include "SceneRenderPath.h" #include "Scene/Scene.h" +#include "Material/Material.h" -Seele::SceneRenderPath::SceneRenderPath(Gfx::PGraphics graphics, Gfx::PViewport target) +using namespace Seele; + +SceneRenderPath::SceneRenderPath(Gfx::PGraphics graphics, Gfx::PViewport target) : RenderPath(graphics, target) { - scene = new Scene(); } -Seele::SceneRenderPath::~SceneRenderPath() +SceneRenderPath::~SceneRenderPath() { } + +void SceneRenderPath::setTargetScene(PScene newScene) +{ + scene = newScene; +} + +void SceneRenderPath::init() +{ + +} + +void SceneRenderPath::beginFrame() +{ + +} + +void SceneRenderPath::render() +{ + +} + +void SceneRenderPath::endFrame() +{ + +} diff --git a/src/Engine/Graphics/SceneRenderPath.h b/src/Engine/Graphics/SceneRenderPath.h index b93cf61..65ec08d 100644 --- a/src/Engine/Graphics/SceneRenderPath.h +++ b/src/Engine/Graphics/SceneRenderPath.h @@ -9,9 +9,11 @@ class SceneRenderPath : public RenderPath public: SceneRenderPath(Gfx::PGraphics graphics, Gfx::PViewport target); virtual ~SceneRenderPath(); - virtual void beginFrame() = 0; - virtual void render() = 0; - virtual void endFrame() = 0; + void setTargetScene(PScene scene); + virtual void init(); + virtual void beginFrame(); + virtual void render(); + virtual void endFrame(); protected: PScene scene; diff --git a/src/Engine/Graphics/SceneView.cpp b/src/Engine/Graphics/SceneView.cpp index 301e80e..e195c2f 100644 --- a/src/Engine/Graphics/SceneView.cpp +++ b/src/Engine/Graphics/SceneView.cpp @@ -1,11 +1,11 @@ #include "SceneView.h" -#include "ForwardPlusRenderPath.h" +#include "SceneRenderPath.h" #include "Window.h" Seele::SceneView::SceneView(Gfx::PGraphics graphics, PWindow owner, const ViewportCreateInfo &createInfo) : View(graphics, owner, createInfo) { - renderer = new ForwardPlusRenderPath(graphics, viewport); + renderer = new SceneRenderPath(graphics, viewport); } Seele::SceneView::~SceneView() diff --git a/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp b/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp index be7b6e0..9a93eaf 100644 --- a/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp @@ -61,16 +61,15 @@ Allocation::Allocation(PGraphics graphics, Allocator *allocator, VkDeviceSize si Allocation::~Allocation() { - allocator->free(this); } PSubAllocation Allocation::getSuballocation(VkDeviceSize requestedSize, VkDeviceSize alignment) { + std::scoped_lock lck(lock); if (isDedicated) { - if (activeAllocations.empty()) + if (activeAllocations.empty() && requestedSize == bytesAllocated) { - assert(requestedSize == bytesAllocated); PSubAllocation suballoc = freeRanges[0]; activeAllocations[0] = suballoc.getHandle(); freeRanges.clear(); @@ -82,9 +81,9 @@ PSubAllocation Allocation::getSuballocation(VkDeviceSize requestedSize, VkDevice return nullptr; } } - for (uint32 i = 0; i < freeRanges.size(); ++i) + for (auto it : freeRanges) { - PSubAllocation freeAllocation = freeRanges[i]; + PSubAllocation freeAllocation = it.value; VkDeviceSize allocatedOffset = freeAllocation->allocatedOffset; VkDeviceSize alignedOffset = align(allocatedOffset, alignment); VkDeviceSize alignmentAdjustment = alignedOffset - allocatedOffset; @@ -115,32 +114,48 @@ PSubAllocation Allocation::getSuballocation(VkDeviceSize requestedSize, VkDevice void Allocation::markFree(SubAllocation *allocation) { + // Dont free if it is already a free allocation, since they also mark themselves on deletion + if(freeRanges.find(allocation->allocatedOffset) != nullptr) + { + return; + } VkDeviceSize lowerBound = allocation->allocatedOffset; VkDeviceSize upperBound = allocation->allocatedOffset + allocation->allocatedSize; PSubAllocation allocHandle; + std::scoped_lock lck(lock); + //Join lower bound for (auto freeRange : freeRanges) { PSubAllocation freeAlloc = freeRange.value; - if (freeAlloc->allocatedOffset + freeAlloc->allocatedSize + 1 == lowerBound) + if (freeAlloc->allocatedOffset + freeAlloc->allocatedSize == lowerBound) { + //extend freeAlloc by the allocatedSize freeAlloc->allocatedSize += allocation->allocatedSize; allocHandle = freeAlloc; break; } } - auto foundAlloc = freeRanges.find(upperBound + 1); + //Join upper bound + auto foundAlloc = freeRanges.find(upperBound); if (foundAlloc != freeRanges.end()) { - if (allocHandle == nullptr) + // There is a free allocation ending where the new free one ends + if (allocHandle != nullptr) { + // extend allocHandle by another foundAlloc->allocatedSize bytes allocHandle->allocatedSize += foundAlloc->value->allocatedSize; freeRanges.erase(foundAlloc->key); } else { + // set foundAlloc back by size amount allocHandle = foundAlloc->value; + // remove from offset map since key changes + freeRanges.erase(foundAlloc->key); allocHandle->allocatedOffset -= allocation->allocatedSize; allocHandle->alignedOffset -= allocation->allocatedSize; + // place back at correct offset + freeRanges[allocHandle->allocatedOffset] = allocHandle; } } if (allocHandle == nullptr) @@ -150,6 +165,8 @@ void Allocation::markFree(SubAllocation *allocation) } activeAllocations.erase(allocation->allocatedOffset); bytesUsed -= allocation->allocatedSize; + + // TODO: delete allocation when bytesUsed == 0 } Allocator::Allocator(PGraphics graphics) @@ -167,6 +184,7 @@ Allocator::Allocator(PGraphics graphics) Allocator::~Allocator() { + std::scoped_lock lck(lock); for (auto heap : heaps) { for (auto alloc : heap.allocations) @@ -181,6 +199,7 @@ Allocator::~Allocator() PSubAllocation Allocator::allocate(const VkMemoryRequirements2 &memRequirements2, VkMemoryPropertyFlags properties, VkMemoryDedicatedAllocateInfo *dedicatedInfo) { + std::scoped_lock lck(lock); const VkMemoryRequirements &requirements = memRequirements2.memoryRequirements; uint8 memoryTypeIndex; VK_CHECK(findMemoryType(requirements.memoryTypeBits, properties, &memoryTypeIndex)); @@ -213,6 +232,7 @@ PSubAllocation Allocator::allocate(const VkMemoryRequirements2 &memRequirements2 void Allocator::free(Allocation *allocation) { + std::scoped_lock lck(lock); for (auto heap : heaps) { for (uint32 i = 0; i < heap.allocations.size(); ++i) diff --git a/src/Engine/Graphics/Vulkan/VulkanAllocator.h b/src/Engine/Graphics/Vulkan/VulkanAllocator.h index 2345451..609943e 100644 --- a/src/Engine/Graphics/Vulkan/VulkanAllocator.h +++ b/src/Engine/Graphics/Vulkan/VulkanAllocator.h @@ -3,6 +3,7 @@ #include "VulkanGraphicsEnums.h" #include "Containers/Map.h" #include "Containers/Array.h" +#include namespace Seele { @@ -101,6 +102,7 @@ private: VkMemoryPropertyFlags properties; Map activeAllocations; Map freeRanges; + std::mutex lock; void *mappedPointer; uint8 memoryTypeIndex; uint8 isDedicated : 1; @@ -153,6 +155,7 @@ private: }; Array heaps; VkResult findMemoryType(uint32 typeBits, VkMemoryPropertyFlags properties, uint8 *typeIndex); + std::mutex lock; PGraphics graphics; VkPhysicalDeviceMemoryProperties memProperties; }; diff --git a/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp b/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp index 28e1915..9ab7c62 100644 --- a/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp @@ -17,7 +17,7 @@ struct PendingBuffer static Map pendingBuffers; Buffer::Buffer(PGraphics graphics, uint32 size, VkBufferUsageFlags usage, Gfx::QueueType queueType) - : QueueOwnedResource(graphics, queueType), currentBuffer(0), size(size) + : graphics(graphics), currentBuffer(0), size(size), currentOwner(queueType) { if (usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT || usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT || @@ -58,7 +58,7 @@ Buffer::Buffer(PGraphics graphics, uint32 size, VkBufferUsageFlags usage, Gfx::Q Buffer::~Buffer() { - auto fence = getCommands()->getCommands()->getFence(); + auto fence = graphics->getQueueCommands(currentOwner)->getCommands()->getFence(); auto &deletionQueue = graphics->getDeletionQueue(); VkDevice device = graphics->getDevice(); VkBuffer buf[Gfx::numFramesBuffered]; @@ -74,11 +74,11 @@ void Buffer::executeOwnershipBarrier(Gfx::QueueType newOwner) { VkBufferMemoryBarrier barrier = init::BufferMemoryBarrier(); - PCommandBufferManager sourceManager = getCommands(); + PCommandBufferManager sourceManager = graphics->getQueueCommands(currentOwner); PCommandBufferManager dstManager = nullptr; VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; VkPipelineStageFlags dstStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; - QueueFamilyMapping mapping = graphics->getFamilyMapping(); + Gfx::QueueFamilyMapping mapping = graphics->getFamilyMapping(); barrier.srcQueueFamilyIndex = mapping.getQueueTypeFamilyIndex(currentOwner); barrier.dstQueueFamilyIndex = mapping.getQueueTypeFamilyIndex(newOwner); assert(barrier.srcQueueFamilyIndex != barrier.dstQueueFamilyIndex); @@ -134,7 +134,7 @@ void Buffer::executeOwnershipBarrier(Gfx::QueueType newOwner) vkCmdPipelineBarrier(srcCommand, srcStage, dstStage, 0, 0, nullptr, numBuffers, dynamicBarriers, 0, nullptr); vkCmdPipelineBarrier(dstCommand, srcStage, dstStage, 0, 0, nullptr, numBuffers, dynamicBarriers, 0, nullptr); sourceManager->submitCommands(); - cachedCmdBufferManager = dstManager; + currentOwner = newOwner; } void *Buffer::lock(bool bWriteOnly) @@ -160,19 +160,19 @@ void *Buffer::lock(bool bWriteOnly) pending.prevQueue = currentOwner; if (bWriteOnly) { - transferOwnership(Gfx::QueueType::DEDICATED_TRANSFER); + requestOwnershipTransfer(Gfx::QueueType::DEDICATED_TRANSFER); PStagingBuffer stagingBuffer = graphics->getStagingManager()->allocateStagingBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); data = stagingBuffer->getMappedPointer(); pending.stagingBuffer = stagingBuffer; } else { - PCmdBuffer current = getCommands()->getCommands(); - getCommands()->submitCommands(); - getCommands()->waitForCommands(current); + PCmdBuffer current = graphics->getQueueCommands(currentOwner)->getCommands(); + graphics->getQueueCommands(currentOwner)->submitCommands(); + graphics->getQueueCommands(currentOwner)->waitForCommands(current); - transferOwnership(Gfx::QueueType::DEDICATED_TRANSFER); - VkCommandBuffer handle = getCommands()->getCommands()->getHandle(); + requestOwnershipTransfer(Gfx::QueueType::DEDICATED_TRANSFER); + VkCommandBuffer handle = graphics->getQueueCommands(currentOwner)->getCommands()->getHandle(); VkBufferMemoryBarrier barrier = init::BufferMemoryBarrier(); @@ -194,8 +194,8 @@ void *Buffer::lock(bool bWriteOnly) vkCmdCopyBuffer(handle, buffers[currentBuffer].buffer, stagingBuffer->getHandle(), 1, ®ions); - getCommands()->submitCommands(); - vkQueueWaitIdle(getCommands()->getQueue()->getHandle()); + graphics->getQueueCommands(currentOwner)->submitCommands(); + vkQueueWaitIdle(graphics->getQueueCommands(currentOwner)->getQueue()->getHandle()); stagingBuffer->flushMappedMemory(); pending.stagingBuffer = stagingBuffer; @@ -219,7 +219,7 @@ void Buffer::unlock() if (pending.bWriteOnly) { PStagingBuffer stagingBuffer = pending.stagingBuffer; - PCmdBuffer cmdBuffer = getCommands()->getCommands(); + PCmdBuffer cmdBuffer = graphics->getQueueCommands(currentOwner)->getCommands(); VkCommandBuffer cmdHandle = cmdBuffer->getHandle(); VkBufferCopy region; @@ -227,13 +227,14 @@ void Buffer::unlock() region.size = size; vkCmdCopyBuffer(cmdHandle, stagingBuffer->getHandle(), buffers[currentBuffer].buffer, 1, ®ion); } - transferOwnership(pending.prevQueue); + requestOwnershipTransfer(pending.prevQueue); graphics->getStagingManager()->releaseStagingBuffer(pending.stagingBuffer); } } UniformBuffer::UniformBuffer(PGraphics graphics, const BulkResourceData &resourceData) : Buffer(graphics, resourceData.size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, resourceData.owner) + , Gfx::UniformBuffer(graphics, resourceData.owner) { if (resourceData.data != nullptr) { @@ -247,6 +248,17 @@ UniformBuffer::~UniformBuffer() { } +void UniformBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) +{ + Gfx::QueueOwnedResource::transferOwnership(newOwner); + Buffer::currentOwner = newOwner; +} + +void UniformBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) +{ + Buffer::executeOwnershipBarrier(newOwner); +} + VkAccessFlags UniformBuffer::getSourceAccessMask() { return VK_ACCESS_MEMORY_WRITE_BIT; @@ -259,6 +271,7 @@ VkAccessFlags UniformBuffer::getDestAccessMask() StructuredBuffer::StructuredBuffer(PGraphics graphics, const BulkResourceData &resourceData) : Buffer(graphics, resourceData.size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, resourceData.owner) + , Gfx::StructuredBuffer(graphics, resourceData.owner) { if (resourceData.data != nullptr) { @@ -272,6 +285,16 @@ StructuredBuffer::~StructuredBuffer() { } +void StructuredBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) +{ + Gfx::QueueOwnedResource::transferOwnership(newOwner); +} + +void StructuredBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) +{ + Buffer::executeOwnershipBarrier(newOwner); +} + VkAccessFlags StructuredBuffer::getSourceAccessMask() { return VK_ACCESS_MEMORY_WRITE_BIT; @@ -284,7 +307,7 @@ VkAccessFlags StructuredBuffer::getDestAccessMask() VertexBuffer::VertexBuffer(PGraphics graphics, const VertexBufferCreateInfo &resourceData) : Buffer(graphics, resourceData.resourceData.size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, resourceData.resourceData.owner) - , Gfx::VertexBuffer(resourceData.numVertices, resourceData.vertexSize) + , Gfx::VertexBuffer(graphics, resourceData.numVertices, resourceData.vertexSize, resourceData.resourceData.owner) { if (resourceData.resourceData.data != nullptr) { @@ -298,6 +321,16 @@ VertexBuffer::~VertexBuffer() { } +void VertexBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) +{ + Gfx::QueueOwnedResource::transferOwnership(newOwner); +} + +void VertexBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) +{ + Buffer::executeOwnershipBarrier(newOwner); +} + VkAccessFlags VertexBuffer::getSourceAccessMask() { return VK_ACCESS_MEMORY_WRITE_BIT; @@ -310,7 +343,7 @@ VkAccessFlags VertexBuffer::getDestAccessMask() IndexBuffer::IndexBuffer(PGraphics graphics, const IndexBufferCreateInfo &resourceData) : Buffer(graphics, resourceData.resourceData.size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, resourceData.resourceData.owner) - , Gfx::IndexBuffer(resourceData.resourceData.size, resourceData.indexType) + , Gfx::IndexBuffer(graphics, resourceData.resourceData.size, resourceData.indexType, resourceData.resourceData.owner) { if (resourceData.resourceData.data != nullptr) { @@ -324,6 +357,16 @@ IndexBuffer::~IndexBuffer() { } +void IndexBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) +{ + Gfx::QueueOwnedResource::transferOwnership(newOwner); +} + +void IndexBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) +{ + Buffer::executeOwnershipBarrier(newOwner); +} + VkAccessFlags IndexBuffer::getSourceAccessMask() { return VK_ACCESS_MEMORY_WRITE_BIT; diff --git a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp index 59f6812..9a42812 100644 --- a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp @@ -7,6 +7,7 @@ #include "VulkanRenderPass.h" #include "VulkanPipeline.h" #include "VulkanDescriptorSets.h" +#include "Graphics/MeshBatch.h" using namespace Seele; using namespace Seele::Vulkan; @@ -174,9 +175,9 @@ void SecondaryCmdBuffer::bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) PIndexBuffer buf = indexBuffer.cast(); vkCmdBindIndexBuffer(handle, buf->getHandle(), 0, VK_INDEX_TYPE_UINT16); } -void SecondaryCmdBuffer::draw(DrawInstance data) +void SecondaryCmdBuffer::draw(const MeshBatchElement& data) { - vkCmdDrawIndexed(handle, data.indexBuffer->getNumIndices(), data.numInstances, data.minVertexIndex, data.baseVertexIndex, data.firstInstance); + vkCmdDrawIndexed(handle, data.indexBuffer->getNumIndices(), data.numInstances, data.minVertexIndex, data.baseVertexIndex, 0); } CommandBufferManager::CommandBufferManager(PGraphics graphics, PQueue queue) diff --git a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h index 2cf22f3..b56b997 100644 --- a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h +++ b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h @@ -77,7 +77,7 @@ public: virtual void bindDescriptor(Gfx::PDescriptorSet descriptorSet) override; virtual void bindVertexBuffer(Gfx::PVertexBuffer vertexBuffer) override; virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) override; - virtual void draw(DrawInstance data) override; + virtual void draw(const MeshBatchElement& data) override; private: PGraphicsPipeline pipeline; diff --git a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp index 85e0999..bf7121f 100644 --- a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp @@ -72,6 +72,13 @@ void PipelineLayout::create() layoutHash = memCrc32(&createInfo, sizeof(VkPipelineLayoutCreateInfo), 0); } +void PipelineLayout::reset() +{ + vkDestroyPipelineLayout(graphics->getDevice(), layoutHandle, nullptr); + descriptorSetLayouts.clear(); + pushConstants.clear(); +} + DescriptorSet::~DescriptorSet() { } diff --git a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h index caa419e..84fd7d0 100644 --- a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h +++ b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h @@ -34,6 +34,7 @@ public: } virtual ~PipelineLayout(); virtual void create(); + virtual void reset(); inline VkPipelineLayout getHandle() const { return layoutHandle; diff --git a/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp b/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp index bb6f5cf..5c20342 100644 --- a/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp @@ -7,6 +7,8 @@ #include "VulkanRenderPass.h" #include "VulkanFramebuffer.h" #include "VulkanPipelineCache.h" +#include "VulkanDescriptorSets.h" +#include "VulkanShader.h" #include "Graphics/GraphicsResources.h" #include @@ -99,9 +101,7 @@ void Graphics::executeCommands(Array commands) Gfx::PTexture2D Graphics::createTexture2D(const TextureCreateInfo &createInfo) { - PTexture2D result = new Texture2D(this, createInfo.width, createInfo.height, createInfo.bArray, - createInfo.bArray, createInfo.arrayLayers, createInfo.format, - createInfo.samples, createInfo.usage, createInfo.queueType); + PTexture2D result = new Texture2D(this, createInfo); return result; } @@ -133,11 +133,51 @@ Gfx::PRenderCommand Graphics::createRenderCommand() cmdBuffer->begin(getGraphicsCommands()->getCommands()); return cmdBuffer; } +Gfx::PVertexShader Graphics::createVertexShader(const ShaderCreateInfo& createInfo) +{ + PVertexShader shader = new VertexShader(this); + shader->create(createInfo); + return shader; +} +Gfx::PControlShader Graphics::createControlShader(const ShaderCreateInfo& createInfo) +{ + PControlShader shader = new ControlShader(this); + shader->create(createInfo); + return shader; +} +Gfx::PEvaluationShader Graphics::createEvaluationShader(const ShaderCreateInfo& createInfo) +{ + PEvaluationShader shader = new EvaluationShader(this); + shader->create(createInfo); + return shader; +} +Gfx::PGeometryShader Graphics::createGeometryShader(const ShaderCreateInfo& createInfo) +{ + PGeometryShader shader = new GeometryShader(this); + shader->create(createInfo); + return shader; +} +Gfx::PFragmentShader Graphics::createFragmentShader(const ShaderCreateInfo& createInfo) +{ + PFragmentShader shader = new FragmentShader(this); + shader->create(createInfo); + return shader; +} Gfx::PGraphicsPipeline Graphics::createGraphicsPipeline(const GraphicsPipelineCreateInfo& createInfo) { PGraphicsPipeline pipeline = pipelineCache->createPipeline(createInfo); return pipeline; } +Gfx::PDescriptorLayout Graphics::createDescriptorLayout() +{ + PDescriptorLayout layout = new DescriptorLayout(this); + return layout; +} +Gfx::PPipelineLayout Graphics::createPipelineLayout() +{ + PPipelineLayout layout = new PipelineLayout(this); + return layout; +} VkInstance Graphics::getInstance() const { @@ -154,6 +194,23 @@ VkPhysicalDevice Graphics::getPhysicalDevice() const return physicalDevice; } +PCommandBufferManager Graphics::getQueueCommands(Gfx::QueueType queueType) +{ + switch (queueType) + { + case Gfx::QueueType::GRAPHICS: + return graphicsCommands; + case Gfx::QueueType::COMPUTE: + return computeCommands; + case Gfx::QueueType::TRANSFER: + return transferCommands; + case Gfx::QueueType::DEDICATED_TRANSFER: + return dedicatedTransferCommands; + default: + throw new std::logic_error("invalid queue type"); + } +} + PCommandBufferManager Graphics::getGraphicsCommands() { return graphicsCommands; diff --git a/src/Engine/Graphics/Vulkan/VulkanGraphics.h b/src/Engine/Graphics/Vulkan/VulkanGraphics.h index 43df875..6bded7a 100644 --- a/src/Engine/Graphics/Vulkan/VulkanGraphics.h +++ b/src/Engine/Graphics/Vulkan/VulkanGraphics.h @@ -22,15 +22,12 @@ public: VkDevice getDevice() const; VkPhysicalDevice getPhysicalDevice() const; + PCommandBufferManager getQueueCommands(Gfx::QueueType queueType); PCommandBufferManager getGraphicsCommands(); PCommandBufferManager getComputeCommands(); PCommandBufferManager getTransferCommands(); PCommandBufferManager getDedicatedTransferCommands(); - const QueueFamilyMapping getFamilyMapping() const - { - return queueMapping; - } QueueOwnedResourceDeletion &getDeletionQueue() { return deletionQueue; @@ -56,8 +53,16 @@ public: virtual Gfx::PVertexBuffer createVertexBuffer(const VertexBufferCreateInfo &bulkData) override; virtual Gfx::PIndexBuffer createIndexBuffer(const IndexBufferCreateInfo &bulkData) override; virtual Gfx::PRenderCommand createRenderCommand() override; + virtual Gfx::PVertexShader createVertexShader(const ShaderCreateInfo& createInfo) override; + virtual Gfx::PControlShader createControlShader(const ShaderCreateInfo& createInfo) override; + virtual Gfx::PEvaluationShader createEvaluationShader(const ShaderCreateInfo& createInfo) override; + virtual Gfx::PGeometryShader createGeometryShader(const ShaderCreateInfo& createInfo) override; + virtual Gfx::PFragmentShader createFragmentShader(const ShaderCreateInfo& createInfo) override; virtual Gfx::PGraphicsPipeline createGraphicsPipeline(const GraphicsPipelineCreateInfo& createInfo) override; + virtual Gfx::PDescriptorLayout createDescriptorLayout() override; + virtual Gfx::PPipelineLayout createPipelineLayout() override; + protected: Array getRequiredExtensions(); void initInstance(GraphicsInitializer initInfo); @@ -73,7 +78,6 @@ protected: PQueue computeQueue; PQueue transferQueue; PQueue dedicatedTransferQueue; - QueueFamilyMapping queueMapping; QueueOwnedResourceDeletion deletionQueue; PPipelineCache pipelineCache; PCommandBufferManager graphicsCommands; diff --git a/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.cpp b/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.cpp index 483fc9f..83a4ef1 100644 --- a/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.cpp @@ -50,47 +50,6 @@ void QueueOwnedResourceDeletion::run() } } -QueueOwnedResource::QueueOwnedResource(PGraphics graphics, Gfx::QueueType startQueueType) - : graphics(graphics), currentOwner(startQueueType) -{ -} - -QueueOwnedResource::~QueueOwnedResource() -{ - cachedCmdBufferManager = nullptr; - graphics = nullptr; -} - -void QueueOwnedResource::transferOwnership(Gfx::QueueType newOwner) -{ - if (graphics->getFamilyMapping().needsTransfer(currentOwner, newOwner)) - { - executeOwnershipBarrier(newOwner); - currentOwner = newOwner; - } -} - -PCommandBufferManager QueueOwnedResource::getCommands() -{ - if (cachedCmdBufferManager != nullptr) - { - assert(cachedCmdBufferManager->getQueue()->getFamilyIndex() == graphics->getFamilyMapping().getQueueTypeFamilyIndex(currentOwner)); - return cachedCmdBufferManager; - } - switch (currentOwner) - { - case Gfx::QueueType::GRAPHICS: - return graphics->getGraphicsCommands(); - case Gfx::QueueType::COMPUTE: - return graphics->getComputeCommands(); - case Gfx::QueueType::TRANSFER: - return graphics->getTransferCommands(); - case Gfx::QueueType::DEDICATED_TRANSFER: - return graphics->getDedicatedTransferCommands(); - } - return nullptr; -} - Semaphore::Semaphore(PGraphics graphics) : graphics(graphics) { diff --git a/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.h b/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.h index 1fccbdd..6822926 100644 --- a/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.h +++ b/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.h @@ -1,8 +1,5 @@ #pragma once #include "Graphics/GraphicsResources.h" -#include -#include -#include #include namespace Seele @@ -54,35 +51,6 @@ private: }; DEFINE_REF(Fence); -struct QueueFamilyMapping -{ - uint32 graphicsFamily; - uint32 computeFamily; - uint32 transferFamily; - uint32 dedicatedTransferFamily; - uint32 getQueueTypeFamilyIndex(Gfx::QueueType type) const - { - switch (type) - { - case Gfx::QueueType::GRAPHICS: - return graphicsFamily; - case Gfx::QueueType::COMPUTE: - return computeFamily; - case Gfx::QueueType::TRANSFER: - return transferFamily; - case Gfx::QueueType::DEDICATED_TRANSFER: - return dedicatedTransferFamily; - default: - return VK_QUEUE_FAMILY_IGNORED; - } - } - bool needsTransfer(Gfx::QueueType src, Gfx::QueueType dst) const - { - uint32 srcIndex = getQueueTypeFamilyIndex(src); - uint32 dstIndex = getQueueTypeFamilyIndex(dst); - return srcIndex != dstIndex; - } -}; class QueueOwnedResourceDeletion { public: @@ -103,24 +71,8 @@ private: static std::condition_variable cv; static List deletionQueue; }; -class QueueOwnedResource -{ -public: - QueueOwnedResource(PGraphics graphics, Gfx::QueueType startQueueType); - virtual ~QueueOwnedResource(); - PCommandBufferManager getCommands(); - //Preliminary checks to see if the barrier should be executed at all - void transferOwnership(Gfx::QueueType newOwner); -protected: - virtual void executeOwnershipBarrier(Gfx::QueueType newOwner) = 0; - Gfx::QueueType currentOwner; - PGraphics graphics; - PCommandBufferManager cachedCmdBufferManager; -}; -DEFINE_REF(QueueOwnedResource); - -class Buffer : public QueueOwnedResource +class Buffer { public: Buffer(PGraphics graphics, uint32 size, VkBufferUsageFlags usage, Gfx::QueueType queueType); @@ -146,11 +98,14 @@ protected: uint32 numBuffers; uint32 currentBuffer; uint32 size; + PGraphics graphics; + Gfx::QueueType currentOwner; + + void executeOwnershipBarrier(Gfx::QueueType newOwner); + virtual void requestOwnershipTransfer(Gfx::QueueType newOwner) = 0; virtual VkAccessFlags getSourceAccessMask() = 0; virtual VkAccessFlags getDestAccessMask() = 0; - // Inherited via QueueOwnedResource - virtual void executeOwnershipBarrier(Gfx::QueueType newOwner); }; DEFINE_REF(Buffer); @@ -161,8 +116,12 @@ public: virtual ~UniformBuffer(); protected: + // Inherited via Vulkan::Buffer + virtual void requestOwnershipTransfer(Gfx::QueueType newOwner); virtual VkAccessFlags getSourceAccessMask(); virtual VkAccessFlags getDestAccessMask(); + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(Gfx::QueueType newOwner); }; DEFINE_REF(UniformBuffer); @@ -173,8 +132,12 @@ public: virtual ~StructuredBuffer(); protected: + // Inherited via Vulkan::Buffer virtual VkAccessFlags getSourceAccessMask(); virtual VkAccessFlags getDestAccessMask(); + virtual void requestOwnershipTransfer(Gfx::QueueType newOwner); + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(Gfx::QueueType newOwner); }; DEFINE_REF(StructuredBuffer); @@ -185,8 +148,12 @@ public: virtual ~VertexBuffer(); protected: + // Inherited via Vulkan::Buffer virtual VkAccessFlags getSourceAccessMask(); virtual VkAccessFlags getDestAccessMask(); + virtual void requestOwnershipTransfer(Gfx::QueueType newOwner); + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(Gfx::QueueType newOwner); }; DEFINE_REF(VertexBuffer); @@ -197,17 +164,20 @@ public: virtual ~IndexBuffer(); protected: + // Inherited via Vulkan::Buffer + virtual void requestOwnershipTransfer(Gfx::QueueType newOwner); virtual VkAccessFlags getSourceAccessMask(); virtual VkAccessFlags getDestAccessMask(); + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(Gfx::QueueType newOwner); }; DEFINE_REF(IndexBuffer); -class TextureHandle : public QueueOwnedResource +class TextureHandle { public: - TextureHandle(PGraphics graphics, VkImageViewType viewType, uint32 sizeX, uint32 sizeY, uint32 sizeZ, - bool bArray, uint32 arraySize, uint32 mipLevels, Gfx::SeFormat format, - uint32 samples, Gfx::SeImageUsageFlags usage, Gfx::QueueType owner = Gfx::QueueType::GRAPHICS, VkImage existingImage = VK_NULL_HANDLE); + TextureHandle(PGraphics graphics, VkImageViewType viewType, + const TextureCreateInfo& createInfo, VkImage existingImage = VK_NULL_HANDLE); virtual ~TextureHandle(); inline VkImageView getView() const @@ -234,9 +204,10 @@ public: { return aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); } - // Inherited via QueueOwnedResource - virtual void executeOwnershipBarrier(Gfx::QueueType newOwner); + void executeOwnershipBarrier(Gfx::QueueType newOwner); + void changeLayout(VkImageLayout newLayout); + Gfx::QueueType currentOwner; private: PGraphics graphics; PSubAllocation allocation; @@ -276,10 +247,7 @@ DEFINE_REF(TextureBase); class Texture2D : public TextureBase, public Gfx::Texture2D { public: - Texture2D(PGraphics graphics, uint32 sizeX, uint32 sizeY, - bool bArray, uint32 arraySize, uint32 mipLevels, Gfx::SeFormat format, - uint32 samples, Gfx::SeImageUsageFlags usage, - Gfx::QueueType owner = Gfx::QueueType::GRAPHICS, VkImage existingImage = VK_NULL_HANDLE); + Texture2D(PGraphics graphics, const TextureCreateInfo& createInfo, VkImage existingImage = VK_NULL_HANDLE); virtual ~Texture2D(); inline uint32 getSizeX() const { @@ -305,8 +273,10 @@ public: { return textureHandle->isDepthStencil(); } +protected: + // Inherited via QueueOwnedResource + virtual void executeOwnershipBarrier(Gfx::QueueType newOwner); -private: }; DEFINE_REF(Texture2D); diff --git a/src/Engine/Graphics/Vulkan/VulkanPipeline.cpp b/src/Engine/Graphics/Vulkan/VulkanPipeline.cpp index 30243dc..f715867 100644 --- a/src/Engine/Graphics/Vulkan/VulkanPipeline.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanPipeline.cpp @@ -6,9 +6,8 @@ using namespace Seele; using namespace Seele::Vulkan; GraphicsPipeline::GraphicsPipeline(PGraphics graphics, VkPipeline handle, PPipelineLayout pipelineLayout, const GraphicsPipelineCreateInfo& createInfo) - : Gfx::GraphicsPipeline(createInfo) + : Gfx::GraphicsPipeline(createInfo, pipelineLayout) , graphics(graphics) - , layout(pipelineLayout) , pipeline(handle) { } @@ -24,5 +23,5 @@ void GraphicsPipeline::bind(VkCommandBuffer handle) VkPipelineLayout GraphicsPipeline::getLayout() const { - return layout->getHandle(); + return layout.cast()->getHandle(); } \ No newline at end of file diff --git a/src/Engine/Graphics/Vulkan/VulkanPipeline.h b/src/Engine/Graphics/Vulkan/VulkanPipeline.h index 643b98f..fcfad08 100644 --- a/src/Engine/Graphics/Vulkan/VulkanPipeline.h +++ b/src/Engine/Graphics/Vulkan/VulkanPipeline.h @@ -16,7 +16,6 @@ public: VkPipelineLayout getLayout() const; private: VkPipeline pipeline; - PPipelineLayout layout; PGraphics graphics; }; DEFINE_REF(GraphicsPipeline); diff --git a/src/Engine/Graphics/Vulkan/VulkanPipelineCache.cpp b/src/Engine/Graphics/Vulkan/VulkanPipelineCache.cpp index a69506b..3fed053 100644 --- a/src/Engine/Graphics/Vulkan/VulkanPipelineCache.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanPipelineCache.cpp @@ -52,6 +52,9 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo createInfo.pNext = 0; createInfo.flags = 0; createInfo.stageCount = 0; + + PPipelineLayout layout = graphics->createPipelineLayout(); + VkPipelineTessellationStateCreateInfo tessInfo; VkPipelineShaderStageCreateInfo stageInfos[5]; std::memset(stageInfos, 0, sizeof(stageInfos)); @@ -63,6 +66,10 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo vertInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; vertInfo.module = shader->getModuleHandle(); vertInfo.pName = shader->getEntryPointName(); + for(auto descriptor : shader->getDescriptorLayouts()) + { + layout->addDescriptorLayout(descriptor.key, descriptor.value); + } } if(gfxInfo.controlShader != nullptr) { @@ -86,6 +93,15 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo tessInfo.pNext = 0; tessInfo.flags = 0; tessInfo.patchControlPoints = control->getNumPatches(); + + for(auto descriptor : eval->getDescriptorLayouts()) + { + layout->addDescriptorLayout(descriptor.key, descriptor.value); + } + for(auto descriptor : control->getDescriptorLayouts()) + { + layout->addDescriptorLayout(descriptor.key, descriptor.value); + } } if(gfxInfo.geometryShader != nullptr) { @@ -96,6 +112,11 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo geometryInfo.stage = VK_SHADER_STAGE_GEOMETRY_BIT; geometryInfo.module = geometry->getModuleHandle(); geometryInfo.pName = geometry->getEntryPointName(); + + for(auto descriptor : geometry->getDescriptorLayouts()) + { + layout->addDescriptorLayout(descriptor.key, descriptor.value); + } } if(gfxInfo.fragmentShader != nullptr) { @@ -106,7 +127,13 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo fragmentInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragmentInfo.module = fragment->getModuleHandle(); fragmentInfo.pName = fragment->getEntryPointName(); + + for(auto descriptor : fragment->getDescriptorLayouts()) + { + layout->addDescriptorLayout(descriptor.key, descriptor.value); + } } + layout->create(); VkPipelineVertexInputStateCreateInfo vertexInput = init::PipelineVertexInputStateCreateInfo(); Gfx::PVertexDeclaration vertexDecl = gfxInfo.vertexDeclaration; @@ -116,7 +143,7 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo uint32 bindingNum = 0; for(auto vertexBinding : vertexStreams) { - uint32 stride = vertexBinding.getVertexBuffer()->getVertexSize(); + uint32 stride = 0; for(auto vertexAttrib : vertexBinding.getVertexDescriptions()) { auto attrib = attribDesc.add(); @@ -137,9 +164,9 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo VkPipelineInputAssemblyStateCreateInfo assemblyInfo = init::PipelineInputAssemblyStateCreateInfo( - cast(gfxInfo.topology), - 0, - false + cast(gfxInfo.topology), + 0, + false ); VkPipelineViewportStateCreateInfo viewportInfo = @@ -214,6 +241,7 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo 0 ); + createInfo.pStages = stageInfos; createInfo.pVertexInputState = &vertexInput; createInfo.pInputAssemblyState = &assemblyInfo; @@ -225,7 +253,7 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo createInfo.pColorBlendState = &blendState; createInfo.pDynamicState = &dynamicState; createInfo.renderPass = gfxInfo.renderPass.cast()->getHandle(); - createInfo.layout = gfxInfo.pipelineLayout.cast()->getHandle(); + createInfo.layout = layout->getHandle(); createInfo.subpass = 0; VkPipeline pipelineHandle; @@ -235,6 +263,6 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo int64 delta = std::chrono::duration_cast(endTime - beginTime).count(); std::cout << "Gfx creation time: " << delta << std::endl; - PGraphicsPipeline result = new GraphicsPipeline(graphics, pipelineHandle, gfxInfo.pipelineLayout.cast(), gfxInfo); + PGraphicsPipeline result = new GraphicsPipeline(graphics, pipelineHandle, layout, gfxInfo); return result; } \ No newline at end of file diff --git a/src/Engine/Graphics/Vulkan/VulkanShader.cpp b/src/Engine/Graphics/Vulkan/VulkanShader.cpp index 5b52311..70a1d4a 100644 --- a/src/Engine/Graphics/Vulkan/VulkanShader.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanShader.cpp @@ -1,4 +1,102 @@ #include "VulkanShader.h" +#include "VulkanGraphics.h" +#include "VulkanDescriptorSets.h" +#include "slang.h" +using namespace slang; using namespace Seele; -using namespace Seele::Vulkan; \ No newline at end of file +using namespace Seele::Vulkan; + +Shader::Shader(PGraphics graphics, ShaderType shaderType, VkShaderStageFlags stage) + : graphics(graphics) + , type(shaderType) + , stage(stage) +{ +} + +Shader::~Shader() +{ + if(module != VK_NULL_HANDLE) + { + vkDestroyShaderModule(graphics->getDevice(), module, nullptr); + } +} + +Map Shader::getDescriptorLayouts() +{ + return descriptorSets; +} + +static SlangStage getStageFromShaderType(ShaderType type) +{ + switch (type) + { + case ShaderType::VERTEX: + return SLANG_STAGE_VERTEX; + case ShaderType::CONTROL: + return SLANG_STAGE_HULL; + case ShaderType::EVALUATION: + return SLANG_STAGE_DOMAIN; + case ShaderType::GEOMETRY: + return SLANG_STAGE_GEOMETRY; + case ShaderType::FRAGMENT: + return SLANG_STAGE_PIXEL; + default: + return SLANG_STAGE_NONE; + } +} + +void Shader::create(const ShaderCreateInfo& createInfo) +{ + entryPointName = createInfo.entryPoint; + static SlangSession* session = spCreateSession(NULL); + + SlangCompileRequest* request = spCreateCompileRequest(session); + int targetIndex = spAddCodeGenTarget(request, SLANG_SPIRV); + spSetTargetProfile(request, targetIndex, spFindProfile(session, "glsl_vk")); + spSetDumpIntermediates(request, true); + + int translationUnitIndex = spAddTranslationUnit(request, SLANG_SOURCE_LANGUAGE_SLANG, ""); + + spAddTranslationUnitSourceString( + request, + translationUnitIndex, + entryPointName.c_str(), + createInfo.code.c_str() + ); + spAddSearchPath(request, "shaders/lib/"); + + spSetGlobalGenericArgs(request, createInfo.typeParameter.size(), createInfo.typeParameter.data()); + + int entryPointIndex = spAddEntryPoint(request, translationUnitIndex, entryPointName.c_str(), getStageFromShaderType(type)); + if(spCompile(request)) + { + char const* diagnostice = spGetDiagnosticOutput(request); + std::cout << diagnostice << std::endl; + } + + ShaderReflection* reflection = slang::ShaderReflection::get(request); + + uint32 parameterCount = reflection->getParameterCount(); + for(uint32 i = 0; i < parameterCount; ++i) + { + VariableLayoutReflection* parameter = + reflection->getParameterByIndex(i); + uint32 descriptorIndex = parameter->getBindingSpace(); + uint32 descriptorBinding = parameter->getBindingIndex(); + PDescriptorLayout& layout = descriptorSets[descriptorIndex]; + std::cout << parameter->getTypeLayout()->getName() << std::endl; + //layout->addDescriptorBinding(descriptorBinding, parame) + } + + size_t dataSize = 0; + const void* data = spGetEntryPointCode(request, entryPointIndex, &dataSize); + + VkShaderModuleCreateInfo moduleInfo; + moduleInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + moduleInfo.pNext = nullptr; + moduleInfo.flags = 0; + moduleInfo.codeSize = dataSize; + moduleInfo.pCode = static_cast(data); + VK_CHECK(vkCreateShaderModule(graphics->getDevice(), &moduleInfo, nullptr, &module)); +} \ No newline at end of file diff --git a/src/Engine/Graphics/Vulkan/VulkanShader.h b/src/Engine/Graphics/Vulkan/VulkanShader.h index 341db35..18113ca 100644 --- a/src/Engine/Graphics/Vulkan/VulkanShader.h +++ b/src/Engine/Graphics/Vulkan/VulkanShader.h @@ -6,13 +6,16 @@ namespace Seele { namespace Vulkan { - +DECLARE_REF(Graphics); +DECLARE_REF(DescriptorLayout); class Shader { public: Shader(PGraphics graphics, ShaderType shaderType, VkShaderStageFlags stage); virtual ~Shader(); + void create(const ShaderCreateInfo& createInfo); + VkShaderModule getModuleHandle() const { return module; @@ -21,18 +24,23 @@ public: { return entryPointName.c_str(); } + Map getDescriptorLayouts(); private: + PGraphics graphics; + Map descriptorSets; VkShaderModule module; + VkShaderStageFlags stage; + ShaderType type; std::string entryPointName; }; DEFINE_REF(Shader); -template +template class ShaderBase : public Base, public Shader { public: ShaderBase(PGraphics graphics) - : Shader(graphics, shaderType, stage) + : Shader(graphics, shaderType, stageFlags) { } virtual ~ShaderBase() diff --git a/src/Engine/Graphics/Vulkan/VulkanTexture.cpp b/src/Engine/Graphics/Vulkan/VulkanTexture.cpp index ad88444..1f37026 100644 --- a/src/Engine/Graphics/Vulkan/VulkanTexture.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanTexture.cpp @@ -29,10 +29,21 @@ VkImageAspectFlags getAspectFromFormat(Gfx::SeFormat format) } } -TextureHandle::TextureHandle(PGraphics graphics, VkImageViewType viewType, uint32 sizeX, uint32 sizeY, uint32 sizeZ, - bool bArray, uint32 arraySize, uint32 mipLevel, - Gfx::SeFormat format, uint32 samples, Gfx::SeImageUsageFlags usage, Gfx::QueueType owner, VkImage existingImage) - : QueueOwnedResource(graphics, owner), graphics(graphics), sizeX(sizeX), sizeY(sizeY), sizeZ(sizeZ), mipLevels(mipLevel), format(format), samples(samples), usage(usage), arrayCount(bArray ? arraySize : 1), aspect(getAspectFromFormat(format)), image(existingImage), layout(VK_IMAGE_LAYOUT_UNDEFINED) +TextureHandle::TextureHandle(PGraphics graphics, VkImageViewType viewType, + const TextureCreateInfo& createInfo, VkImage existingImage) + : currentOwner(createInfo.resourceData.owner) + , graphics(graphics) + , sizeX(createInfo.width) + , sizeY(createInfo.height) + , sizeZ(createInfo.depth) + , mipLevels(createInfo.mipLevels) + , format(createInfo.format) + , samples(createInfo.samples) + , usage(createInfo.usage) + , arrayCount(createInfo.bArray ? createInfo.arrayLayers : 1) + , aspect(getAspectFromFormat(createInfo.format)) + , image(existingImage) + , layout(VK_IMAGE_LAYOUT_UNDEFINED) { if (existingImage == VK_NULL_HANDLE) { @@ -42,7 +53,7 @@ TextureHandle::TextureHandle(PGraphics graphics, VkImageViewType viewType, uint3 info.extent.width = sizeX; info.extent.height = sizeY; info.extent.depth = sizeZ; - info.arrayLayers = arraySize; + info.arrayLayers = arrayCount; info.format = cast(format); uint32 layerCount = 1; @@ -67,13 +78,18 @@ TextureHandle::TextureHandle(PGraphics graphics, VkImageViewType viewType, uint3 default: break; } - info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - info.mipLevels = mipLevel; + info.initialLayout = layout; + info.mipLevels = mipLevels; info.arrayLayers = arrayCount * layerCount; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.samples = (VkSampleCountFlagBits)samples; info.tiling = VK_IMAGE_TILING_OPTIMAL; info.usage = usage; + //To upload to the image we need to specify transfer dst + if(createInfo.resourceData.size > 0) + { + info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } VK_CHECK(vkCreateImage(graphics->getDevice(), &info, nullptr, &image)); VkMemoryDedicatedRequirements memDedicatedRequirements; @@ -91,6 +107,37 @@ TextureHandle::TextureHandle(PGraphics graphics, VkImageViewType viewType, uint3 allocation = allocator->allocate(requirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, image); vkBindImageMemory(graphics->getDevice(), image, allocation->getHandle(), allocation->getOffset()); } + + const BulkResourceData& resourceData = createInfo.resourceData; + if(resourceData.size > 0) + { + changeLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + PStagingBuffer staging = graphics->getStagingManager()->allocateStagingBuffer(resourceData.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + void* data = staging->getMappedPointer(); + std::memcpy(data, resourceData.data, resourceData.size); + staging->flushMappedMemory(); + + PCommandBufferManager cmdBufferManager = graphics->getQueueCommands(currentOwner); + VkBufferImageCopy region; + region.bufferOffset = 0; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + + region.imageOffset = {0, 0, 0}; + region.imageExtent = {sizeX, sizeX, sizeZ}; + + vkCmdCopyBufferToImage(cmdBufferManager->getCommands()->getHandle(), + staging->getHandle(), image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + // When loading a texture from a file, we will almost always use it as a texture map for fragment shaders + changeLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + VkImageViewCreateInfo viewInfo = init::ImageViewCreateInfo(); viewInfo.subresourceRange = init::ImageSubresourceRange(aspect); @@ -106,7 +153,7 @@ TextureHandle::TextureHandle(PGraphics graphics, VkImageViewType viewType, uint3 TextureHandle::~TextureHandle() { auto &deletionQueue = graphics->getDeletionQueue(); - auto fence = getCommands()->getCommands()->getFence(); + auto fence = graphics->getQueueCommands(currentOwner)->getCommands()->getFence(); VkDevice device = graphics->getDevice(); VkImageView view = defaultView; VkImage img = image; @@ -114,6 +161,20 @@ TextureHandle::~TextureHandle() deletionQueue.addPendingDelete(fence, [device, img]() { vkDestroyImage(device, img, nullptr); }); } +void TextureHandle::changeLayout(VkImageLayout newLayout) +{ + VkImageMemoryBarrier barrier = + init::ImageMemoryBarrier( + image, + layout, + newLayout); + PCommandBufferManager cmdManager = graphics->getQueueCommands(currentOwner); + vkCmdPipelineBarrier(cmdManager->getCommands()->getHandle(), + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + 0, 0, nullptr, 0, nullptr, 1, &barrier); + layout = newLayout; +} + void TextureHandle::executeOwnershipBarrier(Gfx::QueueType newOwner) { VkImageMemoryBarrier imageBarrier = @@ -122,11 +183,11 @@ void TextureHandle::executeOwnershipBarrier(Gfx::QueueType newOwner) imageBarrier.oldLayout = layout; imageBarrier.newLayout = layout; imageBarrier.subresourceRange = init::ImageSubresourceRange(aspect); - PCommandBufferManager sourceManager = getCommands(); + PCommandBufferManager sourceManager = graphics->getQueueCommands(currentOwner); PCommandBufferManager dstManager = nullptr; VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; VkPipelineStageFlags dstStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - QueueFamilyMapping mapping = graphics->getFamilyMapping(); + Gfx::QueueFamilyMapping mapping = graphics->getFamilyMapping(); imageBarrier.srcQueueFamilyIndex = mapping.getQueueTypeFamilyIndex(currentOwner); imageBarrier.dstQueueFamilyIndex = mapping.getQueueTypeFamilyIndex(newOwner); if (currentOwner == Gfx::QueueType::TRANSFER || currentOwner == Gfx::QueueType::DEDICATED_TRANSFER) @@ -150,7 +211,7 @@ void TextureHandle::executeOwnershipBarrier(Gfx::QueueType newOwner) dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; dstManager = graphics->getTransferCommands(); } - else if (currentOwner == Gfx::QueueType::DEDICATED_TRANSFER) + else if (newOwner == Gfx::QueueType::DEDICATED_TRANSFER) { imageBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT; @@ -173,30 +234,25 @@ void TextureHandle::executeOwnershipBarrier(Gfx::QueueType newOwner) vkCmdPipelineBarrier(sourceCmd, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &imageBarrier); vkCmdPipelineBarrier(destCmd, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &imageBarrier); sourceManager->submitCommands(); - cachedCmdBufferManager = dstManager; } void TextureBase::changeLayout(VkImageLayout newLayout) { - VkImageMemoryBarrier barrier = - init::ImageMemoryBarrier( - textureHandle->image, - textureHandle->layout, - newLayout); - vkCmdPipelineBarrier(textureHandle->getCommands()->getCommands()->getHandle(), - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - 0, 0, nullptr, 0, nullptr, 1, &barrier); - textureHandle->layout = newLayout; + textureHandle->changeLayout(newLayout); } -Texture2D::Texture2D(PGraphics graphics, uint32 sizeX, uint32 sizeY, - bool bArray, uint32 arraySize, uint32 mipLevels, Gfx::SeFormat format, - uint32 samples, Gfx::SeImageUsageFlags usage, Gfx::QueueType owner, VkImage existingImage) +Texture2D::Texture2D(PGraphics graphics, const TextureCreateInfo& createInfo, VkImage existingImage) + : Gfx::Texture2D(graphics, createInfo.resourceData.owner) { - textureHandle = new TextureHandle(graphics, bArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, - sizeX, sizeY, 1, bArray, arraySize, mipLevels, format, samples, usage, owner, existingImage); + textureHandle = new TextureHandle(graphics, createInfo.bArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, + createInfo, existingImage); } Texture2D::~Texture2D() { +} + +void Texture2D::executeOwnershipBarrier(Gfx::QueueType newOwner) +{ + textureHandle->executeOwnershipBarrier(newOwner); } \ No newline at end of file diff --git a/src/Engine/Graphics/Vulkan/VulkanViewport.cpp b/src/Engine/Graphics/Vulkan/VulkanViewport.cpp index eaa53e7..1820510 100644 --- a/src/Engine/Graphics/Vulkan/VulkanViewport.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanViewport.cpp @@ -181,13 +181,17 @@ void Window::createSwapchain() PCmdBuffer cmdBuffer = graphics->getGraphicsCommands()->getCommands(); + TextureCreateInfo backBufferCreateInfo; + backBufferCreateInfo.width = sizeX; + backBufferCreateInfo.height = sizeY; + backBufferCreateInfo.usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + backBufferCreateInfo.resourceData.owner = Gfx::QueueType::GRAPHICS; + backBufferCreateInfo.format = cast(surfaceFormat.format); for (uint32 i = 0; i < numSwapchainImages; ++i) { imageAcquired[i] = new Semaphore(graphics); renderFinished[i] = new Semaphore(graphics); - backBufferImages[i] = new Texture2D(graphics, sizeX, sizeY, false, 1, 1, - cast(surfaceFormat.format), 1, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - Gfx::QueueType::GRAPHICS, swapchainImages[i]); + backBufferImages[i] = new Texture2D(graphics, backBufferCreateInfo, swapchainImages[i]); VkClearColorValue clearColor; std::memset(&clearColor, 0, sizeof(VkClearColorValue)); diff --git a/src/Engine/Graphics/WindowManager.cpp b/src/Engine/Graphics/WindowManager.cpp index 14291ca..891d7ce 100644 --- a/src/Engine/Graphics/WindowManager.cpp +++ b/src/Engine/Graphics/WindowManager.cpp @@ -1,6 +1,8 @@ #include "WindowManager.h" #include "Vulkan/VulkanGraphics.h" +Gfx::PGraphics WindowManager::graphics; + Seele::WindowManager::WindowManager() { graphics = new Vulkan::Graphics(); diff --git a/src/Engine/Graphics/WindowManager.h b/src/Engine/Graphics/WindowManager.h index 358af0b..b2235b5 100644 --- a/src/Engine/Graphics/WindowManager.h +++ b/src/Engine/Graphics/WindowManager.h @@ -14,7 +14,7 @@ public: PWindow addWindow(const WindowCreateInfo &createInfo); void beginFrame(); void endFrame(); - Gfx::PGraphics getGraphics() + static Gfx::PGraphics getGraphics() { return graphics; } @@ -25,7 +25,7 @@ public: private: Array windows; - Gfx::PGraphics graphics; + static Gfx::PGraphics graphics; }; DEFINE_REF(WindowManager); } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Material/CMakeLists.txt b/src/Engine/Material/CMakeLists.txt index 9174620..54d19d0 100644 --- a/src/Engine/Material/CMakeLists.txt +++ b/src/Engine/Material/CMakeLists.txt @@ -2,5 +2,8 @@ target_sources(SeeleEngine PRIVATE Material.h Material.cpp + MaterialAsset.h + MaterialAsset.cpp MaterialInstance.h - MaterialInstance.cpp) \ No newline at end of file + MaterialInstance.cpp + ShaderExpression.h) \ No newline at end of file diff --git a/src/Engine/Material/Material.cpp b/src/Engine/Material/Material.cpp index e41c5ee..b397194 100644 --- a/src/Engine/Material/Material.cpp +++ b/src/Engine/Material/Material.cpp @@ -1,5 +1,7 @@ #include "Material.h" +#include "Asset/AssetRegistry.h" #include +#include using namespace Seele; using json = nlohmann::json; @@ -9,29 +11,84 @@ Material::Material() } Material::Material(const std::string& directory, const std::string& name) - : FileAsset(directory, name) + : MaterialAsset(directory, name) { } Material::Material(const std::string& fullPath) - : FileAsset(fullPath) -{ + : MaterialAsset(fullPath) +{ } Material::~Material() { } + void Material::compile() { auto& stream = getReadStream(); - stream.seekg(0); json j; stream >> j; - std::cout << j["test"] << std::endl; -} + std::stringstream codeStream; + materialName = j["name"].get(); + std::string profile = j["profile"].get(); + codeStream << "import LightEnv;" << std::endl; + codeStream << "import Material;" << std::endl; + codeStream << "import BRDF;" << std::endl; + codeStream << "import InputGeometry;" << std::endl; -Gfx::PGraphicsPipeline Material::getPipeline() -{ - return pipeline; + codeStream << "struct " << materialName << ": IMaterial {" << std::endl; + for(auto param : j["params"].items()) + { + std::string type = param.value()["type"].get(); + + auto default = param.value().find("default"); + if(type.compare("float") == 0) + { + PFloatParameter p = new FloatParameter(); + if(default != param.value().end()) + { + p->defaultValue = std::stof(default.value().get()); + } + parameters.add(p); + } + else if(type.compare("float3") == 0) + { + PVectorParameter p = new VectorParameter(); + if(default != param.value().end()) + { + p->defaultValue = parseVector(default.value().get().c_str()); + } + parameters.add(p); + } + else if(type.compare("Texture2D") == 0) + { + PTextureParameter p = new TextureParameter(); + if(default != param.value().end()) + { + + } + parameters.add(p); + } + else if(type.compare("SamplerState") == 0) + { + PSamplerParameter p = new SamplerParameter(); + parameters.add(p); + } + else + { + std::cout << "Error unsupported parameter type" << std::endl; + } + codeStream << type << " " << param.key(); + } + codeStream << "typedef " << profile << " BRDF;" << std::endl; + codeStream << profile << " prepare(MaterialPixelParameter geometry){" << std::endl; + codeStream << profile << " result;" << std::endl; + for(auto c : j["code"].items()) + { + codeStream << c.value().get() << std::endl; + } + + codeStream << "}};" << std::endl; } \ No newline at end of file diff --git a/src/Engine/Material/Material.h b/src/Engine/Material/Material.h index 3514b50..0cc6a03 100644 --- a/src/Engine/Material/Material.h +++ b/src/Engine/Material/Material.h @@ -1,44 +1,22 @@ #pragma once #include "MinimalEngine.h" -#include "Asset/FileAsset.h" -#include "Graphics/GraphicsResources.h" -#include +#include "MaterialAsset.h" namespace Seele { -struct FloatExpression -{ - float data; - std::string name; - uint32 location; -}; -struct VectorExpression -{ - Vector data; - std::string name; - uint32 location; -}; -struct TextureExpression -{ - Gfx::PTexture texture; - std::string name; - uint32 location; -}; -DECLARE_NAME_REF(Gfx, GraphicsPipeline); -DECLARE_NAME_REF(Gfx, PipelineLayout); -class Material : public FileAsset + +class Material : public MaterialAsset { public: Material(); Material(const std::string &directory, const std::string &name); Material(const std::string &fullPath); ~Material(); - void compile(); - Gfx::PGraphicsPipeline getPipeline(); - + inline std::string getMaterialName() const {return materialName;} private: - Gfx::PGraphicsPipeline pipeline; - Gfx::PPipelineLayout pipelineLayout; + void compile(); + std::string materialName; + friend class MaterialLoader; }; DEFINE_REF(Material); } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Material/MaterialAsset.cpp b/src/Engine/Material/MaterialAsset.cpp new file mode 100644 index 0000000..792cb5f --- /dev/null +++ b/src/Engine/Material/MaterialAsset.cpp @@ -0,0 +1,21 @@ +#include "MaterialAsset.h" + +using namespace Seele; + +MaterialAsset::MaterialAsset() +{ +} + +MaterialAsset::MaterialAsset(const std::string& directory, const std::string& name) + : Asset(directory, name) +{ +} + +MaterialAsset::MaterialAsset(const std::string& fullPath) + : Asset(fullPath) +{ +} + +MaterialAsset::~MaterialAsset() +{ +} diff --git a/src/Engine/Material/MaterialAsset.h b/src/Engine/Material/MaterialAsset.h new file mode 100644 index 0000000..ccabd49 --- /dev/null +++ b/src/Engine/Material/MaterialAsset.h @@ -0,0 +1,19 @@ +#pragma once +#include "Asset/Asset.h" +#include "ShaderExpression.h" + +namespace Seele +{ +class MaterialAsset : public Asset +{ +public: + MaterialAsset(); + MaterialAsset(const std::string &directory, const std::string &name); + MaterialAsset(const std::string &fullPath); + ~MaterialAsset(); +protected: + //For now its simply the collection of parameters, since there is no point for expressions + Array parameters; +}; +DEFINE_REF(MaterialAsset); +} // namespace Seele diff --git a/src/Engine/Material/MaterialInstance.cpp b/src/Engine/Material/MaterialInstance.cpp index b3d6821..34c2e98 100644 --- a/src/Engine/Material/MaterialInstance.cpp +++ b/src/Engine/Material/MaterialInstance.cpp @@ -8,12 +8,12 @@ MaterialInstance::MaterialInstance() } MaterialInstance::MaterialInstance(const std::string& directory, const std::string& name) - : FileAsset(directory, name) + : Asset(directory, name) { } MaterialInstance::MaterialInstance(const std::string& fullPath) - : FileAsset(fullPath) + : Asset(fullPath) { } diff --git a/src/Engine/Material/MaterialInstance.h b/src/Engine/Material/MaterialInstance.h index 8e45741..59c71a2 100644 --- a/src/Engine/Material/MaterialInstance.h +++ b/src/Engine/Material/MaterialInstance.h @@ -1,11 +1,11 @@ #pragma once -#include "Asset/FileAsset.h" +#include "Asset/Asset.h" namespace Seele { DECLARE_NAME_REF(Gfx, DescriptorSet); DECLARE_REF(Material); -class MaterialInstance : public FileAsset +class MaterialInstance : public Asset { public: MaterialInstance(); diff --git a/src/Engine/Material/ShaderExpression.h b/src/Engine/Material/ShaderExpression.h new file mode 100644 index 0000000..def0fd4 --- /dev/null +++ b/src/Engine/Material/ShaderExpression.h @@ -0,0 +1,79 @@ +#pragma once +#include "MinimalEngine.h" + +namespace Seele +{ +struct ExpressionInput +{ + +}; +struct ExpressionOutput +{ + +}; +struct ShaderExpression +{ +}; +struct ShaderParameter : public ShaderExpression +{ + std::string name; +}; +DEFINE_REF(ShaderParameter); +struct FloatParameter : public ShaderParameter +{ + float defaultValue; + bool setParameter(const std::string& paramName, float newDefault) + { + if(name.compare(paramName) == 0) + { + defaultValue = newDefault; + return true; + } + return false; + } +}; +DEFINE_REF(FloatParameter); +struct VectorParameter : public ShaderParameter +{ + Vector defaultValue; + bool setParameter(const std::string& paramName, Vector newDefault) + { + if(name.compare(paramName) == 0) + { + defaultValue = newDefault; + return true; + } + return false; + } +}; +DEFINE_REF(VectorParameter); +DECLARE_NAME_REF(Gfx, Texture2D); +struct TextureParameter : public ShaderParameter +{ + Gfx::PTexture2D defaultValue; + bool setParameter(const std::string& paramName, Gfx::PTexture2D newDefault) + { + if(name.compare(paramName) == 0) + { + return true; + } + return false; + } +}; +DEFINE_REF(TextureParameter); +DECLARE_NAME_REF(Gfx, SamplerState); +struct SamplerParameter : public ShaderParameter +{ + Gfx::PSamplerState defaultValue; + bool setParameter(const std::string& paramName, Gfx::PSamplerState newDefault) + { + if(name.compare(paramName) == 0) + { + return true; + } + return false; + } +}; +DEFINE_REF(SamplerParameter); + +} // namespace Seele diff --git a/src/Engine/Math/CMakeLists.txt b/src/Engine/Math/CMakeLists.txt index 55dc26a..dc535d0 100644 --- a/src/Engine/Math/CMakeLists.txt +++ b/src/Engine/Math/CMakeLists.txt @@ -3,5 +3,6 @@ target_sources(SeeleEngine Math.h Matrix.h Vector.h + Vector.cpp Transform.h Transform.cpp) \ No newline at end of file diff --git a/src/Engine/Math/Math.h b/src/Engine/Math/Math.h index 44cb866..885473c 100644 --- a/src/Engine/Math/Math.h +++ b/src/Engine/Math/Math.h @@ -1,3 +1,4 @@ +#pragma once #include "Vector.h" #include "Matrix.h" #include "EngineTypes.h" diff --git a/src/Engine/Math/Transform.cpp b/src/Engine/Math/Transform.cpp index 4913bb6..3691c9e 100644 --- a/src/Engine/Math/Transform.cpp +++ b/src/Engine/Math/Transform.cpp @@ -181,9 +181,10 @@ Transform &Transform::operator=(Transform &&other) return *this; } -Transform &Transform::operator*(const Transform &other) const +Transform &Transform::operator*(const Transform &other) { Transform outTransform; multiply(&outTransform, this, &other); - return outTransform; + *this = std::move(outTransform); + return *this; } diff --git a/src/Engine/Math/Transform.h b/src/Engine/Math/Transform.h index 285dc62..bd18a59 100644 --- a/src/Engine/Math/Transform.h +++ b/src/Engine/Math/Transform.h @@ -28,7 +28,7 @@ public: Transform &operator=(const Transform &other); Transform &operator=(Transform &&other); - Transform &operator*(const Transform &other) const; + Transform &operator*(const Transform &other); private: Vector4 position; diff --git a/src/Engine/Math/Vector.cpp b/src/Engine/Math/Vector.cpp new file mode 100644 index 0000000..f55ec33 --- /dev/null +++ b/src/Engine/Math/Vector.cpp @@ -0,0 +1,17 @@ +#include "Vector.h" +#include + +using namespace Seele; + +Vector Seele::parseVector(const char* str) +{ + //regex pattern consisting of 'float3(xComp, yComp, zComp)', more also matches for invalid floats, but that will throw later + std::regex pattern("float3\\(\\s*([0-9.]+f?)\\s*,\\s*([0-9.]+f?)\\s*,\\s*([0-9.]+f?)\\s*\\)"); + std::cmatch base_match; + std::regex_match(str, base_match, pattern); + //match 0 is the whole expression + float x = std::stof(base_match[1].str()); + float y = std::stof(base_match[2].str()); + float z = std::stof(base_match[3].str()); + return Vector(x, y, z); +} \ No newline at end of file diff --git a/src/Engine/Math/Vector.h b/src/Engine/Math/Vector.h index cccafab..81c8142 100644 --- a/src/Engine/Math/Vector.h +++ b/src/Engine/Math/Vector.h @@ -22,6 +22,8 @@ typedef glm::ivec4 IVector4; typedef glm::quat Quaternion; +Vector parseVector(const char*); + static inline float square(float x) { return x * x; diff --git a/src/Engine/MinimalEngine.h b/src/Engine/MinimalEngine.h index 3a5a582..2187007 100644 --- a/src/Engine/MinimalEngine.h +++ b/src/Engine/MinimalEngine.h @@ -1,9 +1,4 @@ #pragma once -#include -#include -#include -#include -#include #include "Containers/Map.h" #include "EngineTypes.h" #include "Math/Math.h" @@ -52,7 +47,10 @@ public: ~RefObject() { registeredObjects.erase(handle); +// we cant always have the definition of every class +#pragma warning(disable : 4150) delete handle; +#pragma warning(default : 4150) } RefObject &operator=(const RefObject &rhs) { @@ -74,15 +72,15 @@ public: } return *this; } - bool operator==(const RefObject &other) const + inline bool operator==(const RefObject &other) const { return handle == other.handle; } - bool operator!=(const RefObject &other) const + inline bool operator!=(const RefObject &other) const { return handle != other.handle; } - bool operator<(const RefObject &other) const + inline bool operator<(const RefObject &other) const { return handle < other.handle; } @@ -90,7 +88,7 @@ public: { refCount++; } - void removeRef() + inline void removeRef() { refCount--; if (refCount.load() == 0) @@ -222,11 +220,11 @@ public: object->removeRef(); } } - bool operator==(const RefPtr &other) const + inline bool operator==(const RefPtr &other) const { return object == other.object; } - bool operator!=(const RefPtr &other) const + inline bool operator!=(const RefPtr &other) const { return object != other.object; } @@ -234,12 +232,12 @@ public: { return object < other.object; } - T *operator->() + inline T *operator->() { assert(object != nullptr); return object->getHandle(); } - const T *operator->() const + inline const T *operator->() const { assert(object != nullptr); return object->getHandle(); @@ -248,11 +246,11 @@ public: { return object; } - T *getHandle() + inline T *getHandle() { return object->getHandle(); } - const T *getHandle() const + inline const T *getHandle() const { return object->getHandle(); } @@ -291,6 +289,14 @@ template class UniquePtr { public: + UniquePtr() + : handle(nullptr) + { + } + UniquePtr(nullptr_t) + : handle(nullptr) + { + } UniquePtr(T *ptr) : handle(ptr) { diff --git a/src/Engine/Scene/Components/CMakeLists.txt b/src/Engine/Scene/Components/CMakeLists.txt index ba4188d..3871b11 100644 --- a/src/Engine/Scene/Components/CMakeLists.txt +++ b/src/Engine/Scene/Components/CMakeLists.txt @@ -3,4 +3,5 @@ target_sources(SeeleEngine Component.h Component.cpp PrimitiveComponent.cpp - PrimitiveComponent.h) \ No newline at end of file + PrimitiveComponent.h + PrimitiveUniformBufferLayout.h) \ No newline at end of file diff --git a/src/Engine/Scene/Components/PrimitiveComponent.h b/src/Engine/Scene/Components/PrimitiveComponent.h index cbd0896..62ebffd 100644 --- a/src/Engine/Scene/Components/PrimitiveComponent.h +++ b/src/Engine/Scene/Components/PrimitiveComponent.h @@ -1,7 +1,9 @@ #pragma once #include "Component.h" #include "Graphics/GraphicsResources.h" +#include "Graphics/Mesh.h" #include "Material/MaterialInstance.h" +#include "Graphics/MeshBatch.h" namespace Seele { @@ -14,9 +16,10 @@ public: Matrix4 getRenderMatrix(); private: - PMaterialInstance instance; - Gfx::PVertexBuffer vertexBuffer; - Gfx::PIndexBuffer indexBuffer; + Array materials; + Gfx::PUniformBuffer uniformBuffer; + Array staticMeshes; + PMesh mesh; friend class Scene; }; DEFINE_REF(PrimitiveComponent); diff --git a/src/Engine/Scene/Components/PrimitiveUniformBufferLayout.h b/src/Engine/Scene/Components/PrimitiveUniformBufferLayout.h new file mode 100644 index 0000000..e8c5a52 --- /dev/null +++ b/src/Engine/Scene/Components/PrimitiveUniformBufferLayout.h @@ -0,0 +1,12 @@ +#pragma once +#include "Graphics/GraphicsResources.h" + +namespace Seele +{ +struct PrimitiveUniformBuffer +{ + Matrix4 localToWorld; + Vector4 worldToLocal; + Vector4 actorWorldPosition; +}; +} // namespace Seele diff --git a/src/Engine/Scene/Scene.cpp b/src/Engine/Scene/Scene.cpp index c163f22..ab0934c 100644 --- a/src/Engine/Scene/Scene.cpp +++ b/src/Engine/Scene/Scene.cpp @@ -32,14 +32,15 @@ void Scene::addPrimitiveComponent(PPrimitiveComponent comp) primitives.add(comp); } -Map Scene::getMeshBatches() +Map Scene::getMeshBatches() { meshBatches.clear(); for (auto primitive : primitives) { - PMaterialInstance matInstance = primitive->instance; + /* Array materials = primitive->materials; + PMaterialInstance matInstance = primitive->; PMaterial mat = matInstance->getBaseMaterial(); - DrawInstance inst; + MeshBatch inst; inst.instance = primitive->instance; inst.vertexBuffer = primitive->vertexBuffer; inst.indexBuffer = primitive->indexBuffer; @@ -47,15 +48,15 @@ Map Scene::getMeshBatches() if (meshBatches.find(mat) != meshBatches.end()) { - DrawState &state = meshBatches[mat]; + MeshBatchElement &state = meshBatches[mat]; state.instances.add(inst); } else { - DrawState state; + MeshBatchElement state; state.instances.add(inst); meshBatches[mat] = state; - } + }*/ } return meshBatches; } \ No newline at end of file diff --git a/src/Engine/Scene/Scene.h b/src/Engine/Scene/Scene.h index d5b70b5..0bea77b 100644 --- a/src/Engine/Scene/Scene.h +++ b/src/Engine/Scene/Scene.h @@ -3,6 +3,8 @@ #include "Actor/Actor.h" #include "Graphics/GraphicsResources.h" #include "Components/PrimitiveComponent.h" +#include "Graphics/MeshBatch.h" +#include "Material/Material.h" namespace Seele { @@ -18,11 +20,11 @@ public: void addPrimitiveComponent(PPrimitiveComponent comp); private: - Map meshBatches; + Map meshBatches; Array rootActors; Array primitives; - + const static int constant = 10; public: - Map getMeshBatches(); + Map getMeshBatches(); }; } // namespace Seele \ No newline at end of file diff --git a/src/Engine/main.cpp b/src/Engine/main.cpp index 52b29c9..ee8f030 100644 --- a/src/Engine/main.cpp +++ b/src/Engine/main.cpp @@ -1,9 +1,12 @@ #include "Graphics/RenderCore.h" +#include "Asset/AssetRegistry.h" using namespace Seele; int main() { RenderCore core; core.init(); + AssetRegistry::init("./"); + AssetRegistry::importFile("D:\\Private\\Programming\\Unreal Engine\\Assets\\TestAssets\\Unbenannt.fbx"); core.renderLoop(); core.shutdown(); return 0; diff --git a/test.mat b/test.mat deleted file mode 100644 index c6b2d89..0000000 --- a/test.mat +++ /dev/null @@ -1,3 +0,0 @@ -{ - "test": "Hello World" -} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e68159a..c4dd8a6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,9 +5,24 @@ find_package(Boost COMPONENTS unit_test_framework REQUIRED) include_directories(${ENGINE_ROOT}) include_directories(${Boost_INCLUDE_DIRS}) -add_executable(Seele_unit_tests "") add_subdirectory(Engine/) target_link_libraries(Seele_unit_tests ${Boost_LIBRARIES}) +target_precompile_headers(Seele_unit_tests + PRIVATE + + + + + + + + + + + + ) + + enable_testing() add_test(SeeleEngineTest Seele_unit_tests) diff --git a/test/Engine/CMakeLists.txt b/test/Engine/CMakeLists.txt index 38c10ff..86f8b74 100644 --- a/test/Engine/CMakeLists.txt +++ b/test/Engine/CMakeLists.txt @@ -5,4 +5,5 @@ target_sources(Seele_unit_tests EngineTest.cpp) target_include_directories(Seele_unit_tests PUBLIC ./) add_subdirectory(Containers/) -add_subdirectory(Graphics/) \ No newline at end of file +add_subdirectory(Graphics/) +add_subdirectory(Math/) \ No newline at end of file diff --git a/test/Engine/Math/CMakeLists.txt b/test/Engine/Math/CMakeLists.txt new file mode 100644 index 0000000..1b16358 --- /dev/null +++ b/test/Engine/Math/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(Seele_unit_tests + PRIVATE + ../../../src/Engine/Math/Vector.cpp + Vector.cpp) \ No newline at end of file diff --git a/test/Engine/Math/Vector.cpp b/test/Engine/Math/Vector.cpp new file mode 100644 index 0000000..6df3059 --- /dev/null +++ b/test/Engine/Math/Vector.cpp @@ -0,0 +1,45 @@ +#include "EngineTest.h" +#include "Math/Vector.h" +#include + +using namespace Seele; + +BOOST_AUTO_TEST_SUITE(VectorParse) + +BOOST_AUTO_TEST_CASE(parse_vector_basic) +{ + const char* str = "float3(0, 0, 0)"; + Vector vec = parseVector(str); + BOOST_CHECK_EQUAL(vec.x, 0); + BOOST_CHECK_EQUAL(vec.y, 0); + BOOST_CHECK_EQUAL(vec.z, 0); +} + +BOOST_AUTO_TEST_CASE(parse_vector_literal) +{ + const char* str = "float3(0.0f, 0.0f, 0.0f)"; + Vector vec = parseVector(str); + BOOST_CHECK_EQUAL(vec.x, 0); + BOOST_CHECK_EQUAL(vec.y, 0); + BOOST_CHECK_EQUAL(vec.z, 0); +} + +BOOST_AUTO_TEST_CASE(parse_vector_no_literal) +{ + const char* str = "float3(0.0, 0.0, 0.0)"; + Vector vec = parseVector(str); + BOOST_CHECK_EQUAL(vec.x, 0); + BOOST_CHECK_EQUAL(vec.y, 0); + BOOST_CHECK_EQUAL(vec.z, 0); +} + +BOOST_AUTO_TEST_CASE(parse_vector_float) +{ + const char* str = "float3(0.01, 0.01f, 0.01f)"; + Vector vec = parseVector(str); + BOOST_CHECK_EQUAL(vec.x, 0.01f); + BOOST_CHECK_EQUAL(vec.y, 0.01f); + BOOST_CHECK_EQUAL(vec.z, 0.01f); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file