mirror of
https://github.com/ZDoom/ZDRay.git
synced 2024-11-10 06:41:37 +00:00
Add first steps in using the GPU for the ray tracing
This commit is contained in:
parent
410a0e0c7c
commit
3e11f81d5a
9 changed files with 4240 additions and 5 deletions
151
CMakeLists.txt
151
CMakeLists.txt
|
@ -163,6 +163,13 @@ set( SOURCES
|
||||||
src/lightmap/collision.cpp
|
src/lightmap/collision.cpp
|
||||||
src/lightmap/delauneytriangulator.cpp
|
src/lightmap/delauneytriangulator.cpp
|
||||||
src/lightmap/delauneytriangulator.h
|
src/lightmap/delauneytriangulator.h
|
||||||
|
src/lightmap/vulkandevice.cpp
|
||||||
|
src/lightmap/vulkandevice.h
|
||||||
|
src/lightmap/vulkanobjects.h
|
||||||
|
src/lightmap/vulkanbuilders.cpp
|
||||||
|
src/lightmap/vulkanbuilders.h
|
||||||
|
src/lightmap/gpuraytracer.cpp
|
||||||
|
src/lightmap/gpuraytracer.h
|
||||||
src/math/angle.cpp
|
src/math/angle.cpp
|
||||||
src/math/bounds.cpp
|
src/math/bounds.cpp
|
||||||
src/math/mathlib.cpp
|
src/math/mathlib.cpp
|
||||||
|
@ -210,6 +217,128 @@ set( HEADERS
|
||||||
src/math/mathlib.h
|
src/math/mathlib.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(THIRDPARTY_SOURCES
|
||||||
|
../thirdparty/vk_mem_alloc/vk_mem_alloc.h
|
||||||
|
../thirdparty/vk_mem_alloc/vk_mem_alloc.cpp
|
||||||
|
../thirdparty/volk/volk.c
|
||||||
|
../thirdparty/volk/volk.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/SymbolTable.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/propagateNoContraction.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/PoolAlloc.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/Intermediate.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/gl_types.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/parseVersions.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/attribute.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/Scan.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/iomapper.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/ParseHelper.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/glslang_tab.cpp.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/SymbolTable.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/RemoveTree.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/Versions.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/reflection.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/LiveTraverser.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/iomapper.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/intermOut.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/Versions.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/Initialize.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/linkValidate.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/InfoSink.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/Constant.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/IntermTraverse.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/propagateNoContraction.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/glslang_tab.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/ShaderLang.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/preprocessor/Pp.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/preprocessor/PpTokens.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/preprocessor/PpAtom.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/preprocessor/PpContext.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/preprocessor/PpTokens.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/preprocessor/PpScanner.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/preprocessor/PpContext.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/attribute.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/localintermediate.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/parseConst.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/Initialize.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/limits.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/ParseContextBase.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/RemoveTree.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/ParseHelper.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/Scan.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/reflection.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/MachineIndependent/ScanContext.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/OSDependent/osinclude.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/GenericCodeGen/Link.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/GenericCodeGen/CodeGen.cpp
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Public/ShaderLang.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/ConstantUnion.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/InitializeGlobals.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/Common.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/PoolAlloc.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/arrays.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/ShHandle.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/InfoSink.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/ResourceLimits.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/Types.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/revision.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/BaseTypes.h
|
||||||
|
../thirdparty/ShaderCompiler/glslang/Include/intermediate.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/Logger.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/GlslangToSpv.cpp
|
||||||
|
../thirdparty/ShaderCompiler/spirv/SPVRemapper.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/GLSL.ext.EXT.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/hex_float.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/doc.cpp
|
||||||
|
../thirdparty/ShaderCompiler/spirv/disassemble.cpp
|
||||||
|
../thirdparty/ShaderCompiler/spirv/SpvPostProcess.cpp
|
||||||
|
../thirdparty/ShaderCompiler/spirv/bitutils.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/InReadableOrder.cpp
|
||||||
|
../thirdparty/ShaderCompiler/spirv/GLSL.ext.AMD.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/GLSL.ext.NV.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/SPVRemapper.cpp
|
||||||
|
../thirdparty/ShaderCompiler/spirv/SpvBuilder.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/GLSL.ext.KHR.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/disassemble.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/SpvBuilder.cpp
|
||||||
|
../thirdparty/ShaderCompiler/spirv/GlslangToSpv.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/doc.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/SpvTools.cpp
|
||||||
|
../thirdparty/ShaderCompiler/spirv/spvIR.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/Logger.cpp
|
||||||
|
../thirdparty/ShaderCompiler/spirv/SpvTools.h
|
||||||
|
../thirdparty/ShaderCompiler/spirv/GLSL.std.450.h
|
||||||
|
../thirdparty/ShaderCompiler/OGLCompilersDLL/InitializeDll.cpp
|
||||||
|
../thirdparty/ShaderCompiler/OGLCompilersDLL/InitializeDll.h
|
||||||
|
../thirdparty/vulkan/vk_sdk_platform.h
|
||||||
|
../thirdparty/vulkan/vulkan_fuchsia.h
|
||||||
|
../thirdparty/vulkan/vulkan_win32.h
|
||||||
|
../thirdparty/vulkan/vulkan_ios.h
|
||||||
|
../thirdparty/vulkan/vk_icd.h
|
||||||
|
../thirdparty/vulkan/vk_layer.h
|
||||||
|
../thirdparty/vulkan/vulkan_xcb.h
|
||||||
|
../thirdparty/vulkan/vulkan_macos.h
|
||||||
|
../thirdparty/vulkan/vk_layer_dispatch_table.h
|
||||||
|
../thirdparty/vulkan/vulkan_ggp.h
|
||||||
|
../thirdparty/vulkan/vulkan_core.h
|
||||||
|
../thirdparty/vulkan/vulkan_wayland.h
|
||||||
|
../thirdparty/vulkan/vulkan_metal.h
|
||||||
|
../thirdparty/vulkan/vulkan_android.h
|
||||||
|
../thirdparty/vulkan/vulkan_vi.h
|
||||||
|
../thirdparty/vulkan/vulkan.h
|
||||||
|
../thirdparty/vulkan/vk_platform.h
|
||||||
|
../thirdparty/vulkan/vulkan_mir.h
|
||||||
|
../thirdparty/vulkan/vulkan_xlib_xrandr.h
|
||||||
|
../thirdparty/vulkan/vulkan_xlib.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(THIRDPARTY_WIN32_SOURCES
|
||||||
|
../thirdparty/ShaderCompiler/glslang/OSDependent/Windows/ossource.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(THIRDPARTY_UNIX_SOURCES
|
||||||
|
../thirdparty/ShaderCompiler/glslang/OSDependent/Unix/ossource.cpp
|
||||||
|
)
|
||||||
|
|
||||||
if( SSE_MATTERS )
|
if( SSE_MATTERS )
|
||||||
if( FULL_SSE2 )
|
if( FULL_SSE2 )
|
||||||
message( STATUS "Using SSE2 math everywhere." )
|
message( STATUS "Using SSE2 math everywhere." )
|
||||||
|
@ -243,8 +372,20 @@ if( WIN32 )
|
||||||
else( CMAKE_COMPILER_IS_GNUCXX )
|
else( CMAKE_COMPILER_IS_GNUCXX )
|
||||||
set( SOURCES ${SOURCES} src/platform/windows/resource.rc )
|
set( SOURCES ${SOURCES} src/platform/windows/resource.rc )
|
||||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||||
|
|
||||||
|
set(THIRDPARTY_SOURCES ${THIRDPARTY_SOURCES} ${THIRDPARTY_WIN32_SOURCES})
|
||||||
|
else()
|
||||||
|
set(THIRDPARTY_SOURCES ${THIRDPARTY_SOURCES} ${THIRDPARTY_UNIX_SOURCES})
|
||||||
endif( WIN32 )
|
endif( WIN32 )
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
# Use all cores for compilation
|
||||||
|
set(CMAKE_CXX_FLAGS "/MP ${CMAKE_CXX_FLAGS}")
|
||||||
|
|
||||||
|
# Ignore warnings in third party code
|
||||||
|
set_source_files_properties(${THIRDPARTY_SOURCES} PROPERTIES COMPILE_FLAGS "/wd4244 /wd4267 /wd4005 /wd4018 -D_CRT_SECURE_NO_WARNINGS")
|
||||||
|
endif()
|
||||||
|
|
||||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||||
set( ZDRAY_LIBS "${ZLIB_LIBRARIES}" pthread )
|
set( ZDRAY_LIBS "${ZLIB_LIBRARIES}" pthread )
|
||||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||||
|
@ -265,9 +406,9 @@ set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
|
||||||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
|
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
|
||||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
|
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
|
||||||
|
|
||||||
add_executable( zdray ${SOURCES} ${HEADERS} )
|
add_executable( zdray ${SOURCES} ${HEADERS} ${THIRDPARTY_SOURCES} )
|
||||||
target_link_libraries( zdray ${ZDRAY_LIBS} ${PROF_LIB} )
|
target_link_libraries( zdray ${ZDRAY_LIBS} ${PROF_LIB} )
|
||||||
include_directories( src "${ZLIB_INCLUDE_DIR}" )
|
include_directories( src "${ZLIB_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty" )
|
||||||
|
|
||||||
source_group("Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/.+")
|
source_group("Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/.+")
|
||||||
source_group("Sources\\BlockmapBuilder" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/blockmapbuilder/.+")
|
source_group("Sources\\BlockmapBuilder" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/blockmapbuilder/.+")
|
||||||
|
@ -282,3 +423,9 @@ source_group("Sources\\Wad" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
source_group("Sources\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/math/.+")
|
source_group("Sources\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/math/.+")
|
||||||
source_group("Sources\\Lightmap" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/lightmap/.+")
|
source_group("Sources\\Lightmap" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/lightmap/.+")
|
||||||
source_group("Sources\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/models/.+")
|
source_group("Sources\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/models/.+")
|
||||||
|
|
||||||
|
source_group("thirdparty" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/.+")
|
||||||
|
source_group("thirdparty\\ShaderCompiler" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/ShaderCompiler/.+")
|
||||||
|
source_group("thirdparty\\vk_mem_alloc" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/vk_mem_alloc/.+")
|
||||||
|
source_group("thirdparty\\volk" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/volk/.+")
|
||||||
|
source_group("thirdparty\\vulkan" REGULAR_EXPRESSION "${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/vulkan/.+")
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "level/level.h"
|
#include "level/level.h"
|
||||||
#include "lightmap/lightmap.h"
|
#include "lightmap/lightmap.h"
|
||||||
#include "lightmap/raytracer.h"
|
#include "lightmap/raytracer.h"
|
||||||
|
#include "lightmap/gpuraytracer.h"
|
||||||
//#include "rejectbuilder.h"
|
//#include "rejectbuilder.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -687,15 +688,21 @@ void FProcessor::BuildNodes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#define USE_GPU_RAYTRACER
|
||||||
|
//#define USE_CPU_RAYTRACER
|
||||||
|
|
||||||
void FProcessor::BuildLightmaps()
|
void FProcessor::BuildLightmaps()
|
||||||
{
|
{
|
||||||
Level.SetupLights();
|
Level.SetupLights();
|
||||||
LightmapMesh = std::make_unique<LevelMesh>(Level, Samples, LMDims);
|
LightmapMesh = std::make_unique<LevelMesh>(Level, Samples, LMDims);
|
||||||
#if 1
|
#if defined(USE_GPU_RAYTRACER)
|
||||||
DLightRaytracer raytracer;
|
GPURaytracer raytracer;
|
||||||
|
raytracer.Raytrace(LightmapMesh.get());
|
||||||
|
#elif defined(USE_CPU_RAYTRACER)
|
||||||
|
Raytracer raytracer;
|
||||||
raytracer.Raytrace(LightmapMesh.get());
|
raytracer.Raytrace(LightmapMesh.get());
|
||||||
#else
|
#else
|
||||||
Raytracer raytracer;
|
DLightRaytracer raytracer;
|
||||||
raytracer.Raytrace(LightmapMesh.get());
|
raytracer.Raytrace(LightmapMesh.get());
|
||||||
#endif
|
#endif
|
||||||
LightmapMesh->CreateTextures();
|
LightmapMesh->CreateTextures();
|
||||||
|
|
330
src/lightmap/gpuraytracer.cpp
Normal file
330
src/lightmap/gpuraytracer.cpp
Normal file
|
@ -0,0 +1,330 @@
|
||||||
|
|
||||||
|
#include "math/mathlib.h"
|
||||||
|
#include "surfaces.h"
|
||||||
|
#include "level/level.h"
|
||||||
|
#include "gpuraytracer.h"
|
||||||
|
#include "surfacelight.h"
|
||||||
|
#include "worker.h"
|
||||||
|
#include "framework/binfile.h"
|
||||||
|
#include "framework/templates.h"
|
||||||
|
#include "framework/halffloat.h"
|
||||||
|
#include "vulkanbuilders.h"
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
extern int Multisample;
|
||||||
|
extern int LightBounce;
|
||||||
|
extern float GridSize;
|
||||||
|
|
||||||
|
GPURaytracer::GPURaytracer()
|
||||||
|
{
|
||||||
|
device = std::make_unique<VulkanDevice>();
|
||||||
|
}
|
||||||
|
|
||||||
|
GPURaytracer::~GPURaytracer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPURaytracer::Raytrace(LevelMesh* level)
|
||||||
|
{
|
||||||
|
mesh = level;
|
||||||
|
|
||||||
|
printf("Creating vertex and index buffers\n");
|
||||||
|
|
||||||
|
size_t vertexbuffersize = (size_t)mesh->MeshVertices.Size() * sizeof(Vec3);
|
||||||
|
size_t indexbuffersize = (size_t)mesh->MeshElements.Size() * sizeof(uint32_t);
|
||||||
|
size_t aabbbuffersize = sizeof(Vec3) * 2;
|
||||||
|
size_t transferbuffersize = vertexbuffersize + indexbuffersize + aabbbuffersize;
|
||||||
|
size_t vertexoffset = 0;
|
||||||
|
size_t indexoffset = vertexoffset + vertexbuffersize;
|
||||||
|
size_t aabboffset = indexoffset + indexbuffersize;
|
||||||
|
|
||||||
|
Vec3 aabbs[2] = { mesh->MeshVertices[0], mesh->MeshVertices[1] };
|
||||||
|
for (Vec3& v : mesh->MeshVertices)
|
||||||
|
{
|
||||||
|
aabbs[0].x = std::min(aabbs[0].x, v.x);
|
||||||
|
aabbs[0].y = std::min(aabbs[0].y, v.y);
|
||||||
|
aabbs[0].z = std::min(aabbs[0].z, v.z);
|
||||||
|
aabbs[1].x = std::max(aabbs[1].x, v.x);
|
||||||
|
aabbs[1].y = std::max(aabbs[1].y, v.y);
|
||||||
|
aabbs[1].z = std::max(aabbs[1].z, v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferBuilder vbuilder;
|
||||||
|
vbuilder.setUsage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
||||||
|
vbuilder.setSize(vertexbuffersize);
|
||||||
|
auto vertexBuffer = vbuilder.create(device.get());
|
||||||
|
|
||||||
|
BufferBuilder ibuilder;
|
||||||
|
ibuilder.setUsage(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
||||||
|
ibuilder.setSize(indexbuffersize);
|
||||||
|
auto indexBuffer = ibuilder.create(device.get());
|
||||||
|
|
||||||
|
BufferBuilder abuilder;
|
||||||
|
abuilder.setUsage(/*VK_BUFFER_USAGE_AABB_BUFFER_BIT |*/ VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
||||||
|
abuilder.setSize(aabbbuffersize);
|
||||||
|
auto aabbBuffer = abuilder.create(device.get());
|
||||||
|
|
||||||
|
BufferBuilder tbuilder;
|
||||||
|
tbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
|
||||||
|
tbuilder.setSize(transferbuffersize);
|
||||||
|
auto transferBuffer = tbuilder.create(device.get());
|
||||||
|
auto data = (uint8_t*)transferBuffer->Map(0, transferbuffersize);
|
||||||
|
memcpy(data + vertexoffset, mesh->MeshVertices.Data(), vertexbuffersize);
|
||||||
|
memcpy(data + indexoffset, mesh->MeshElements.Data(), indexbuffersize);
|
||||||
|
memcpy(data + aabboffset, aabbs, aabbbuffersize);
|
||||||
|
transferBuffer->Unmap();
|
||||||
|
|
||||||
|
printf("Creating bottom level acceleration structure\n");
|
||||||
|
|
||||||
|
AccelerationStructureBuilder blbuilder;
|
||||||
|
blbuilder.setUsage(VMA_MEMORY_USAGE_GPU_ONLY);
|
||||||
|
blbuilder.setType(VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV);
|
||||||
|
blbuilder.setInstanceCount(1);
|
||||||
|
blbuilder.addTriangles();
|
||||||
|
blbuilder.setVertices(vertexBuffer.get(), 0, mesh->MeshVertices.Size(), sizeof(Vec3), VK_FORMAT_R32G32B32_SFLOAT);
|
||||||
|
blbuilder.setIndices(indexBuffer.get(), 0, mesh->MeshElements.Size(), VK_INDEX_TYPE_UINT32);
|
||||||
|
auto blAccelStruct = blbuilder.create(device.get());
|
||||||
|
|
||||||
|
ScratchBufferBuilder blsbuilder;
|
||||||
|
blsbuilder.setAccelerationStruct(blAccelStruct.get());
|
||||||
|
auto blScratchBuffer = blsbuilder.create(device.get());
|
||||||
|
|
||||||
|
printf("Creating top level acceleration structure\n");
|
||||||
|
|
||||||
|
AccelerationStructureBuilder tlbuilder;
|
||||||
|
tlbuilder.setUsage(VMA_MEMORY_USAGE_GPU_ONLY);
|
||||||
|
tlbuilder.setType(VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV);
|
||||||
|
tlbuilder.setInstanceCount(1);
|
||||||
|
//tlbuilder.addAABBs(aabbBuffer.get(), 1, sizeof(Vec3) * 2, 0);
|
||||||
|
auto topLevel = tlbuilder.create(device.get());
|
||||||
|
|
||||||
|
printf("Tracing light probes\n");
|
||||||
|
|
||||||
|
Worker::RunJob((int)mesh->lightProbes.size(), [=](int id) {
|
||||||
|
RaytraceProbeSample(&mesh->lightProbes[id]);
|
||||||
|
});
|
||||||
|
|
||||||
|
printf("Tracing surfaces (%d bounces)\n", LightBounce);
|
||||||
|
|
||||||
|
struct SurfaceTask
|
||||||
|
{
|
||||||
|
int surf, x, y;
|
||||||
|
};
|
||||||
|
std::vector<SurfaceTask> tasks;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mesh->surfaces.size(); i++)
|
||||||
|
{
|
||||||
|
Surface* surface = mesh->surfaces[i].get();
|
||||||
|
int sampleWidth = surface->lightmapDims[0];
|
||||||
|
int sampleHeight = surface->lightmapDims[1];
|
||||||
|
for (int y = 0; y < sampleHeight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < sampleWidth; x++)
|
||||||
|
{
|
||||||
|
SurfaceTask task;
|
||||||
|
task.surf = (int)i;
|
||||||
|
task.x = x;
|
||||||
|
task.y = y;
|
||||||
|
tasks.push_back(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Worker::RunJob((int)tasks.size(), [=](int id) {
|
||||||
|
const SurfaceTask& task = tasks[id];
|
||||||
|
RaytraceSurfaceSample(mesh->surfaces[task.surf].get(), task.x, task.y);
|
||||||
|
});
|
||||||
|
|
||||||
|
printf("Raytrace complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPURaytracer::RaytraceProbeSample(LightProbeSample* probe)
|
||||||
|
{
|
||||||
|
Vec3 color(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
for (ThingLight& light : mesh->map->ThingLights)
|
||||||
|
{
|
||||||
|
Vec3 lightOrigin = light.LightOrigin();
|
||||||
|
float lightRadius = light.LightRadius();
|
||||||
|
|
||||||
|
if (probe->Position.DistanceSq(lightOrigin) > (lightRadius * lightRadius))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (mesh->TraceAnyHit(lightOrigin, probe->Position))
|
||||||
|
continue; // this light is occluded by something
|
||||||
|
|
||||||
|
Vec3 dir = (lightOrigin - probe->Position);
|
||||||
|
float dist = dir.Unit();
|
||||||
|
dir.Normalize();
|
||||||
|
|
||||||
|
color += light.rgb * (light.SpotAttenuation(dir) * light.DistAttenuation(dist) * light.intensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
probe->Color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPURaytracer::RaytraceSurfaceSample(Surface* surface, int x, int y)
|
||||||
|
{
|
||||||
|
Vec3 normal = surface->plane.Normal();
|
||||||
|
Vec3 pos = surface->lightmapOrigin + normal + surface->lightmapSteps[0] * (float)x + surface->lightmapSteps[1] * (float)y;
|
||||||
|
|
||||||
|
Vec3 incoming(0.0f, 0.0f, 0.0f);
|
||||||
|
if (LightBounce > 0)
|
||||||
|
{
|
||||||
|
float totalWeight = 0.0f;
|
||||||
|
for (int i = 0; i < SAMPLE_COUNT; i++)
|
||||||
|
{
|
||||||
|
Vec2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||||
|
Vec3 H = ImportanceSampleGGX(Xi, normal, 1.0f);
|
||||||
|
Vec3 L = Vec3::Normalize(H * (2.0f * Vec3::Dot(normal, H)) - normal);
|
||||||
|
float NdotL = std::max(Vec3::Dot(normal, L), 0.0f);
|
||||||
|
if (NdotL > 0.0f)
|
||||||
|
{
|
||||||
|
incoming += TracePath(pos, L, i) * NdotL;
|
||||||
|
totalWeight += NdotL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
incoming = incoming / totalWeight / (float)LightBounce;
|
||||||
|
}
|
||||||
|
|
||||||
|
incoming = incoming + GetSurfaceEmittance(surface, 0.0f) + GetLightEmittance(surface, pos);
|
||||||
|
|
||||||
|
size_t sampleWidth = surface->lightmapDims[0];
|
||||||
|
surface->samples[x + y * sampleWidth] = incoming;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 GPURaytracer::GetLightEmittance(Surface* surface, const Vec3& pos)
|
||||||
|
{
|
||||||
|
Vec3 emittance = Vec3(0.0f);
|
||||||
|
for (ThingLight& light : mesh->map->ThingLights)
|
||||||
|
{
|
||||||
|
Vec3 lightOrigin = light.LightOrigin();
|
||||||
|
float lightRadius = light.LightRadius();
|
||||||
|
|
||||||
|
if (surface->plane.Distance(lightOrigin) - surface->plane.d < 0)
|
||||||
|
continue; // completely behind the plane
|
||||||
|
|
||||||
|
if (pos.DistanceSq(lightOrigin) > (lightRadius * lightRadius))
|
||||||
|
continue; // light too far away
|
||||||
|
|
||||||
|
Vec3 dir = (lightOrigin - pos);
|
||||||
|
float dist = dir.Unit();
|
||||||
|
dir.Normalize();
|
||||||
|
|
||||||
|
float attenuation = light.SpotAttenuation(dir) * light.DistAttenuation(dist) * surface->plane.Normal().Dot(dir);
|
||||||
|
if (attenuation <= 0.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (mesh->TraceAnyHit(lightOrigin, pos))
|
||||||
|
continue; // this light is occluded by something
|
||||||
|
|
||||||
|
emittance += light.rgb * (attenuation * light.intensity);
|
||||||
|
}
|
||||||
|
return emittance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 GPURaytracer::TracePath(const Vec3& pos, const Vec3& dir, int sampleIndex, int depth)
|
||||||
|
{
|
||||||
|
if (depth >= LightBounce)
|
||||||
|
return Vec3(0.0f);
|
||||||
|
|
||||||
|
LevelTraceHit hit = mesh->Trace(pos, pos + dir * 1000.0f);
|
||||||
|
if (hit.fraction == 1.0f)
|
||||||
|
return Vec3(0.0f);
|
||||||
|
|
||||||
|
Vec3 normal = hit.hitSurface->plane.Normal();
|
||||||
|
Vec3 hitpos = hit.start * (1.0f - hit.fraction) + hit.end * hit.fraction + normal * 0.1f;
|
||||||
|
|
||||||
|
Vec3 emittance = GetSurfaceEmittance(hit.hitSurface, pos.Distance(hitpos)) + GetLightEmittance(hit.hitSurface, hitpos) * 0.5f;
|
||||||
|
|
||||||
|
Vec2 Xi = Hammersley(sampleIndex, SAMPLE_COUNT);
|
||||||
|
Vec3 H = ImportanceSampleGGX(Xi, normal, 1.0f);
|
||||||
|
Vec3 L = Vec3::Normalize(H * (2.0f * Vec3::Dot(normal, H)) - normal);
|
||||||
|
|
||||||
|
float NdotL = std::max(Vec3::Dot(normal, L), 0.0f);
|
||||||
|
if (NdotL <= 0.0f)
|
||||||
|
return emittance;
|
||||||
|
|
||||||
|
const float p = 1 / (2 * M_PI);
|
||||||
|
Vec3 incoming = TracePath(hitpos, normal, (sampleIndex + depth + 1) % SAMPLE_COUNT, depth + 1);
|
||||||
|
|
||||||
|
return emittance + incoming * NdotL / p;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GPURaytracer::RadicalInverse_VdC(uint32_t bits)
|
||||||
|
{
|
||||||
|
bits = (bits << 16u) | (bits >> 16u);
|
||||||
|
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||||
|
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||||
|
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||||
|
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||||
|
return float(bits) * 2.3283064365386963e-10f; // / 0x100000000
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 GPURaytracer::Hammersley(uint32_t i, uint32_t N)
|
||||||
|
{
|
||||||
|
return Vec2(float(i) / float(N), RadicalInverse_VdC(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 GPURaytracer::ImportanceSampleGGX(Vec2 Xi, Vec3 N, float roughness)
|
||||||
|
{
|
||||||
|
float a = roughness * roughness;
|
||||||
|
|
||||||
|
float phi = 2.0f * M_PI * Xi.x;
|
||||||
|
float cosTheta = sqrt((1.0f - Xi.y) / (1.0f + (a * a - 1.0f) * Xi.y));
|
||||||
|
float sinTheta = sqrt(1.0f - cosTheta * cosTheta);
|
||||||
|
|
||||||
|
// from spherical coordinates to cartesian coordinates
|
||||||
|
Vec3 H(std::cos(phi) * sinTheta, std::sin(phi) * sinTheta, cosTheta);
|
||||||
|
|
||||||
|
// from tangent-space vector to world-space sample vector
|
||||||
|
Vec3 up = std::abs(N.z) < 0.999f ? Vec3(0.0f, 0.0f, 1.0f) : Vec3(1.0f, 0.0f, 0.0f);
|
||||||
|
Vec3 tangent = Vec3::Normalize(Vec3::Cross(up, N));
|
||||||
|
Vec3 bitangent = Vec3::Cross(N, tangent);
|
||||||
|
|
||||||
|
Vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
|
||||||
|
return Vec3::Normalize(sampleVec);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 GPURaytracer::GetSurfaceEmittance(Surface* surface, float distance)
|
||||||
|
{
|
||||||
|
SurfaceLightDef* def = nullptr;
|
||||||
|
if (surface->type >= ST_MIDDLESIDE && surface->type <= ST_LOWERSIDE)
|
||||||
|
{
|
||||||
|
int lightdefidx = mesh->map->Sides[surface->typeIndex].lightdef;
|
||||||
|
if (lightdefidx != -1)
|
||||||
|
{
|
||||||
|
def = &mesh->map->SurfaceLights[lightdefidx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (surface->type == ST_FLOOR || surface->type == ST_CEILING)
|
||||||
|
{
|
||||||
|
MapSubsectorEx* sub = &mesh->map->GLSubsectors[surface->typeIndex];
|
||||||
|
IntSector* sector = mesh->map->GetSectorFromSubSector(sub);
|
||||||
|
|
||||||
|
if (sector && surface->numVerts > 0)
|
||||||
|
{
|
||||||
|
if (sector->floorlightdef != -1 && surface->type == ST_FLOOR)
|
||||||
|
{
|
||||||
|
def = &mesh->map->SurfaceLights[sector->floorlightdef];
|
||||||
|
}
|
||||||
|
else if (sector->ceilinglightdef != -1 && surface->type == ST_CEILING)
|
||||||
|
{
|
||||||
|
def = &mesh->map->SurfaceLights[sector->ceilinglightdef];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def)
|
||||||
|
{
|
||||||
|
float attenuation = std::max(1.0f - (distance / def->distance), 0.0f);
|
||||||
|
return def->rgb * (attenuation * def->intensity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Vec3(0.0f);
|
||||||
|
}
|
||||||
|
}
|
33
src/lightmap/gpuraytracer.h
Normal file
33
src/lightmap/gpuraytracer.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "vulkandevice.h"
|
||||||
|
|
||||||
|
class LevelMesh;
|
||||||
|
|
||||||
|
class GPURaytracer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GPURaytracer();
|
||||||
|
~GPURaytracer();
|
||||||
|
|
||||||
|
void Raytrace(LevelMesh* level);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void RaytraceProbeSample(LightProbeSample* probe);
|
||||||
|
void RaytraceSurfaceSample(Surface* surface, int x, int y);
|
||||||
|
Vec3 TracePath(const Vec3& pos, const Vec3& dir, int sampleIndex, int depth = 0);
|
||||||
|
|
||||||
|
Vec3 GetLightEmittance(Surface* surface, const Vec3& pos);
|
||||||
|
Vec3 GetSurfaceEmittance(Surface* surface, float distance);
|
||||||
|
|
||||||
|
static float RadicalInverse_VdC(uint32_t bits);
|
||||||
|
static Vec2 Hammersley(uint32_t i, uint32_t N);
|
||||||
|
static Vec3 ImportanceSampleGGX(Vec2 Xi, Vec3 N, float roughness);
|
||||||
|
|
||||||
|
int SAMPLE_COUNT = 1024;// 128;// 1024;
|
||||||
|
|
||||||
|
LevelMesh* mesh = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<VulkanDevice> device;
|
||||||
|
};
|
192
src/lightmap/vulkanbuilders.cpp
Normal file
192
src/lightmap/vulkanbuilders.cpp
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
|
||||||
|
#include "vulkanbuilders.h"
|
||||||
|
|
||||||
|
static const TBuiltInResource DefaultTBuiltInResource = {
|
||||||
|
/* .MaxLights = */ 32,
|
||||||
|
/* .MaxClipPlanes = */ 6,
|
||||||
|
/* .MaxTextureUnits = */ 32,
|
||||||
|
/* .MaxTextureCoords = */ 32,
|
||||||
|
/* .MaxVertexAttribs = */ 64,
|
||||||
|
/* .MaxVertexUniformComponents = */ 4096,
|
||||||
|
/* .MaxVaryingFloats = */ 64,
|
||||||
|
/* .MaxVertexTextureImageUnits = */ 32,
|
||||||
|
/* .MaxCombinedTextureImageUnits = */ 80,
|
||||||
|
/* .MaxTextureImageUnits = */ 32,
|
||||||
|
/* .MaxFragmentUniformComponents = */ 4096,
|
||||||
|
/* .MaxDrawBuffers = */ 32,
|
||||||
|
/* .MaxVertexUniformVectors = */ 128,
|
||||||
|
/* .MaxVaryingVectors = */ 8,
|
||||||
|
/* .MaxFragmentUniformVectors = */ 16,
|
||||||
|
/* .MaxVertexOutputVectors = */ 16,
|
||||||
|
/* .MaxFragmentInputVectors = */ 15,
|
||||||
|
/* .MinProgramTexelOffset = */ -8,
|
||||||
|
/* .MaxProgramTexelOffset = */ 7,
|
||||||
|
/* .MaxClipDistances = */ 8,
|
||||||
|
/* .MaxComputeWorkGroupCountX = */ 65535,
|
||||||
|
/* .MaxComputeWorkGroupCountY = */ 65535,
|
||||||
|
/* .MaxComputeWorkGroupCountZ = */ 65535,
|
||||||
|
/* .MaxComputeWorkGroupSizeX = */ 1024,
|
||||||
|
/* .MaxComputeWorkGroupSizeY = */ 1024,
|
||||||
|
/* .MaxComputeWorkGroupSizeZ = */ 64,
|
||||||
|
/* .MaxComputeUniformComponents = */ 1024,
|
||||||
|
/* .MaxComputeTextureImageUnits = */ 16,
|
||||||
|
/* .MaxComputeImageUniforms = */ 8,
|
||||||
|
/* .MaxComputeAtomicCounters = */ 8,
|
||||||
|
/* .MaxComputeAtomicCounterBuffers = */ 1,
|
||||||
|
/* .MaxVaryingComponents = */ 60,
|
||||||
|
/* .MaxVertexOutputComponents = */ 64,
|
||||||
|
/* .MaxGeometryInputComponents = */ 64,
|
||||||
|
/* .MaxGeometryOutputComponents = */ 128,
|
||||||
|
/* .MaxFragmentInputComponents = */ 128,
|
||||||
|
/* .MaxImageUnits = */ 8,
|
||||||
|
/* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8,
|
||||||
|
/* .MaxCombinedShaderOutputResources = */ 8,
|
||||||
|
/* .MaxImageSamples = */ 0,
|
||||||
|
/* .MaxVertexImageUniforms = */ 0,
|
||||||
|
/* .MaxTessControlImageUniforms = */ 0,
|
||||||
|
/* .MaxTessEvaluationImageUniforms = */ 0,
|
||||||
|
/* .MaxGeometryImageUniforms = */ 0,
|
||||||
|
/* .MaxFragmentImageUniforms = */ 8,
|
||||||
|
/* .MaxCombinedImageUniforms = */ 8,
|
||||||
|
/* .MaxGeometryTextureImageUnits = */ 16,
|
||||||
|
/* .MaxGeometryOutputVertices = */ 256,
|
||||||
|
/* .MaxGeometryTotalOutputComponents = */ 1024,
|
||||||
|
/* .MaxGeometryUniformComponents = */ 1024,
|
||||||
|
/* .MaxGeometryVaryingComponents = */ 64,
|
||||||
|
/* .MaxTessControlInputComponents = */ 128,
|
||||||
|
/* .MaxTessControlOutputComponents = */ 128,
|
||||||
|
/* .MaxTessControlTextureImageUnits = */ 16,
|
||||||
|
/* .MaxTessControlUniformComponents = */ 1024,
|
||||||
|
/* .MaxTessControlTotalOutputComponents = */ 4096,
|
||||||
|
/* .MaxTessEvaluationInputComponents = */ 128,
|
||||||
|
/* .MaxTessEvaluationOutputComponents = */ 128,
|
||||||
|
/* .MaxTessEvaluationTextureImageUnits = */ 16,
|
||||||
|
/* .MaxTessEvaluationUniformComponents = */ 1024,
|
||||||
|
/* .MaxTessPatchComponents = */ 120,
|
||||||
|
/* .MaxPatchVertices = */ 32,
|
||||||
|
/* .MaxTessGenLevel = */ 64,
|
||||||
|
/* .MaxViewports = */ 16,
|
||||||
|
/* .MaxVertexAtomicCounters = */ 0,
|
||||||
|
/* .MaxTessControlAtomicCounters = */ 0,
|
||||||
|
/* .MaxTessEvaluationAtomicCounters = */ 0,
|
||||||
|
/* .MaxGeometryAtomicCounters = */ 0,
|
||||||
|
/* .MaxFragmentAtomicCounters = */ 8,
|
||||||
|
/* .MaxCombinedAtomicCounters = */ 8,
|
||||||
|
/* .MaxAtomicCounterBindings = */ 1,
|
||||||
|
/* .MaxVertexAtomicCounterBuffers = */ 0,
|
||||||
|
/* .MaxTessControlAtomicCounterBuffers = */ 0,
|
||||||
|
/* .MaxTessEvaluationAtomicCounterBuffers = */ 0,
|
||||||
|
/* .MaxGeometryAtomicCounterBuffers = */ 0,
|
||||||
|
/* .MaxFragmentAtomicCounterBuffers = */ 1,
|
||||||
|
/* .MaxCombinedAtomicCounterBuffers = */ 1,
|
||||||
|
/* .MaxAtomicCounterBufferSize = */ 16384,
|
||||||
|
/* .MaxTransformFeedbackBuffers = */ 4,
|
||||||
|
/* .MaxTransformFeedbackInterleavedComponents = */ 64,
|
||||||
|
/* .MaxCullDistances = */ 8,
|
||||||
|
/* .MaxCombinedClipAndCullDistances = */ 8,
|
||||||
|
/* .MaxSamples = */ 4,
|
||||||
|
/* .maxMeshOutputVerticesNV = */ 256,
|
||||||
|
/* .maxMeshOutputPrimitivesNV = */ 512,
|
||||||
|
/* .maxMeshWorkGroupSizeX_NV = */ 32,
|
||||||
|
/* .maxMeshWorkGroupSizeY_NV = */ 1,
|
||||||
|
/* .maxMeshWorkGroupSizeZ_NV = */ 1,
|
||||||
|
/* .maxTaskWorkGroupSizeX_NV = */ 32,
|
||||||
|
/* .maxTaskWorkGroupSizeY_NV = */ 1,
|
||||||
|
/* .maxTaskWorkGroupSizeZ_NV = */ 1,
|
||||||
|
/* .maxMeshViewCountNV = */ 4,
|
||||||
|
|
||||||
|
/* .limits = */ {
|
||||||
|
/* .nonInductiveForLoops = */ 1,
|
||||||
|
/* .whileLoops = */ 1,
|
||||||
|
/* .doWhileLoops = */ 1,
|
||||||
|
/* .generalUniformIndexing = */ 1,
|
||||||
|
/* .generalAttributeMatrixVectorIndexing = */ 1,
|
||||||
|
/* .generalVaryingIndexing = */ 1,
|
||||||
|
/* .generalSamplerIndexing = */ 1,
|
||||||
|
/* .generalVariableIndexing = */ 1,
|
||||||
|
/* .generalConstantMatrixVectorIndexing = */ 1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void ShaderBuilder::init()
|
||||||
|
{
|
||||||
|
ShInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderBuilder::deinit()
|
||||||
|
{
|
||||||
|
ShFinalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderBuilder::ShaderBuilder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderBuilder::setVertexShader(const std::string &c) { code = c; stage = EShLanguage::EShLangVertex; }
|
||||||
|
void ShaderBuilder::setTessControlShader(const std::string &c) { code = c; stage = EShLanguage::EShLangTessControl; }
|
||||||
|
void ShaderBuilder::setTessEvaluationShader(const std::string &c) { code = c; stage = EShLanguage::EShLangTessEvaluation; }
|
||||||
|
void ShaderBuilder::setGeometryShader(const std::string &c) { code = c; stage = EShLanguage::EShLangGeometry; }
|
||||||
|
void ShaderBuilder::setFragmentShader(const std::string &c) { code = c; stage = EShLanguage::EShLangFragment; }
|
||||||
|
void ShaderBuilder::setComputeShader(const std::string &c) { code = c; stage = EShLanguage::EShLangCompute; }
|
||||||
|
void ShaderBuilder::setRayGenShader(const std::string &c) { code = c; stage = EShLanguage::EShLangRayGenNV; }
|
||||||
|
void ShaderBuilder::setIntersectShader(const std::string &c) { code = c; stage = EShLanguage::EShLangIntersectNV; }
|
||||||
|
void ShaderBuilder::setAnyHitShader(const std::string &c) { code = c; stage = EShLanguage::EShLangAnyHitNV; }
|
||||||
|
void ShaderBuilder::setClosestHitShader(const std::string &c) { code = c; stage = EShLanguage::EShLangClosestHitNV; }
|
||||||
|
void ShaderBuilder::setMissShader(const std::string &c) { code = c; stage = EShLanguage::EShLangMissNV; }
|
||||||
|
void ShaderBuilder::setCallableShader(const std::string &c) { code = c; stage = EShLanguage::EShLangCallableNV; }
|
||||||
|
void ShaderBuilder::setTaskShader(const std::string &c) { code = c; stage = EShLanguage::EShLangTaskNV; }
|
||||||
|
void ShaderBuilder::setMeshShader(const std::string &c) { code = c; stage = EShLanguage::EShLangMeshNV; }
|
||||||
|
|
||||||
|
std::unique_ptr<VulkanShader> ShaderBuilder::create(VulkanDevice *device)
|
||||||
|
{
|
||||||
|
EShLanguage stage = (EShLanguage)this->stage;
|
||||||
|
const char *sources[] = { code.c_str() };
|
||||||
|
|
||||||
|
TBuiltInResource resources = DefaultTBuiltInResource;
|
||||||
|
|
||||||
|
glslang::TShader shader(stage);
|
||||||
|
shader.setStrings(sources, 1);
|
||||||
|
shader.setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, 100);
|
||||||
|
shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0);
|
||||||
|
shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0);
|
||||||
|
bool compileSuccess = shader.parse(&resources, 110, false, EShMsgVulkanRules);
|
||||||
|
if (!compileSuccess)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string("Shader compile failed: ") + shader.getInfoLog());
|
||||||
|
}
|
||||||
|
|
||||||
|
glslang::TProgram program;
|
||||||
|
program.addShader(&shader);
|
||||||
|
bool linkSuccess = program.link(EShMsgDefault);
|
||||||
|
if (!linkSuccess)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string("Shader link failed: ") + program.getInfoLog());
|
||||||
|
}
|
||||||
|
|
||||||
|
glslang::TIntermediate *intermediate = program.getIntermediate(stage);
|
||||||
|
if (!intermediate)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Internal shader compiler error");
|
||||||
|
}
|
||||||
|
|
||||||
|
glslang::SpvOptions spvOptions;
|
||||||
|
spvOptions.generateDebugInfo = false;
|
||||||
|
spvOptions.disableOptimizer = false;
|
||||||
|
spvOptions.optimizeSize = true;
|
||||||
|
|
||||||
|
std::vector<unsigned int> spirv;
|
||||||
|
spv::SpvBuildLogger logger;
|
||||||
|
glslang::GlslangToSpv(*intermediate, spirv, &logger, &spvOptions);
|
||||||
|
|
||||||
|
VkShaderModuleCreateInfo createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
createInfo.codeSize = spirv.size() * sizeof(unsigned int);
|
||||||
|
createInfo.pCode = spirv.data();
|
||||||
|
|
||||||
|
VkShaderModule shaderModule;
|
||||||
|
VkResult result = vkCreateShaderModule(device->device, &createInfo, nullptr, &shaderModule);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("Could not create vulkan shader module");
|
||||||
|
|
||||||
|
return std::make_unique<VulkanShader>(device, shaderModule);
|
||||||
|
}
|
1747
src/lightmap/vulkanbuilders.h
Normal file
1747
src/lightmap/vulkanbuilders.h
Normal file
File diff suppressed because it is too large
Load diff
515
src/lightmap/vulkandevice.cpp
Normal file
515
src/lightmap/vulkandevice.cpp
Normal file
|
@ -0,0 +1,515 @@
|
||||||
|
|
||||||
|
#include "vulkandevice.h"
|
||||||
|
#include "vulkanobjects.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
VulkanDevice::VulkanDevice(int vk_device, bool vk_debug, std::function<void(const char* typestr, const std::string& msg)> printLogCallback) : vk_device(vk_device), vk_debug(vk_debug), printLogCallback(printLogCallback)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
initVolk();
|
||||||
|
createInstance();
|
||||||
|
selectPhysicalDevice();
|
||||||
|
selectFeatures();
|
||||||
|
createDevice();
|
||||||
|
createAllocator();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
releaseResources();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanDevice::~VulkanDevice()
|
||||||
|
{
|
||||||
|
releaseResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDevice::selectFeatures()
|
||||||
|
{
|
||||||
|
enabledDeviceFeatures.samplerAnisotropy = physicalDevice.features.samplerAnisotropy;
|
||||||
|
enabledDeviceFeatures.fragmentStoresAndAtomics = physicalDevice.features.fragmentStoresAndAtomics;
|
||||||
|
enabledDeviceFeatures.depthClamp = physicalDevice.features.depthClamp;
|
||||||
|
enabledDeviceFeatures.shaderClipDistance = physicalDevice.features.shaderClipDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanDevice::checkRequiredFeatures(const VkPhysicalDeviceFeatures &f)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
f.samplerAnisotropy == VK_TRUE &&
|
||||||
|
f.fragmentStoresAndAtomics == VK_TRUE &&
|
||||||
|
f.depthClamp == VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDevice::selectPhysicalDevice()
|
||||||
|
{
|
||||||
|
availableDevices = getPhysicalDevices(instance);
|
||||||
|
if (availableDevices.empty())
|
||||||
|
throw std::runtime_error("No Vulkan devices found. Either the graphics card has no vulkan support or the driver is too old.");
|
||||||
|
|
||||||
|
// createSurface();
|
||||||
|
|
||||||
|
supportedDevices.clear();
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < availableDevices.size(); idx++)
|
||||||
|
{
|
||||||
|
const auto &info = availableDevices[idx];
|
||||||
|
|
||||||
|
if (!checkRequiredFeatures(info.features))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::set<std::string> requiredExtensionSearch(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end());
|
||||||
|
for (const auto &ext : info.extensions)
|
||||||
|
requiredExtensionSearch.erase(ext.extensionName);
|
||||||
|
if (!requiredExtensionSearch.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
VulkanCompatibleDevice dev;
|
||||||
|
dev.device = &availableDevices[idx];
|
||||||
|
|
||||||
|
bool window = false; // static_cast<bool>(createSurfaceWindow);
|
||||||
|
|
||||||
|
// Figure out what can present
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)info.queueFamilies.size(); i++)
|
||||||
|
{
|
||||||
|
VkBool32 presentSupport = false;
|
||||||
|
VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(info.device, i, surface, &presentSupport);
|
||||||
|
if (result == VK_SUCCESS && info.queueFamilies[i].queueCount > 0 && presentSupport)
|
||||||
|
{
|
||||||
|
dev.presentFamily = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The vulkan spec states that graphics and compute queues can always do transfer.
|
||||||
|
// Furthermore the spec states that graphics queues always can do compute.
|
||||||
|
// Last, the spec makes it OPTIONAL whether the VK_QUEUE_TRANSFER_BIT is set for such queues, but they MUST support transfer.
|
||||||
|
//
|
||||||
|
// In short: pick the first graphics queue family for everything.
|
||||||
|
for (int i = 0; i < (int)info.queueFamilies.size(); i++)
|
||||||
|
{
|
||||||
|
const auto &queueFamily = info.queueFamilies[i];
|
||||||
|
if (queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT))
|
||||||
|
{
|
||||||
|
dev.graphicsFamily = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev.graphicsFamily != -1 && (!window || dev.presentFamily != -1))
|
||||||
|
{
|
||||||
|
supportedDevices.push_back(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supportedDevices.empty())
|
||||||
|
throw std::runtime_error("No Vulkan device supports the minimum requirements of this application");
|
||||||
|
|
||||||
|
// The device order returned by Vulkan can be anything. Prefer discrete > integrated > virtual gpu > cpu > other
|
||||||
|
std::stable_sort(supportedDevices.begin(), supportedDevices.end(), [&](const auto &a, const auto b) {
|
||||||
|
|
||||||
|
// Sort by GPU type first. This will ensure the "best" device is most likely to map to vk_device 0
|
||||||
|
static const int typeSort[] = { 4, 1, 0, 2, 3 };
|
||||||
|
int sortA = a.device->properties.deviceType < 5 ? typeSort[a.device->properties.deviceType] : (int)a.device->properties.deviceType;
|
||||||
|
int sortB = b.device->properties.deviceType < 5 ? typeSort[b.device->properties.deviceType] : (int)b.device->properties.deviceType;
|
||||||
|
if (sortA != sortB)
|
||||||
|
return sortA < sortB;
|
||||||
|
|
||||||
|
// Then sort by the device's unique ID so that vk_device uses a consistent order
|
||||||
|
int sortUUID = memcmp(a.device->properties.pipelineCacheUUID, b.device->properties.pipelineCacheUUID, VK_UUID_SIZE);
|
||||||
|
return sortUUID < 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
size_t selected = vk_device;
|
||||||
|
if (selected >= supportedDevices.size())
|
||||||
|
selected = 0;
|
||||||
|
|
||||||
|
// Enable optional extensions we are interested in, if they are available on this device
|
||||||
|
for (const auto &ext : supportedDevices[selected].device->extensions)
|
||||||
|
{
|
||||||
|
for (const auto &opt : optionalDeviceExtensions)
|
||||||
|
{
|
||||||
|
if (strcmp(ext.extensionName, opt) == 0)
|
||||||
|
{
|
||||||
|
enabledDeviceExtensions.push_back(opt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
physicalDevice = *supportedDevices[selected].device;
|
||||||
|
graphicsFamily = supportedDevices[selected].graphicsFamily;
|
||||||
|
presentFamily = supportedDevices[selected].presentFamily;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VulkanDevice::supportsDeviceExtension(const char *ext) const
|
||||||
|
{
|
||||||
|
return std::find(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end(), ext) != enabledDeviceExtensions.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDevice::createAllocator()
|
||||||
|
{
|
||||||
|
VmaAllocatorCreateInfo allocinfo = {};
|
||||||
|
if (supportsDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) && supportsDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME))
|
||||||
|
allocinfo.flags = VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
|
||||||
|
allocinfo.physicalDevice = physicalDevice.device;
|
||||||
|
allocinfo.device = device;
|
||||||
|
allocinfo.preferredLargeHeapBlockSize = 64 * 1024 * 1024;
|
||||||
|
if (vmaCreateAllocator(&allocinfo, &allocator) != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("Unable to create allocator");
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDevice::createDevice()
|
||||||
|
{
|
||||||
|
float queuePriority = 1.0f;
|
||||||
|
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||||
|
|
||||||
|
std::set<int> neededFamilies;
|
||||||
|
neededFamilies.insert(graphicsFamily);
|
||||||
|
if (presentFamily != -1)
|
||||||
|
neededFamilies.insert(presentFamily);
|
||||||
|
|
||||||
|
for (int index : neededFamilies)
|
||||||
|
{
|
||||||
|
VkDeviceQueueCreateInfo queueCreateInfo = {};
|
||||||
|
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
|
queueCreateInfo.queueFamilyIndex = index;
|
||||||
|
queueCreateInfo.queueCount = 1;
|
||||||
|
queueCreateInfo.pQueuePriorities = &queuePriority;
|
||||||
|
queueCreateInfos.push_back(queueCreateInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceCreateInfo deviceCreateInfo = {};
|
||||||
|
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
|
deviceCreateInfo.queueCreateInfoCount = (uint32_t)queueCreateInfos.size();
|
||||||
|
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||||
|
deviceCreateInfo.pEnabledFeatures = &enabledDeviceFeatures;
|
||||||
|
deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
|
||||||
|
deviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.data();
|
||||||
|
deviceCreateInfo.enabledLayerCount = 0;
|
||||||
|
|
||||||
|
VkResult result = vkCreateDevice(physicalDevice.device, &deviceCreateInfo, nullptr, &device);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("Could not create vulkan device");
|
||||||
|
|
||||||
|
volkLoadDevice(device);
|
||||||
|
|
||||||
|
vkGetDeviceQueue(device, graphicsFamily, 0, &graphicsQueue);
|
||||||
|
if (presentFamily != -1)
|
||||||
|
vkGetDeviceQueue(device, presentFamily, 0, &presentQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifdef WIN32
|
||||||
|
void VulkanDevice::createSurface()
|
||||||
|
{
|
||||||
|
VkWin32SurfaceCreateInfoKHR windowCreateInfo = {};
|
||||||
|
windowCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||||
|
windowCreateInfo.hwnd = window;
|
||||||
|
windowCreateInfo.hinstance = GetModuleHandle(nullptr);
|
||||||
|
|
||||||
|
VkResult result = vkCreateWin32SurfaceKHR(instance, &windowCreateInfo, nullptr, &surface);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("Could not create vulkan surface");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void VulkanDevice::createSurface()
|
||||||
|
{
|
||||||
|
for (const auto &info : availableDevices)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < (uint32_t)info.queueFamilies.size(); i++)
|
||||||
|
{
|
||||||
|
const auto &queueFamily = info.queueFamilies[i];
|
||||||
|
if (queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT))
|
||||||
|
{
|
||||||
|
uint32_t graphicsFamily = i;
|
||||||
|
auto handles = createSurfaceWindow(info.device, graphicsFamily);
|
||||||
|
|
||||||
|
VkXlibSurfaceCreateInfoKHR windowCreateInfo = {};
|
||||||
|
windowCreateInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
|
||||||
|
windowCreateInfo.dpy = handles.first;
|
||||||
|
windowCreateInfo.window = handles.second;
|
||||||
|
|
||||||
|
VkResult result = vkCreateXlibSurfaceKHR(instance, &windowCreateInfo, nullptr, &surface);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("Could not create vulkan surface");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("No vulkan device supports graphics!");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
void VulkanDevice::createInstance()
|
||||||
|
{
|
||||||
|
availableLayers = getAvailableLayers();
|
||||||
|
extensions = getExtensions();
|
||||||
|
enabledExtensions = getPlatformExtensions();
|
||||||
|
|
||||||
|
std::string debugLayer = "VK_LAYER_LUNARG_standard_validation";
|
||||||
|
bool wantDebugLayer = vk_debug;
|
||||||
|
bool debugLayerFound = false;
|
||||||
|
for (const VkLayerProperties &layer : availableLayers)
|
||||||
|
{
|
||||||
|
if (layer.layerName == debugLayer && wantDebugLayer)
|
||||||
|
{
|
||||||
|
enabledValidationLayers.push_back(debugLayer.c_str());
|
||||||
|
enabledExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
|
debugLayerFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable optional instance extensions we are interested in
|
||||||
|
for (const auto &ext : extensions)
|
||||||
|
{
|
||||||
|
for (const auto &opt : optionalExtensions)
|
||||||
|
{
|
||||||
|
if (strcmp(ext.extensionName, opt) == 0)
|
||||||
|
{
|
||||||
|
enabledExtensions.push_back(opt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkApplicationInfo appInfo = {};
|
||||||
|
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
|
appInfo.pApplicationName = "UT99";
|
||||||
|
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||||
|
appInfo.pEngineName = "UT99";
|
||||||
|
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||||
|
appInfo.apiVersion = VK_API_VERSION_1_1;
|
||||||
|
|
||||||
|
VkInstanceCreateInfo createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
|
createInfo.pApplicationInfo = &appInfo;
|
||||||
|
createInfo.enabledExtensionCount = (uint32_t)enabledExtensions.size();
|
||||||
|
createInfo.enabledLayerCount = (uint32_t)enabledValidationLayers.size();
|
||||||
|
createInfo.ppEnabledLayerNames = enabledValidationLayers.data();
|
||||||
|
createInfo.ppEnabledExtensionNames = enabledExtensions.data();
|
||||||
|
|
||||||
|
VkResult result = vkCreateInstance(&createInfo, nullptr, &instance);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("Could not create vulkan instance");
|
||||||
|
|
||||||
|
volkLoadInstance(instance);
|
||||||
|
|
||||||
|
if (debugLayerFound)
|
||||||
|
{
|
||||||
|
VkDebugUtilsMessengerCreateInfoEXT createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||||
|
createInfo.messageSeverity =
|
||||||
|
//VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
|
||||||
|
//VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||||
|
createInfo.messageType =
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||||
|
createInfo.pfnUserCallback = debugCallback;
|
||||||
|
createInfo.pUserData = this;
|
||||||
|
result = vkCreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger);
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkCreateDebugUtilsMessengerEXT failed");
|
||||||
|
|
||||||
|
debugLayerActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBool32 VulkanDevice::debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData)
|
||||||
|
{
|
||||||
|
VulkanDevice *device = (VulkanDevice*)userData;
|
||||||
|
|
||||||
|
static std::mutex mtx;
|
||||||
|
static std::set<std::string> seenMessages;
|
||||||
|
static int totalMessages;
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(mtx);
|
||||||
|
|
||||||
|
std::string msg = callbackData->pMessage;
|
||||||
|
|
||||||
|
bool found = seenMessages.find(msg) != seenMessages.end();
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
if (totalMessages < 20)
|
||||||
|
{
|
||||||
|
totalMessages++;
|
||||||
|
seenMessages.insert(msg);
|
||||||
|
|
||||||
|
const char *typestr;
|
||||||
|
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
|
||||||
|
{
|
||||||
|
typestr = "vulkan error";
|
||||||
|
}
|
||||||
|
else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
|
||||||
|
{
|
||||||
|
typestr = "vulkan warning";
|
||||||
|
}
|
||||||
|
else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT)
|
||||||
|
{
|
||||||
|
typestr = "vulkan info";
|
||||||
|
}
|
||||||
|
else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT)
|
||||||
|
{
|
||||||
|
typestr = "vulkan verbose";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
typestr = "vulkan";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device->printLogCallback)
|
||||||
|
device->printLogCallback(typestr, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<VkLayerProperties> VulkanDevice::getAvailableLayers()
|
||||||
|
{
|
||||||
|
uint32_t layerCount;
|
||||||
|
VkResult result = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
||||||
|
|
||||||
|
std::vector<VkLayerProperties> availableLayers(layerCount);
|
||||||
|
result = vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
||||||
|
return availableLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<VkExtensionProperties> VulkanDevice::getExtensions()
|
||||||
|
{
|
||||||
|
uint32_t extensionCount = 0;
|
||||||
|
VkResult result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
|
||||||
|
|
||||||
|
std::vector<VkExtensionProperties> extensions(extensionCount);
|
||||||
|
result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<VulkanPhysicalDevice> VulkanDevice::getPhysicalDevices(VkInstance instance)
|
||||||
|
{
|
||||||
|
uint32_t deviceCount = 0;
|
||||||
|
VkResult result = vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
|
||||||
|
if (result == VK_ERROR_INITIALIZATION_FAILED) // Some drivers return this when a card does not support vulkan
|
||||||
|
return {};
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkEnumeratePhysicalDevices failed");
|
||||||
|
if (deviceCount == 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
std::vector<VkPhysicalDevice> devices(deviceCount);
|
||||||
|
result = vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
throw std::runtime_error("vkEnumeratePhysicalDevices failed (2)");
|
||||||
|
|
||||||
|
std::vector<VulkanPhysicalDevice> devinfo(deviceCount);
|
||||||
|
for (size_t i = 0; i < devices.size(); i++)
|
||||||
|
{
|
||||||
|
auto &dev = devinfo[i];
|
||||||
|
dev.device = devices[i];
|
||||||
|
|
||||||
|
VkPhysicalDeviceProperties2 props = {};
|
||||||
|
VkPhysicalDeviceRayTracingPropertiesNV rayprops = {};
|
||||||
|
props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||||
|
props.pNext = &rayprops;
|
||||||
|
rayprops.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV;
|
||||||
|
vkGetPhysicalDeviceProperties2(dev.device, &props);
|
||||||
|
dev.properties = props.properties;
|
||||||
|
dev.rayTracingProperties = rayprops;
|
||||||
|
dev.rayTracingProperties.pNext = nullptr;
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(dev.device, &dev.memoryProperties);
|
||||||
|
vkGetPhysicalDeviceFeatures(dev.device, &dev.features);
|
||||||
|
|
||||||
|
uint32_t queueFamilyCount = 0;
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(dev.device, &queueFamilyCount, nullptr);
|
||||||
|
dev.queueFamilies.resize(queueFamilyCount);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(dev.device, &queueFamilyCount, dev.queueFamilies.data());
|
||||||
|
|
||||||
|
uint32_t deviceExtensionCount = 0;
|
||||||
|
vkEnumerateDeviceExtensionProperties(dev.device, nullptr, &deviceExtensionCount, nullptr);
|
||||||
|
dev.extensions.resize(deviceExtensionCount);
|
||||||
|
vkEnumerateDeviceExtensionProperties(dev.device, nullptr, &deviceExtensionCount, dev.extensions.data());
|
||||||
|
}
|
||||||
|
return devinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
std::vector<const char *> VulkanDevice::getPlatformExtensions()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
{
|
||||||
|
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||||
|
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
std::vector<const char *> VulkanDevice::getPlatformExtensions()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
{
|
||||||
|
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||||
|
VK_KHR_XLIB_SURFACE_EXTENSION_NAME
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void VulkanDevice::initVolk()
|
||||||
|
{
|
||||||
|
static bool volkInited = false;
|
||||||
|
if (!volkInited && volkInitialize() != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unable to find Vulkan");
|
||||||
|
}
|
||||||
|
volkInited = true;
|
||||||
|
auto iver = volkGetInstanceVersion();
|
||||||
|
if (iver == 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Vulkan not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanDevice::releaseResources()
|
||||||
|
{
|
||||||
|
if (device)
|
||||||
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
|
if (allocator)
|
||||||
|
vmaDestroyAllocator(allocator);
|
||||||
|
allocator = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
if (device)
|
||||||
|
vkDestroyDevice(device, nullptr);
|
||||||
|
device = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
if (surface)
|
||||||
|
vkDestroySurfaceKHR(instance, surface, nullptr);
|
||||||
|
surface = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
if (debugMessenger)
|
||||||
|
vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
|
||||||
|
|
||||||
|
if (instance)
|
||||||
|
vkDestroyInstance(instance, nullptr);
|
||||||
|
instance = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t VulkanDevice::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < physicalDevice.memoryProperties.memoryTypeCount; i++)
|
||||||
|
{
|
||||||
|
if ((typeFilter & (1 << i)) && (physicalDevice.memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("failed to find suitable memory type!");
|
||||||
|
}
|
126
src/lightmap/vulkandevice.h
Normal file
126
src/lightmap/vulkandevice.h
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "volk/volk.h"
|
||||||
|
#include "vk_mem_alloc/vk_mem_alloc.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ShaderCompiler/glslang/Public/ShaderLang.h"
|
||||||
|
#include "ShaderCompiler/spirv/GlslangToSpv.h"
|
||||||
|
|
||||||
|
class VulkanSwapChain;
|
||||||
|
class VulkanSemaphore;
|
||||||
|
class VulkanFence;
|
||||||
|
|
||||||
|
class VulkanPhysicalDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VkPhysicalDevice device = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
std::vector<VkExtensionProperties> extensions;
|
||||||
|
std::vector<VkQueueFamilyProperties> queueFamilies;
|
||||||
|
VkPhysicalDeviceProperties properties = {};
|
||||||
|
VkPhysicalDeviceRayTracingPropertiesNV rayTracingProperties = {};
|
||||||
|
VkPhysicalDeviceFeatures features = {};
|
||||||
|
VkPhysicalDeviceMemoryProperties memoryProperties = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class VulkanCompatibleDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VulkanPhysicalDevice *device = nullptr;
|
||||||
|
int graphicsFamily = -1;
|
||||||
|
int presentFamily = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VulkanDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VulkanDevice(int vk_device = 0, bool vk_debug = false, std::function<void(const char* typestr, const std::string& msg)> printLogCallback = {});
|
||||||
|
~VulkanDevice();
|
||||||
|
|
||||||
|
void setDebugObjectName(const char *name, uint64_t handle, VkObjectType type)
|
||||||
|
{
|
||||||
|
if (!debugLayerActive) return;
|
||||||
|
|
||||||
|
VkDebugUtilsObjectNameInfoEXT info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||||
|
info.objectHandle = handle;
|
||||||
|
info.objectType = type;
|
||||||
|
info.pObjectName = name;
|
||||||
|
vkSetDebugUtilsObjectNameEXT(device, &info);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
||||||
|
|
||||||
|
// Instance setup
|
||||||
|
std::vector<VkLayerProperties> availableLayers;
|
||||||
|
std::vector<VkExtensionProperties> extensions;
|
||||||
|
std::vector<const char *> enabledExtensions;
|
||||||
|
std::vector<const char *> optionalExtensions = { VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME };
|
||||||
|
std::vector<const char*> enabledValidationLayers;
|
||||||
|
|
||||||
|
// Device setup
|
||||||
|
VkPhysicalDeviceFeatures enabledDeviceFeatures = {};
|
||||||
|
std::vector<const char *> enabledDeviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
|
||||||
|
std::vector<const char *> optionalDeviceExtensions = {
|
||||||
|
VK_EXT_HDR_METADATA_EXTENSION_NAME,
|
||||||
|
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
|
||||||
|
VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
|
||||||
|
VK_NV_RAY_TRACING_EXTENSION_NAME
|
||||||
|
};
|
||||||
|
VulkanPhysicalDevice physicalDevice;
|
||||||
|
bool debugLayerActive = false;
|
||||||
|
|
||||||
|
VkInstance instance = VK_NULL_HANDLE;
|
||||||
|
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||||
|
VkDevice device = VK_NULL_HANDLE;
|
||||||
|
VmaAllocator allocator = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
VkQueue graphicsQueue = VK_NULL_HANDLE;
|
||||||
|
VkQueue presentQueue = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
int graphicsFamily = -1;
|
||||||
|
int presentFamily = -1;
|
||||||
|
|
||||||
|
// Physical device info
|
||||||
|
std::vector<VulkanPhysicalDevice> availableDevices;
|
||||||
|
std::vector<VulkanCompatibleDevice> supportedDevices;
|
||||||
|
|
||||||
|
static void initVolk();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int vk_device;
|
||||||
|
bool vk_debug;
|
||||||
|
std::function<void(const char* typestr, const std::string& msg)> printLogCallback;
|
||||||
|
|
||||||
|
void createInstance();
|
||||||
|
//void createSurface();
|
||||||
|
void selectPhysicalDevice();
|
||||||
|
void selectFeatures();
|
||||||
|
void createDevice();
|
||||||
|
void createAllocator();
|
||||||
|
void releaseResources();
|
||||||
|
|
||||||
|
bool supportsDeviceExtension(const char *ext) const;
|
||||||
|
|
||||||
|
static bool checkRequiredFeatures(const VkPhysicalDeviceFeatures &f);
|
||||||
|
|
||||||
|
VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData);
|
||||||
|
|
||||||
|
static std::vector<VkLayerProperties> getAvailableLayers();
|
||||||
|
static std::vector<VkExtensionProperties> getExtensions();
|
||||||
|
static std::vector<const char *> getPlatformExtensions();
|
||||||
|
static std::vector<VulkanPhysicalDevice> getPhysicalDevices(VkInstance instance);
|
||||||
|
};
|
1138
src/lightmap/vulkanobjects.h
Normal file
1138
src/lightmap/vulkanobjects.h
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue