From e38c08ff85c436e1bb0e1e561513c21114311349 Mon Sep 17 00:00:00 2001 From: mrq Date: Sun, 12 Jun 2022 17:21:00 -0500 Subject: [PATCH] Commit for 2022.06.12 17-21-07.7z --- Makefile | 99 ++-- bin/data/config.json | 73 ++- bin/data/entities/gui/mainmenu/menu.json | 4 +- bin/data/entities/model.json | 4 +- bin/data/scenes/ss2/medsci.json | 2 +- bin/data/scenes/ss2/test.json | 1 + bin/dreamcast/config.json | 30 +- client/client/ext.cpp | 24 +- client/main.cpp | 50 +- debug.sh | 10 +- engine/inc/uf/engine/behavior/behavior.h | 5 +- engine/inc/uf/engine/scene/behavior.h | 2 + engine/inc/uf/ext/json/json.h | 2 +- engine/inc/uf/ext/opengl/opengl.h | 24 +- .../inc/uf/ext/opengl/rendermodes/compute.h | 27 - .../inc/uf/ext/opengl/rendermodes/deferred.h | 1 + engine/inc/uf/ext/vulkan/graphic.h | 2 +- engine/inc/uf/ext/vulkan/rendermode.h | 17 +- .../inc/uf/ext/vulkan/rendermodes/compute.h | 26 - .../inc/uf/ext/vulkan/rendermodes/deferred.h | 2 + engine/inc/uf/ext/vulkan/vulkan.h | 23 +- engine/inc/uf/macros.h | 12 +- engine/inc/uf/spec/renderer/opengl.h | 1 - engine/inc/uf/spec/renderer/vulkan.h | 1 - engine/inc/uf/utils/math/vector.h | 1 + engine/inc/uf/utils/string/ext.h | 2 +- engine/inc/uf/utils/thread/perthread.h | 10 + engine/inc/uf/utils/thread/perthread.inl | 24 + engine/inc/uf/utils/thread/thread.h | 116 ++-- engine/src/engine/asset/asset.cpp | 98 +--- engine/src/engine/behavior/behavior.cpp | 23 +- engine/src/engine/entity/behavior.cpp | 2 +- engine/src/engine/graph/decode.cpp | 37 +- engine/src/engine/graph/encode.cpp | 39 +- engine/src/engine/graph/graph.cpp | 53 +- engine/src/engine/object/behavior.cpp | 4 + engine/src/engine/object/behaviors/graph.cpp | 4 +- engine/src/engine/object/behaviors/render.cpp | 2 +- engine/src/engine/scene/scene.cpp | 56 +- engine/src/ext/opengl/commands.cpp | 52 +- engine/src/ext/opengl/graphic.cpp | 32 +- engine/src/ext/opengl/opengl.cpp | 150 +++-- engine/src/ext/opengl/rendermode.cpp | 5 +- engine/src/ext/opengl/rendermodes/base.cpp | 9 +- engine/src/ext/opengl/rendermodes/compute.cpp | 49 -- .../src/ext/opengl/rendermodes/deferred.cpp | 3 + .../ext/opengl/rendermodes/rendertarget.cpp | 2 +- engine/src/ext/openvr/openvr.cpp | 4 +- engine/src/ext/reactphysics/reactphysics.cpp | 8 + engine/src/ext/vulkan/device.cpp | 125 ++++- engine/src/ext/vulkan/graphic.cpp | 36 +- engine/src/ext/vulkan/rendermode.cpp | 61 +- engine/src/ext/vulkan/rendermodes/base.cpp | 37 +- engine/src/ext/vulkan/rendermodes/compute.cpp | 260 --------- .../src/ext/vulkan/rendermodes/deferred.cpp | 97 +++- .../ext/vulkan/rendermodes/rendertarget.cpp | 128 +---- engine/src/ext/vulkan/swapchain.cpp | 4 +- engine/src/ext/vulkan/vulkan.cpp | 298 +++++++--- engine/src/ext/xatlas/xatlas.cpp | 20 +- engine/src/utils/thread/thread.cpp | 98 +++- ext/behaviors/baking/behavior.cpp | 23 +- ext/behaviors/hands/behavior.cpp | 525 ------------------ ext/behaviors/hands/behavior.h | 17 - ext/behaviors/light/behavior.cpp | 18 +- ext/behaviors/player/behavior.cpp | 55 +- ext/behaviors/player/behavior.h | 4 +- ext/behaviors/scene/behavior.cpp | 22 +- ext/behaviors/voxelizer/behavior.cpp | 6 +- ext/gui/behavior.cpp | 205 +++++-- ext/main.cpp | 82 ++- makefiles/default/arch | 1 + makefiles/default/cc | 1 + makefiles/default/renderer | 1 + makefiles/dreamcast.gcc.make | 1 + makefiles/win64.clang.make | 2 +- makefiles/win64.gcc.make | 4 +- 76 files changed, 1520 insertions(+), 1838 deletions(-) delete mode 100644 engine/inc/uf/ext/opengl/rendermodes/compute.h delete mode 100644 engine/inc/uf/ext/vulkan/rendermodes/compute.h delete mode 100644 engine/src/ext/opengl/rendermodes/compute.cpp delete mode 100644 engine/src/ext/vulkan/rendermodes/compute.cpp delete mode 100644 ext/behaviors/hands/behavior.cpp delete mode 100644 ext/behaviors/hands/behavior.h create mode 100644 makefiles/default/arch create mode 100644 makefiles/default/cc create mode 100644 makefiles/default/renderer diff --git a/Makefile b/Makefile index a211a012..a9732534 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,18 @@ -ARCH = win64 -CC = $(shell cat "./bin/exe/default.config") +ARCH = $(shell cat "./makefiles/default/arch") +CC = $(shell cat "./makefiles/default/cc") +RENDERER = $(shell cat "./makefiles/default/renderer") TARGET_NAME = program TARGET_EXTENSION = exe TARGET_LIB_EXTENSION = dll -RENDERER = vulkan PREFIX = $(ARCH).$(CC) include makefiles/$(PREFIX).make -.PHONY: $(ARCH)-$(CC) +PREFIX = $(ARCH).$(CC).$(RENDERER) +PREFIX_PATH = $(ARCH)/$(CC)/$(RENDERER) + +.PHONY: $(PREFIX) + @echo "Setting defaults: $(ARCH).$(CC).$(RENDERER)" .FORCE: @@ -22,6 +26,7 @@ ENGINE_LIB_DIR += ./engine/lib EXT_SRC_DIR += ./ext CLIENT_SRC_DIR += ./client + UF_LIBS += EXT_LIBS += FLAGS += @@ -38,15 +43,14 @@ EXT_LIB_NAME += ext #VULKAN_SDK_PATH += /c/VulkanSDK/1.3.204.1/ VULKAN_SDK_PATH += /c/VulkanSDK/1.3.211.0/ -#GLSLC += $(VULKAN_SDK_PATH)/Bin/glslangValidator GLSLC += $(VULKAN_SDK_PATH)/Bin/glslc SPV_OPTIMIZER += $(VULKAN_SDK_PATH)/Bin/spirv-opt # Base Engine's DLL -INC_DIR += $(ENGINE_INC_DIR)/$(ARCH)/$(CC) -LIB_DIR += $(ENGINE_LIB_DIR)/$(ARCH) +INC_DIR += $(ENGINE_INC_DIR) +LIB_DIR += $(ENGINE_LIB_DIR) INCS += -I$(ENGINE_INC_DIR) -I$(INC_DIR) -I./dep/ #-I/mingw64/include -LIBS += -L$(ENGINE_LIB_DIR) -L$(LIB_DIR) -L$(LIB_DIR)/$(CC) +LIBS += -L$(ENGINE_LIB_DIR) -L$(LIB_DIR) -L$(LIB_DIR)/$(ARCH) -L$(LIB_DIR)/$(PREFIX_PATH) LINKS += $(UF_LIBS) $(EXT_LIBS) $(DEPS) DEPS += @@ -55,6 +59,7 @@ ifneq (,$(findstring win64,$(ARCH))) REQ_DEPS += $(RENDERER) json:nlohmann png zlib openal ogg freetype curl luajit reactphysics meshoptimizer xatlas simd ctti gltf # ncurses openvr draco discord bullet ultralight-ux FLAGS += DEPS += -lgdi32 + LINKS += -Wl,-subsystem,windows else ifneq (,$(findstring dreamcast,$(ARCH))) REQ_DEPS += simd opengl gldc json:nlohmann reactphysics png zlib ctti # lua ogg openal aldc gltf freetype bullet meshoptimizer draco luajit ultralight-ux ncurses curl openvr discord endif @@ -206,35 +211,34 @@ endif SRCS_DLL += $(wildcard $(ENGINE_SRC_DIR)/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*/*/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*/*/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*/*/*.cpp) OBJS_DLL += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_DLL)) BASE_DLL += lib$(LIB_NAME) -IM_DLL += $(ENGINE_LIB_DIR)/$(ARCH)/$(CC)/$(BASE_DLL).$(TARGET_LIB_EXTENSION).a -EX_DLL += $(BIN_DIR)/exe/lib/$(ARCH)/$(CC)/$(BASE_DLL).$(TARGET_LIB_EXTENSION) +IM_DLL += $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL).$(TARGET_LIB_EXTENSION).a +EX_DLL += $(BIN_DIR)/exe/lib/$(PREFIX_PATH)/$(BASE_DLL).$(TARGET_LIB_EXTENSION) # External Engine's DLL EXT_INC_DIR += $(INC_DIR) EXT_LB_FLAGS += $(LIB_DIR) EXT_DEPS += -l$(LIB_NAME) $(DEPS) EXT_LINKS += $(UF_LIBS) $(EXT_LIBS) $(EXT_DEPS) -#-Wl,-subsystem,windows EXT_LIB_DIR += $(ENGINE_LIB_DIR)/$(ARCH) -EXT_INCS += -I$(ENGINE_INC_DIR) -I$(EXT_INC_DIR) -I$(VULKAN_SDK_PATH)/include -I/mingw64/include -EXT_LIBS += -L$(ENGINE_LIB_DIR) -L$(EXT_LIB_DIR) -L$(EXT_LIB_DIR)/$(CC) -L$(VULKAN_SDK_PATH)/Lib -L/mingw64/lib +EXT_INCS += -I$(ENGINE_INC_DIR) -I$(EXT_INC_DIR) -I/mingw64/include +EXT_LIBS += -L$(ENGINE_LIB_DIR) -L$(EXT_LIB_DIR) -L$(EXT_LIB_DIR)/$(ARCH) -L$(EXT_LIB_DIR)/$(PREFIX_PATH) -L/mingw64/lib SRCS_EXT_DLL += $(wildcard $(EXT_SRC_DIR)/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*/*/*.cpp) OBJS_EXT_DLL += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_EXT_DLL)) BASE_EXT_DLL += lib$(EXT_LIB_NAME) -EXT_IM_DLL += $(ENGINE_LIB_DIR)/$(ARCH)/$(CC)/$(BASE_EXT_DLL).$(TARGET_LIB_EXTENSION).a -EXT_EX_DLL += $(BIN_DIR)/exe/lib/$(ARCH)/$(CC)/$(BASE_EXT_DLL).$(TARGET_LIB_EXTENSION) +EXT_IM_DLL += $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL).$(TARGET_LIB_EXTENSION).a +EXT_EX_DLL += $(BIN_DIR)/exe/lib/$(PREFIX_PATH)/$(BASE_EXT_DLL).$(TARGET_LIB_EXTENSION) # Client EXE SRCS += $(wildcard $(CLIENT_SRC_DIR)/*.cpp) $(wildcard $(CLIENT_SRC_DIR)/*/*.cpp) OBJS += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS)) -TARGET += $(BIN_DIR)/exe/$(TARGET_NAME).$(CC).$(TARGET_EXTENSION) +TARGET += $(BIN_DIR)/exe/$(TARGET_NAME).$(PREFIX).$(TARGET_EXTENSION) # Shaders SRCS_SHADERS += $(wildcard bin/data/shaders/*.glsl) $(wildcard bin/data/shaders/*/*.glsl) $(wildcard bin/data/shaders/*/*/*.glsl) TARGET_SHADERS += $(patsubst %.glsl,%.spv,$(SRCS_SHADERS)) ifneq (,$(findstring dreamcast,$(ARCH))) -#$(ARCH): $(EX_DLL) $(EXT_EX_DLL) $(TARGET) ./bin/dreamcast/$(TARGET_NAME).cdi -$(ARCH): $(TARGET) ./bin/dreamcast/$(TARGET_NAME).cdi +#$(PREFIX): $(EX_DLL) $(EXT_EX_DLL) $(TARGET) ./bin/dreamcast/$(TARGET_NAME).cdi +$(PREFIX): $(TARGET) ./bin/dreamcast/$(TARGET_NAME).cdi SRCS_DLL = $(wildcard $(ENGINE_SRC_DIR)/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*/*/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*/*/*/*.cpp) OBJS_DLL = $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_DLL)) @@ -245,17 +249,17 @@ DEPS += -lkallisti -lc -lm -lgcc -lstdc++ # -l$(LIB_NAME) -l$(EXT_LIB_NAME) %.$(PREFIX).o: %.cpp $(CXX) $(FLAGS) $(INCS) -c $< -o $@ -$(EX_DLL): FLAGS += -DUF_EXPORTS -DJSON_DLL_BUILD +$(EX_DLL): FLAGS += -DUF_EXPORTS $(EX_DLL): $(OBJS_DLL) $(KOS_AR) cru $@ $^ $(KOS_RANLIB) $@ - cp $@ $(ENGINE_LIB_DIR)/$(ARCH)/$(CC)/$(BASE_DLL).a + cp $@ $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL).a -$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS -DJSON_DLL_BUILD +$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS $(EXT_EX_DLL): $(OBJS_EXT_DLL) $(KOS_AR) cru $@ $^ $(KOS_RANLIB) $@ - cp $@ $(ENGINE_LIB_DIR)/$(ARCH)/$(CC)/$(BASE_EXT_DLL).a + cp $@ $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL).a ./bin/dreamcast/romdisk.img: $(KOS_GENROMFS) -f ./bin/dreamcast/romdisk.img -d ./bin/dreamcast/romdisk/ -v @@ -274,35 +278,35 @@ cdi: cd ./bin/dreamcast/; ./elf2cdi.sh $(TARGET_NAME) else -$(ARCH): $(EX_DLL) $(TARGET) $(TARGET_SHADERS) +$(PREFIX): $(EX_DLL) $(TARGET) $(TARGET_SHADERS) %.$(PREFIX).o: %.cpp $(CXX) $(FLAGS) $(INCS) -c $< -o $@ -$(EX_DLL): FLAGS += -DUF_EXPORTS -DEXT_EXPORTS -DJSON_DLL_BUILD -#$(EX_DLL): FLAGS += -DUF_EXPORTS -DJSON_DLL_BUILD +$(EX_DLL): FLAGS += -DUF_EXPORTS -DEXT_EXPORTS +#$(EX_DLL): FLAGS += -DUF_EXPORTS $(EX_DLL): $(OBJS_DLL) - $(CXX) -shared -o $(EX_DLL) -Wl,--out-implib=$(IM_DLL) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS) - cp $(ENGINE_LIB_DIR)/$(ARCH)/$(CC)/$(BASE_DLL).$(TARGET_LIB_EXTENSION).a $(ENGINE_LIB_DIR)/$(ARCH)/$(CC)/$(BASE_DLL).a + $(CXX) $(FLAGS) -shared -o $(EX_DLL) -Wl,--out-implib=$(IM_DLL) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS) + cp $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL).$(TARGET_LIB_EXTENSION).a $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL).a + @echo -n $(ARCH) > "./bin/exe/default/arch" + @echo -n $(CC) > "./bin/exe/default/cc" + @echo -n $(RENDERER) > "./bin/exe/default/renderer" + @echo "Setting defaults: $(ARCH).$(CC).$(RENDERER)" -$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS -DJSON_DLL_BUILD +$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS $(EXT_EX_DLL): $(OBJS_EXT_DLL) $(CXX) -shared -o $(EXT_EX_DLL) -Wl,--out-implib=$(EXT_IM_DLL) $(OBJS_EXT_DLL) $(EXT_LIBS) $(EXT_INCS) $(EXT_LINKS) - cp $(ENGINE_LIB_DIR)/$(ARCH)/$(CC)/$(BASE_EXT_DLL).$(TARGET_LIB_EXTENSION).a $(ENGINE_LIB_DIR)/$(ARCH)/$(CC)/$(BASE_EXT_DLL).a + cp $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL).$(TARGET_LIB_EXTENSION).a $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL).a $(TARGET): $(OBJS) $(CXX) $(FLAGS) $(OBJS) $(LIBS) $(INCS) $(LINKS) -l$(LIB_NAME) -o $(TARGET) -# $(CXX) $(FLAGS) $(OBJS) $(LIBS) $(INCS) $(LINKS) -l$(LIB_NAME) -o $(TARGET) -# $(CXX) $(FLAGS) $(OBJS) $(LIBS) $(INCS) $(LINKS) -l$(LIB_NAME) -l$(EXT_LIB_NAME) -o $(TARGET) - endif %.spv: %.glsl $(GLSLC) -std=450 -o $@ $< $(SPV_OPTIMIZER) --preserve-bindings --preserve-spec-constants -O $@ -o $@ -ifneq (,$(findstring dreamcast,$(ARCH))) clean: @-rm $(EX_DLL) @-rm $(EXT_EX_DLL) @@ -312,31 +316,26 @@ clean: @-rm -f $(OBJS_EXT_DLL) @-rm -f $(OBJS) +ifneq (,$(findstring dreamcast,$(ARCH))) @-rm ./bin/dreamcast/build/* @-rm ./bin/dreamcast/romdisk.* @-rm ./bin/dreamcast/$(TARGET_NAME).* - -clean-zips: - @-find ./bin/data/ -name "*.gz" -type f -delete +endif run: +ifneq (,$(findstring dreamcast,$(ARCH))) $(KOS_EMU) ./bin/dreamcast/$(TARGET_NAME).cdi else -clean: - @-rm $(EX_DLL) - @-rm $(EXT_EX_DLL) - @-rm $(TARGET) - - @-rm -f $(OBJS_DLL) - @-rm -f $(OBJS_EXT_DLL) - @-rm -f $(OBJS) + @echo -n $(ARCH) > "./bin/exe/default/arch" + @echo -n $(CC) > "./bin/exe/default/cc" + @echo -n $(RENDERER) > "./bin/exe/default/renderer" + @echo "Setting defaults: $(ARCH).$(CC).$(RENDERER)" + ./program.sh +endif clean-zips: @-find ./bin/data/ -name "*.gz" -type f -delete -run: - ./program.sh -endif clean-uf: @-rm $(EX_DLL) @-rm -f $(OBJS_DLL) @@ -356,6 +355,8 @@ clean-shaders: backup: make ARCH=dreamcast clean - make CC=gcc clean - make CC=clang clean + make CC=gcc RENDERER=opengl clean + make CC=gcc RENDERER=vulkan clean + make CC=clang RENDERER=opengl clean + make CC=clang RENDERER=vulkan clean $(7Z) a -r ../misc/backups/$(shell date +"%Y.%m.%d\ %H-%M-%S").7z . \ No newline at end of file diff --git a/bin/data/config.json b/bin/data/config.json index 75ecefeb..e628eafb 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -5,20 +5,20 @@ "meshes": { "interleaved": false }, "matrix": { "reverseInfinite": true }, "lights": { "enabled": true, - "useLightmaps": false, - "max": 32 + "useLightmaps": true, + "max": 16 }, "shadows": { "enabled": true, - "update": 3, - "max": 6, - "samples": 2, + "update": 2, + "max": 8, + "samples": 1, "experimental mode": 1 }, "textures": { "max": { - "2D": 1024, - "cube": 128, + "2D": 256, + "cube": 32, "3D": 1 } }, @@ -26,9 +26,9 @@ "limiter": 1, "size": 128, "dispatch": 8, - "cascades": 4, + "cascades": 3, "cascadePower": 3, - "granularity": 8, + "granularity": 12, "voxelizeScale": 1, "occlusionFalloff": 2, "shadows": 0, @@ -52,10 +52,11 @@ "filters": [ "MessageID = 0x4dae5635", // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout (false positive for cubemaps) "MessageID = 0x609a13b", // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls) - "MessageID = 0x23e43bb7" // UNASSIGNED-CoreValidation-Shader-InputNotProduced (from depth-only calls) + "MessageID = 0x23e43bb7", // UNASSIGNED-CoreValidation-Shader-InputNotProduced (from depth-only calls) + + "MessageID = 0x71500fba" // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup) // "MessageID = 0xe91b58a0" // VUID-vkCmdDrawIndexed-None-02686 (?) - // "MessageID = 0x71500fba", // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup) // "MessageID = 0x124ffb34", // VUID-VkImageMemoryBarrier-oldLayout-01197 (hacky bloom-shit) // "MessageID = 0x8ab1932c", // VUID-VkImageViewCreateInfo-imageViewType-04973 (hacky bloom-shit) @@ -66,26 +67,23 @@ ] }, "framebuffer": { - "size": 1, - // "size": [ 640, 480, "NEAREST" ], - // "size": [ 1280, 720 ], - // "size": [ 960, 540 ], - // "size": [ 640, 480 ], - "msaa": 1 + "msaa": 1, + "size": 1 + // "size": [ 640, 480, "NEAREST" ] + // "size": [ 1280, 720 ] + // "size": [ 960, 540 ] + // "size": [ 640, 480 ] }, + "gpu": "auto", "experimental": { - "rebuild on tick begin": false, - "wait on render end": false, - "individual pipelines": true, - "multithreaded command recording": true, - "multithreaded command rendering": false, - "deferred mode": "", - "deferred reconstruct position": true, - "deferred alias output to swapchain": false, + "batch queue submissions": true, + "dedicated thread": false + }, + "invariant": {}, + "pipelines": { "vsync": false, "hdr": false, "vxgi": true, - "deferred sampling": true, "culling": true, "bloom": false }, @@ -129,17 +127,7 @@ "opengl": { "validation": { "enabled": true }, "framebuffer": { "size": 1, "msaa": 1 }, - "experimental": { - "rebuild on tick begin": false, - "wait on render end": false, - "individual pipelines": true, - "multithreaded command recording": false, // - "multithreaded command rendering": false, - "deferred mode": "", - // "deferred mode": "deferredSampling", - "deferred reconstruct position": true, - "deferred alias output to swapchain": true, - "hdr": false, + "pipelines": { "culling": true }, "formats": { @@ -227,13 +215,13 @@ "framerate": "auto" }, "threads": { - "workers" : "auto", // "async" + "workers" : "auto", "frame limiter": "auto" }, "debug": { "framerate": { "print": true, - "every": 1 + "every": 2 }, "garbage collection": { "enabled": true, @@ -253,7 +241,7 @@ "window" : { "terminal" : { "ncurses" : false, - "visible" : true + "visible" : false }, "keyboard" : { "repeat" : false @@ -261,9 +249,10 @@ "cursor" : { "visible" : true, "center" : false, - "sensitivity": [ 1, 1 ] + "sensitivity": [ 1.25, 1.25 ], + "smoothing": [ 10, 10 ] }, - "mode" : "windowed", // fullscreen, borderless, windowed + "mode" : "borderless", // fullscreen, borderless, windowed "icon" : "./data/textures/icon.png", "size" : [ 1920, 1080 ], // "size" : [ 1280, 720 ], diff --git a/bin/data/entities/gui/mainmenu/menu.json b/bin/data/entities/gui/mainmenu/menu.json index a874f30e..40450ab2 100644 --- a/bin/data/entities/gui/mainmenu/menu.json +++ b/bin/data/entities/gui/mainmenu/menu.json @@ -3,8 +3,8 @@ "type": "Gui", "ignore": false, "assets": [ - "./scripts/menu.lua", - "./textures/menu.png" + "./textures/menu.png", + "./scripts/menu.lua" ], "transform": { "position": [ 0, 0, 0 ], diff --git a/bin/data/entities/model.json b/bin/data/entities/model.json index 85f1d09a..0a1e3a2e 100644 --- a/bin/data/entities/model.json +++ b/bin/data/entities/model.json @@ -24,7 +24,7 @@ "precision": 4, "combined": false, "encode buffers": true, - "unwrap": false, + "unwrap": true, "optimize": "tagged", "quit": true, "mesh": { @@ -43,7 +43,7 @@ "useInputMeshUvs": true, "maxIterations": 8, // "maxChartSize": 0, - // "padding": 0, + "padding": 4, // "texelsPerUnit": 0, "bilinear": true, "blockAlign": true, diff --git a/bin/data/scenes/ss2/medsci.json b/bin/data/scenes/ss2/medsci.json index dcf9b6e2..f70bfce4 100644 --- a/bin/data/scenes/ss2/medsci.json +++ b/bin/data/scenes/ss2/medsci.json @@ -2,7 +2,7 @@ "import": "/model.json", "assets": [ // { "filename": "./craeture.json", "delay": 1 }, - { "filename": "./test.json", "delay": 1 }, + // { "filename": "./test.json", "delay": 1 }, // { "filename": "./models/tiny_msci.glb" } { "filename": "./models/tiny_msci/graph.json" } diff --git a/bin/data/scenes/ss2/test.json b/bin/data/scenes/ss2/test.json index c4fc9edc..4d6bc3a7 100644 --- a/bin/data/scenes/ss2/test.json +++ b/bin/data/scenes/ss2/test.json @@ -16,6 +16,7 @@ "scaling": "relative", "world": true, "cull mode": "none", + "color": [ 1, 0, 1, 1 ], "text settings": { "scale": 8, "font": "Coolvetica.ttf", diff --git a/bin/dreamcast/config.json b/bin/dreamcast/config.json index 3e42ef10..7085792d 100644 --- a/bin/dreamcast/config.json +++ b/bin/dreamcast/config.json @@ -1,12 +1,12 @@ { "engine": { "scenes": { - "start": "McDonalds", + "start": "SS2", "meshes": { "interleaved": false }, "matrix": { "reverseInfinite": false }, "lights": { "enabled": false, "useLightmaps": true, - "max": 2 + "max": 0 }, "shadows": { "enabled": false, @@ -25,23 +25,9 @@ }, "ext": { "opengl": { - "validation": { - "enabled": true - }, - "framebuffer": { - "size": 1, - "msaa": 1 - }, - "experimental": { - "rebuild on tick begin": false, - "wait on render end": false, - "individual pipelines": true, - "multithreaded command recording": true, - "multithreaded command rendering": false, - "deferred mode": "", - "deferred reconstruct position": true, - "deferred alias output to swapchain": true, - "hdr": false, + "validation": { "enabled": false }, + "framebuffer": { "size": 1, "msaa": 1 }, + "pipelines": { "culling": true }, "formats": { @@ -134,14 +120,16 @@ "window" : { "terminal" : { "ncurses" : false, - "visible" : true + "visible" : false }, "keyboard" : { "repeat" : false }, "cursor" : { "visible" : true, - "center" : false + "center" : false, + "sensitivity": [ 1.25, 1.25 ], + "smoothing": [ 10, 10 ] }, "mode" : "windowed", "icon" : "./data/textures/icon.png", diff --git a/client/client/ext.cpp b/client/client/ext.cpp index adfe7601..c45ae933 100644 --- a/client/client/ext.cpp +++ b/client/client/ext.cpp @@ -120,32 +120,22 @@ void client::tick() { if ( client::window.hasFocus() ) { // fullscreener TIMER(1, (uf::inputs::kbm::states::LAlt || uf::inputs::kbm::states::RAlt) && uf::inputs::kbm::states::Enter && ) { - UF_MSG_DEBUG("mpoop fullscreen"); - client::window.toggleFullscreen( false ); uf::renderer::states::resized = true; + client::window.toggleFullscreen( false ); } // mouse move if ( client::config["window"]["mouse"]["center"].as() ) { - auto previous = client::window.getMousePosition(); - client::window.setMousePosition(client::window.getSize()/2); - auto current = client::window.getMousePosition(); auto size = client::window.getSize(); + auto current = client::window.getMousePosition(); + auto center = client::window.getSize() / 2.0f; + client::window.setMousePosition(client::window.getSize() / 2.0f); uf::hooks.call("window:Mouse.Moved", pod::payloads::windowMouseMoved{ { - { - "window:Mouse.Moved", - "client", - }, - { - pod::Vector2ui{ size.x, size.y }, - }, + { "window:Mouse.Moved", "client", }, + { pod::Vector2ui{ size.x, size.y }, }, }, - { - current, - previous - current, - 0 - } + { center, current - center, 0 } }); } } diff --git a/client/main.cpp b/client/main.cpp index e7ab9924..863c5a6a 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -6,8 +6,10 @@ #include #include -#include +#include + +#include #include namespace { @@ -55,7 +57,6 @@ int main(int argc, char** argv){ client::initialize(); ext::initialize(); - // For Multithreaded initialization while ( !client::ready || !ext::ready ) { static uf::Timer timer(false); @@ -67,37 +68,32 @@ int main(int argc, char** argv){ next *= 2; } } + while ( client::ready && ext::ready ) { #if UF_EXCEPTIONS try { #endif - /* - static bool first = false; if ( !first ) { first = true; - ext::json::Value json; - uf::hooks.call("window:Resized", pod::payloads::windowResized{ - { - "window:Resized", - "os", - }, - { uf::vector::decode( client::config["window"]["size"], pod::Vector2ui{} ) }, + if ( uf::renderer::settings::experimental::dedicatedThread /*&& !uf::renderer::states::rebuild*/ ) { + auto& thread = uf::thread::get("Aux"); + uf::thread::queue(thread, [&]{ + ext::render(); + client::render(); }); + + client::tick(); + ext::tick(); + + uf::thread::wait( thread ); + } else { + // UF_TIMER_MULTITRACE_START("Frame Start"); + client::tick(); + ext::tick(); + // UF_TIMER_MULTITRACE("Ticked"); + ext::render(); + client::render(); + // UF_TIMER_MULTITRACE("Rendered"); + // UF_TIMER_MULTITRACE_END("Frame End"); } - */ - #if UF_ENV_DREAMCAST - // UF_TIMER_MULTITRACE_START("Starting"); - ext::tick(); - client::tick(); - // UF_TIMER_MULTITRACE("render"); - ext::render(); - client::render(); - // UF_TIMER_MULTITRACE("tick"); - // UF_TIMER_MULTITRACE_END("Finished"); - #else - client::tick(); - client::render(); - ext::tick(); - ext::render(); - #endif #if UF_EXCEPTIONS } catch ( std::runtime_error& e ) { UF_MSG_ERROR("RUNTIME ERROR: " << e.what()); diff --git a/debug.sh b/debug.sh index d74a4108..211e3142 100644 --- a/debug.sh +++ b/debug.sh @@ -1,8 +1,10 @@ #!/bin/bash cd bin -PREFIX=$(cat ./exe/default.config) -cp ./exe/lib/win64/*.dll . -cp ./exe/lib/win64/$PREFIX/*.dll . -gdb ./exe/program.$PREFIX.exe +ARCH=$(cat ./exe/default/arch) +CC=$(cat ./exe/default/cc) +RENDERER=$(cat ./exe/default/renderer) +cp ./exe/lib/$ARCH/*.dll . +cp ./exe/lib/$ARCH/$CC/$RENDERER/*.dll . +gdb ./exe/program.$ARCH.$CC.$RENDERER.exe rm *.dll diff --git a/engine/inc/uf/engine/behavior/behavior.h b/engine/inc/uf/engine/behavior/behavior.h index bedc509f..f9040044 100644 --- a/engine/inc/uf/engine/behavior/behavior.h +++ b/engine/inc/uf/engine/behavior/behavior.h @@ -52,7 +52,7 @@ namespace uf { typedef uf::stl::vector container_t; // typedef uf::stl::vector container_t; container_t m_behaviors; - struct { + struct Graph { typedef pod::Behavior::function_t value_t; // typedef uint_fast8_t value_t; uf::stl::vector initialize; @@ -70,6 +70,9 @@ namespace uf { container_t& getBehaviors(); const container_t& getBehaviors() const; + Graph& getGraph(); + const Graph& getGraph() const; + bool hasBehavior( const pod::Behavior& ); void addBehavior( const pod::Behavior& ); void removeBehavior( const pod::Behavior& ); diff --git a/engine/inc/uf/engine/scene/behavior.h b/engine/inc/uf/engine/scene/behavior.h index 9139eb71..dc1755ab 100644 --- a/engine/inc/uf/engine/scene/behavior.h +++ b/engine/inc/uf/engine/scene/behavior.h @@ -17,6 +17,8 @@ namespace uf { // we could keep a cache of controllers for each rendermode, but we have to invalidate the cache every time the graph regenerates uf::stl::unordered_map cache; #endif + + pod::Thread::Tasks tasks; ); } } \ No newline at end of file diff --git a/engine/inc/uf/ext/json/json.h b/engine/inc/uf/ext/json/json.h index f9e63b0a..adbab9ac 100644 --- a/engine/inc/uf/ext/json/json.h +++ b/engine/inc/uf/ext/json/json.h @@ -52,7 +52,7 @@ namespace ext { template T& encode( const ext::json::Value& json, T& output, const ext::json::EncodingSettings& settings = {} ); template ext::json::Value& decode( ext::json::Value& json, const T& input, const DecodingSettings& settings = {} ); - inline uf::stl::string UF_API encode( const ext::json::Value& json, const ext::json::EncodingSettings& settings = {} ) { + inline uf::stl::string encode( const ext::json::Value& json, const ext::json::EncodingSettings& settings = {} ) { uf::stl::string output; encode( json, output, settings ); return output; diff --git a/engine/inc/uf/ext/opengl/opengl.h b/engine/inc/uf/ext/opengl/opengl.h index 5f7ae471..6da22193 100644 --- a/engine/inc/uf/ext/opengl/opengl.h +++ b/engine/inc/uf/ext/opengl/opengl.h @@ -26,23 +26,31 @@ namespace ext { extern UF_API ext::opengl::enums::Filter::type_t swapchainUpscaleFilter; namespace experimental { + extern UF_API bool dedicatedThread; extern UF_API bool rebuildOnTickBegin; + extern UF_API bool batchQueueSubmissions; + } + + namespace invariant { extern UF_API bool waitOnRenderEnd; extern UF_API bool individualPipelines; - extern UF_API bool multithreadedCommandRecording; - extern UF_API bool multithreadedCommandRendering; + extern UF_API bool multithreadedRecording; + extern UF_API uf::stl::string deferredMode; extern UF_API bool deferredReconstructPosition; extern UF_API bool deferredAliasOutputToSwapchain; + extern UF_API bool deferredSampling; extern UF_API bool multiview; + } + + namespace pipelines { extern UF_API bool vsync; extern UF_API bool hdr; extern UF_API bool vxgi; - extern UF_API bool deferredSampling; extern UF_API bool culling; extern UF_API bool bloom; } - + namespace formats { extern UF_API GLhandle(VkColorSpaceKHR) colorSpace; extern UF_API ext::opengl::enums::Format::type_t color; @@ -61,9 +69,9 @@ namespace ext { extern UF_API std::mutex mutex; extern UF_API std::mutex immediateModeMutex; - extern UF_API RenderMode* currentRenderMode; + // extern UF_API RenderMode* currentRenderMode; extern UF_API uf::stl::vector renderModes; - extern UF_API uf::stl::vector scenes; + extern UF_API uf::ThreadUnique currentRenderMode; bool UF_API hasRenderMode( const uf::stl::string&, bool = true ); RenderMode& UF_API addRenderMode( RenderMode*, const uf::stl::string& = "" ); @@ -71,6 +79,10 @@ namespace ext { uf::stl::vector UF_API getRenderModes( const uf::stl::string&, bool = true ); uf::stl::vector UF_API getRenderModes( const uf::stl::vector&, bool = true ); void UF_API removeRenderMode( RenderMode*, bool = true ); + RenderMode* UF_API getCurrentRenderMode(); + RenderMode* UF_API getCurrentRenderMode( std::thread::id ); + void UF_API setCurrentRenderMode( RenderMode* renderMode ); + void UF_API setCurrentRenderMode( RenderMode* renderMode, std::thread::id ); void UF_API initialize( /*uint8_t = 0*/ ); void UF_API tick(); diff --git a/engine/inc/uf/ext/opengl/rendermodes/compute.h b/engine/inc/uf/ext/opengl/rendermodes/compute.h deleted file mode 100644 index 8adeb108..00000000 --- a/engine/inc/uf/ext/opengl/rendermodes/compute.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include - -namespace ext { - namespace opengl { - struct UF_API ComputeRenderMode : public RenderMode { - ext::opengl::Graphic blitter, compute; - pod::Vector2ui dispatchSize = { 32, 32 }; - - // RAII - virtual const uf::stl::string getType() const; - virtual const size_t blitters() const; - virtual ext::opengl::Graphic* getBlitter(size_t = 0); - virtual uf::stl::vector getBlitters(); - - virtual void createCommandBuffers(); - virtual void initialize( Device& device ); - virtual void tick(); - virtual void render(); - virtual void destroy(); - virtual void bindPipelines(); - virtual void pipelineBarrier( GLhandle(VkCommandBuffer), uint8_t = -1 ); - }; - } -} \ No newline at end of file diff --git a/engine/inc/uf/ext/opengl/rendermodes/deferred.h b/engine/inc/uf/ext/opengl/rendermodes/deferred.h index d1bef5ea..b0165a8c 100644 --- a/engine/inc/uf/ext/opengl/rendermodes/deferred.h +++ b/engine/inc/uf/ext/opengl/rendermodes/deferred.h @@ -17,6 +17,7 @@ namespace ext { virtual void createCommandBuffers( const uf::stl::vector& graphics ); virtual void initialize( Device& device ); virtual void tick(); + virtual void render(); virtual void destroy(); }; } diff --git a/engine/inc/uf/ext/vulkan/graphic.h b/engine/inc/uf/ext/vulkan/graphic.h index c38c6f27..7050da71 100644 --- a/engine/inc/uf/ext/vulkan/graphic.h +++ b/engine/inc/uf/ext/vulkan/graphic.h @@ -11,7 +11,7 @@ namespace ext { namespace vulkan { struct Graphic; - struct UF_API Pipeline { + struct UF_API Pipeline : public Buffers { bool aliased = false; Device* device = NULL; diff --git a/engine/inc/uf/ext/vulkan/rendermode.h b/engine/inc/uf/ext/vulkan/rendermode.h index f545e2ce..9ecf515e 100644 --- a/engine/inc/uf/ext/vulkan/rendermode.h +++ b/engine/inc/uf/ext/vulkan/rendermode.h @@ -8,7 +8,7 @@ namespace ext { namespace vulkan { struct Graphic; - struct UF_API RenderMode { + struct UF_API RenderMode : public Buffers { bool execute = false; bool executed = false; bool rebuild = false; @@ -57,6 +57,15 @@ namespace ext { uf::stl::unordered_map commandBufferCallbacks; void bindCallback( int32_t, const callback_t& ); + + uf::Image screenshot(size_t = 0, size_t = 0); + + commands_container_t& getCommands(); + commands_container_t& getCommands( std::thread::id ); + void lockMutex(); + void lockMutex( std::thread::id ); + void unlockMutex(); + void unlockMutex( std::thread::id ); virtual ~RenderMode(); // RAII @@ -69,10 +78,6 @@ namespace ext { virtual ext::vulkan::Graphic* getBlitter(size_t = 0); virtual uf::stl::vector getBlitters(); - virtual uf::Image screenshot(size_t = 0, size_t = 0); - - virtual commands_container_t& getCommands(); - virtual commands_container_t& getCommands( std::thread::id ); virtual GraphicDescriptor bindGraphicDescriptor( const GraphicDescriptor&, size_t = 0 ); @@ -86,6 +91,8 @@ namespace ext { virtual void destroy(); virtual void synchronize( uint64_t = UINT64_MAX ); virtual void pipelineBarrier( VkCommandBuffer, uint8_t = -1 ); + + virtual VkSubmitInfo queue(); }; } } \ No newline at end of file diff --git a/engine/inc/uf/ext/vulkan/rendermodes/compute.h b/engine/inc/uf/ext/vulkan/rendermodes/compute.h deleted file mode 100644 index 31efeca0..00000000 --- a/engine/inc/uf/ext/vulkan/rendermodes/compute.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include - -namespace ext { - namespace vulkan { - struct UF_API ComputeRenderMode : public ext::vulkan::RenderMode { - ext::vulkan::Graphic blitter, compute; - - // - virtual const uf::stl::string getType() const; - virtual const size_t blitters() const; - virtual ext::vulkan::Graphic* getBlitter(size_t = 0); - virtual uf::stl::vector getBlitters(); - - virtual void createCommandBuffers(); - virtual void initialize( Device& device ); - virtual void tick(); - virtual void render(); - virtual void destroy(); - virtual void bindPipelines(); - virtual void pipelineBarrier( VkCommandBuffer, uint8_t = -1 ); - }; - } -} \ No newline at end of file diff --git a/engine/inc/uf/ext/vulkan/rendermodes/deferred.h b/engine/inc/uf/ext/vulkan/rendermodes/deferred.h index b00fb16e..bd7e3d55 100644 --- a/engine/inc/uf/ext/vulkan/rendermodes/deferred.h +++ b/engine/inc/uf/ext/vulkan/rendermodes/deferred.h @@ -18,6 +18,8 @@ namespace ext { virtual void createCommandBuffers( const uf::stl::vector& graphics ); virtual void initialize( Device& device ); virtual void tick(); + virtual VkSubmitInfo queue(); + virtual void render(); virtual void destroy(); }; } diff --git a/engine/inc/uf/ext/vulkan/vulkan.h b/engine/inc/uf/ext/vulkan/vulkan.h index 01ec210f..4d56bc00 100644 --- a/engine/inc/uf/ext/vulkan/vulkan.h +++ b/engine/inc/uf/ext/vulkan/vulkan.h @@ -41,6 +41,7 @@ namespace ext { extern UF_API uint8_t msaa; extern UF_API bool validation; extern UF_API size_t viewCount; + extern UF_API size_t gpuID; constexpr size_t maxViews = 6; extern UF_API uf::stl::vector validationFilters; @@ -51,19 +52,27 @@ namespace ext { extern UF_API VkFilter swapchainUpscaleFilter; namespace experimental { + extern UF_API bool dedicatedThread; extern UF_API bool rebuildOnTickBegin; + extern UF_API bool batchQueueSubmissions; + } + + namespace invariant { extern UF_API bool waitOnRenderEnd; extern UF_API bool individualPipelines; - extern UF_API bool multithreadedCommandRecording; - extern UF_API bool multithreadedCommandRendering; + extern UF_API bool multithreadedRecording; + extern UF_API uf::stl::string deferredMode; extern UF_API bool deferredReconstructPosition; extern UF_API bool deferredAliasOutputToSwapchain; + extern UF_API bool deferredSampling; extern UF_API bool multiview; + } + + namespace pipelines { extern UF_API bool vsync; extern UF_API bool hdr; extern UF_API bool vxgi; - extern UF_API bool deferredSampling; extern UF_API bool culling; extern UF_API bool bloom; } @@ -87,10 +96,10 @@ namespace ext { extern UF_API Swapchain swapchain; extern UF_API std::mutex mutex; - extern UF_API RenderMode* currentRenderMode; + // extern UF_API RenderMode* currentRenderMode; extern UF_API uf::stl::vector renderModes; extern UF_API uf::stl::unordered_map renderModesMap; - extern UF_API uf::stl::vector scenes; + extern UF_API uf::ThreadUnique currentRenderMode; bool UF_API hasRenderMode( const uf::stl::string&, bool = true ); RenderMode& UF_API addRenderMode( RenderMode*, const uf::stl::string& = "" ); @@ -98,6 +107,10 @@ namespace ext { uf::stl::vector UF_API getRenderModes( const uf::stl::string&, bool = true ); uf::stl::vector UF_API getRenderModes( const uf::stl::vector&, bool = true ); void UF_API removeRenderMode( RenderMode*, bool = true ); + RenderMode* UF_API getCurrentRenderMode(); + RenderMode* UF_API getCurrentRenderMode( std::thread::id ); + void UF_API setCurrentRenderMode( RenderMode* renderMode ); + void UF_API setCurrentRenderMode( RenderMode* renderMode, std::thread::id ); void UF_API initialize( /*uint8_t = 0*/ ); void UF_API tick(); diff --git a/engine/inc/uf/macros.h b/engine/inc/uf/macros.h index 24ce96f2..0ac0a1f8 100644 --- a/engine/inc/uf/macros.h +++ b/engine/inc/uf/macros.h @@ -79,13 +79,13 @@ #define UF_TIMER_TRACE_INIT() uf::Timer TIMER_TRACE; #define UF_TIMER_TRACE(X) {\ - auto elapsed = TIMER_TRACE.elapsed().asMilliseconds();\ - if ( elapsed > 0 ) UF_MSG_DEBUG(TIMER_TRACE.elapsed().asMilliseconds() << "ms\t" << X);\ + auto elapsed = TIMER_TRACE.elapsed().asMicroseconds();\ + if ( elapsed > 0 ) UF_MSG_DEBUG(TIMER_TRACE.elapsed().asMicroseconds() << "us\t" << X);\ } #define UF_TIMER_TRACE_RESET(X) {\ - auto elapsed = TIMER_TRACE.elapsed().asMilliseconds();\ - if ( elapsed > 0 ) UF_MSG_DEBUG(TIMER_TRACE.elapsed().asMilliseconds() << "ms\t" << X);\ + auto elapsed = TIMER_TRACE.elapsed().asMicroseconds();\ + if ( elapsed > 0 ) UF_MSG_DEBUG(TIMER_TRACE.elapsed().asMicroseconds() << "us\t" << X);\ TIMER_TRACE.reset();\ } @@ -95,8 +95,8 @@ UF_MSG_DEBUG(X);\ #define UF_TIMER_MULTITRACE(X) {\ - TIMER_TRACE_CUR = TIMER_TRACE.elapsed().asMilliseconds();\ - UF_MSG_DEBUG(std::setfill(' ') << std::setw(4) << TIMER_TRACE_CUR << " ms\t" << std::setfill(' ') << std::setw(4) << (TIMER_TRACE_CUR - TIMER_TRACE_PREV) << " ms\t" << X);\ + TIMER_TRACE_CUR = TIMER_TRACE.elapsed().asMicroseconds();\ + UF_MSG_DEBUG(std::setfill(' ') << std::setw(4) << TIMER_TRACE_CUR << " ns\t" << std::setfill(' ') << std::setw(4) << (TIMER_TRACE_CUR - TIMER_TRACE_PREV) << " ns\t" << X);\ TIMER_TRACE_PREV = TIMER_TRACE_CUR;\ } diff --git a/engine/inc/uf/spec/renderer/opengl.h b/engine/inc/uf/spec/renderer/opengl.h index e619fb18..058b3177 100644 --- a/engine/inc/uf/spec/renderer/opengl.h +++ b/engine/inc/uf/spec/renderer/opengl.h @@ -4,7 +4,6 @@ #include #include #include -#include #include namespace spec { diff --git a/engine/inc/uf/spec/renderer/vulkan.h b/engine/inc/uf/spec/renderer/vulkan.h index 770fb96d..f2863ea0 100644 --- a/engine/inc/uf/spec/renderer/vulkan.h +++ b/engine/inc/uf/spec/renderer/vulkan.h @@ -4,7 +4,6 @@ #include #include #include -#include #include namespace spec { diff --git a/engine/inc/uf/utils/math/vector.h b/engine/inc/uf/utils/math/vector.h index 6ca74a56..8215edf2 100644 --- a/engine/inc/uf/utils/math/vector.h +++ b/engine/inc/uf/utils/math/vector.h @@ -11,6 +11,7 @@ #include #include +#include #include namespace pod { diff --git a/engine/inc/uf/utils/string/ext.h b/engine/inc/uf/utils/string/ext.h index 073edc00..13ec5d4d 100644 --- a/engine/inc/uf/utils/string/ext.h +++ b/engine/inc/uf/utils/string/ext.h @@ -12,7 +12,7 @@ namespace uf { // bool match( const uf::stl::string& str, const uf::stl::string& r ); bool UF_API isRegex( const uf::stl::string& str ); uf::stl::vector UF_API match( const uf::stl::string& str, const uf::stl::string& r ); - inline uf::stl::vector UF_API matches( const uf::stl::string& str, const uf::stl::string& r ) { return uf::string::match( str, r ); } + inline uf::stl::vector matches( const uf::stl::string& str, const uf::stl::string& r ) { return uf::string::match( str, r ); } bool UF_API matched( const uf::stl::string& str, const uf::stl::string& r ); diff --git a/engine/inc/uf/utils/thread/perthread.h b/engine/inc/uf/utils/thread/perthread.h index 118645a7..0d4593b4 100644 --- a/engine/inc/uf/utils/thread/perthread.h +++ b/engine/inc/uf/utils/thread/perthread.h @@ -8,13 +8,23 @@ namespace uf { class UF_API ThreadUnique { public: typedef T type_t; + typedef std::mutex* mutex_type_t; typedef std::thread::id id_t; typedef uf::stl::unordered_map container_t; + typedef uf::stl::unordered_map mutex_container_t; protected: container_t m_container; + mutex_container_t m_mutex_container; public: + ~ThreadUnique(); + bool has( id_t id = std::this_thread::get_id() ) const; T& get( id_t id = std::this_thread::get_id() ); + + void lock( id_t id = std::this_thread::get_id() ); + void unlock( id_t id = std::this_thread::get_id() ); + std::lock_guard guard( id_t id = std::this_thread::get_id() ); + container_t& container(); }; } diff --git a/engine/inc/uf/utils/thread/perthread.inl b/engine/inc/uf/utils/thread/perthread.inl index 9fea5b60..b0737048 100644 --- a/engine/inc/uf/utils/thread/perthread.inl +++ b/engine/inc/uf/utils/thread/perthread.inl @@ -1,3 +1,12 @@ +template +uf::ThreadUnique::~ThreadUnique() { + for ( auto& pair : m_mutex_container ) { + if ( !pair.second ) continue; + delete pair.second; + pair.second = NULL; + } +} + template bool uf::ThreadUnique::has( id_t id ) const { return m_container.count(id) > 0; @@ -7,6 +16,21 @@ T& uf::ThreadUnique::get( id_t id ) { return m_container[id]; } template +void uf::ThreadUnique::lock( id_t id ) { + if ( m_mutex_container.count(id) == 0 ) m_mutex_container[id] = new std::mutex; + m_mutex_container[id]->lock(); +} +template +void uf::ThreadUnique::unlock( id_t id ) { + if ( m_mutex_container.count(id) == 0 ) m_mutex_container[id] = new std::mutex; + m_mutex_container[id]->unlock(); +} +template +std::lock_guard uf::ThreadUnique::guard( id_t id ) { + if ( m_mutex_container.count(id) == 0 ) m_mutex_container[id] = new std::mutex; + return std::lock_guard(*m_mutex_container[id]); +} +template typename uf::ThreadUnique::container_t& uf::ThreadUnique::container() { return m_container; } \ No newline at end of file diff --git a/engine/inc/uf/utils/thread/thread.h b/engine/inc/uf/utils/thread/thread.h index 800b881c..632ffd64 100644 --- a/engine/inc/uf/utils/thread/thread.h +++ b/engine/inc/uf/utils/thread/thread.h @@ -31,12 +31,25 @@ namespace pod { std::condition_variable condition; std::thread thread; - pod::Thread::queue_t temps; - pod::Thread::container_t consts; + pod::Thread::queue_t queue; + pod::Thread::container_t container; uf::Timer timer; uint affinity = 0; + + struct UF_API Tasks { + uf::stl::string name = "Aux"; + bool waits = true; + + pod::Thread::queue_t container; + + inline void add( const pod::Thread::function_t& fun ) { container.emplace(fun); } + inline void emplace( const pod::Thread::function_t& fun ) { container.emplace(fun); } + inline void queue( const pod::Thread::function_t& fun ) { container.emplace(fun); } + inline void clear() { container = {}; } + }; }; + } namespace uf { @@ -46,29 +59,14 @@ namespace uf { extern UF_API std::thread::id mainThreadId; extern UF_API bool async; - /* Acts on thread */ - void UF_API start( pod::Thread& ); - void UF_API quit( pod::Thread& ); - - void UF_API tick( pod::Thread& ); - // void UF_API tick( pod::Thread&, const std::function& = NULL ); - + /* Easy to use async helper functions */ pod::Thread& UF_API fetchWorker( const uf::stl::string& name = "Aux" ); - void UF_API batchWorker( const pod::Thread::function_t&, const uf::stl::string& name = "Aux" ); - void UF_API batchWorkers( const uf::stl::vector&, bool = true, const uf::stl::string& name = "Aux" ); - void UF_API batchWorkers_Async( const uf::stl::vector&, bool = true, const uf::stl::string& name = "Aux" ); - void UF_API add( pod::Thread&, const pod::Thread::function_t&, bool = false ); - void UF_API process( pod::Thread& ); + pod::Thread::Tasks UF_API schedule( const uf::stl::string& name = "Aux", bool waits = true ); + void UF_API execute( pod::Thread::Tasks& tasks ); - void UF_API wait( pod::Thread& ); - - const uf::stl::string& UF_API name( const pod::Thread& ); - uint UF_API uid( const pod::Thread& ); - bool UF_API running( const pod::Thread& ); /* Acts on global threads */ typedef uf::stl::vector container_t; extern UF_API uf::thread::container_t threads; - void UF_API terminate(); @@ -80,57 +78,29 @@ namespace uf { pod::Thread& UF_API get( const uf::stl::string& ); bool UF_API isMain(); + + /* Acts on thread */ + void UF_API start( pod::Thread& ); + void UF_API quit( pod::Thread& ); + + void UF_API tick( pod::Thread& ); + + // schedules to worker thread + void UF_API queue( const pod::Thread::function_t& fun ); + void UF_API queue( const pod::Thread::container_t& funs ); + // schedules to target thread + void UF_API queue( pod::Thread& thread, const pod::Thread::function_t& fun ); + void UF_API add( pod::Thread& thread, const pod::Thread::function_t& fun ); + // schedules to named thread + inline void queue( const uf::stl::string& name, const pod::Thread::function_t& fun ) { return uf::thread::queue( uf::thread::get(name), fun ); } + inline void add( const uf::stl::string& name, const pod::Thread::function_t& fun ) { return uf::thread::add( uf::thread::get(name), fun ); } + + void UF_API process( pod::Thread& ); + + void UF_API wait( pod::Thread& ); + + const uf::stl::string& UF_API name( const pod::Thread& ); + uint UF_API uid( const pod::Thread& ); + bool UF_API running( const pod::Thread& ); } -} - -/* -namespace uf { - class UF_API Thread { - public: - typedef std::function function_t; - typedef std::queue queue_t; - typedef uf::stl::vector container_t; - - enum { - TEMP = 0, - CONSTANT = 1, - }; - protected: - uint m_uid; - uint m_mode; - bool m_running; - bool m_shouldLock; - bool m_terminateOnEmpty; - std::mutex m_mutex; - uf::stl::string m_name; - std::thread m_thread; - uf::Thread::queue_t m_temps; - uf::Thread::container_t m_consts; - public: - static uint fps; - static uint thread_count; - Thread( const uf::stl::string& = "", bool = true, uint = 0 ); - virtual ~Thread(); - - void start(); - virtual void tick(const std::function& = NULL); - void add( const uf::Thread::function_t&, uint = 0 ); - void process(); - void quit(); - - uf::stl::string toString() const; - const uf::stl::string& getName() const; - uint getUid() const; - const bool& isRunning() const; - }; - namespace thread { - typedef uf::stl::unordered_map container_t; - extern UF_API uf::thread::container_t threads; - - void UF_API add( uf::Thread* ); - uf::Thread& UF_API get( const uf::stl::string& ); - bool UF_API add( const uf::stl::string&, const uf::Thread::function_t&, uint = 0 ); - bool UF_API quit( const uf::stl::string& ); - }; -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index 120f765e..8c041483 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -50,7 +50,7 @@ uf::Asset uf::Asset::masterAssetLoader; bool uf::Asset::assertionLoad = true; void uf::Asset::processQueue() { - uf::thread::batchWorker( [&](){ + uf::thread::queue([&]{ mutex.lock(); auto jobs = std::move(this->getComponent>()); while ( !jobs.empty() ) { @@ -69,102 +69,6 @@ void uf::Asset::processQueue() { } mutex.unlock(); }); - -#if 0 - auto& jobs = this->getComponent>(); - mutex.lock(); - uf::stl::vector> tasks; - while ( !jobs.empty() ) { - auto job = jobs.front(); - jobs.pop(); - if ( job.uri == "" || job.callback == "" ) continue; - - tasks.emplace_back([=](){ - auto filename = job.type == "cache" ? this->cache(job.uri, job.hash, job.mime) : this->load(job.uri, job.hash, job.mime); - if ( filename == "" ) return; - ext::json::Value payload; - payload["filename"] = filename; - payload["hash"] = job.hash; - payload["mime"] = job.mime; - uf::hooks.call(job.callback, payload); - }); - } - uf::thread::batchWorkers( tasks, false ); - mutex.unlock(); -#elif 0 - auto& jobs = this->getComponent>(); - mutex.lock(); - while ( !jobs.empty() ) { - auto job = jobs.front(); - jobs.pop(); - uf::stl::string callback = job.callback; - uf::stl::string type = job.type; - uf::stl::string uri = job.uri; - uf::stl::string hash = job.hash; - uf::stl::string mime = job.mime; - if ( uri == "" || callback == "" ) { - continue; - } - uf::stl::string filename = type == "cache" ? this->cache(uri, hash, mime) : this->load(uri, hash, mime); - if ( callback != "" && filename != "" ) { - ext::json::Value payload; - payload["filename"] = filename; - payload["hash"] = hash; - payload["mime"] = mime; - uf::hooks.call(callback, payload); - } - } - mutex.unlock(); -#elif 0 - uf::thread::batchWorker( [&](){ - mutex.lock(); - auto jobs = std::move(this->getComponent>()); - while ( !jobs.empty() ) { - auto job = jobs.front(); - jobs.pop(); - uf::stl::string callback = job.callback; - uf::stl::string type = job.type; - uf::stl::string uri = job.uri; - uf::stl::string hash = job.hash; - uf::stl::string mime = job.mime; - if ( uri == "" || callback == "" ) { - continue; - } - uf::stl::string filename = type == "cache" ? this->cache(uri, hash, mime) : this->load(uri, hash, mime); - if ( callback != "" && filename != "" ) { - ext::json::Value payload; - payload["filename"] = filename; - payload["hash"] = hash; - payload["mime"] = mime; - uf::hooks.call(callback, payload); - } - } - mutex.unlock(); - }); -#elif 0 - uf::thread::batchWorker( [&](){ - mutex.lock(); - auto jobs = std::move(this->getComponent>()); - uf::stl::vector> tasks; - while ( !jobs.empty() ) { - auto job = jobs.front(); - jobs.pop(); - if ( job.uri == "" || job.callback == "" ) continue; - - tasks.emplace_back([=](){ - auto filename = job.type == "cache" ? this->cache(job.uri, job.hash, job.mime) : this->load(job.uri, job.hash, job.mime); - if ( filename == "" ) return; - ext::json::Value payload; - payload["filename"] = filename; - payload["hash"] = job.hash; - payload["mime"] = job.mime; - uf::hooks.call(job.callback, payload); - }); - } - uf::thread::batchWorkers( tasks, false ); - mutex.unlock(); - }); -#endif } void uf::Asset::cache( const uf::stl::string& callback, const uf::Asset::Payload& payload ) { mutex.lock(); diff --git a/engine/src/engine/behavior/behavior.cpp b/engine/src/engine/behavior/behavior.cpp index a925b685..a0e7015e 100644 --- a/engine/src/engine/behavior/behavior.cpp +++ b/engine/src/engine/behavior/behavior.cpp @@ -3,6 +3,7 @@ #include #include +#define UF_GRAPH_PRINT_TRACE 0 #define UF_BEHAVIORS_REMOVE_STL_FIND 1 uf::Behaviors::container_t& uf::Behaviors::getBehaviors() { return m_behaviors; } @@ -29,6 +30,8 @@ void uf::Behaviors::removeBehavior( const pod::Behavior& behavior ) { m_behaviors.erase(it); generateGraph(); } +uf::Behaviors::Graph& uf::Behaviors::getGraph() { return m_graph; } +const uf::Behaviors::Graph& uf::Behaviors::getGraph() const { return m_graph; } void uf::Behaviors::generateGraph() { m_graph.initialize.clear(); m_graph.tick.clear(); @@ -82,31 +85,33 @@ void uf::Behaviors::initialize() { void uf::Behaviors::tick() { uf::Object& self = *((uf::Object*) this); if ( !self.isValid() ) return; +// if ( !m_graph.tickMT.empty() ) uf::thread::queue(m_graph.tickMT); if ( m_graph.tick.empty() ) return; -// if ( !m_graph.tickMT.empty() ) uf::thread::batchWorkers(m_graph.tickMT, false); -/* - UF_TIMER_MULTITRACE_START("Starting " << self.getName() << ": " << self.getUid()); +#if UF_GRAPH_PRINT_TRACE + UF_TIMER_MULTITRACE_START("Starting tick " << self.getName() << ": " << self.getUid()); for ( auto& fun : m_graph.tick ) { fun(self); UF_TIMER_MULTITRACE(""); } - UF_TIMER_MULTITRACE_END("Finished " << self.getName() << ": " << self.getUid()) -*/ + UF_TIMER_MULTITRACE_END("Finished tick " << self.getName() << ": " << self.getUid()) +#else UF_BEHAVIOR_POLYFILL(tick) +#endif } void uf::Behaviors::render() { uf::Object& self = *((uf::Object*) this); if ( !self.isValid() ) return; if ( m_graph.render.empty() ) return; -/* - UF_TIMER_MULTITRACE_START("Starting " << self.getName() << ": " << self.getUid()); +#if UF_GRAPH_PRINT_TRACE + UF_TIMER_MULTITRACE_START("Starting render " << self.getName() << ": " << self.getUid()); for ( auto& fun : m_graph.render ) { fun(self); UF_TIMER_MULTITRACE(""); } - UF_TIMER_MULTITRACE_END("Finished " << self.getName() << ": " << self.getUid()) -*/ + UF_TIMER_MULTITRACE_END("Finished render " << self.getName() << ": " << self.getUid()) +#else UF_BEHAVIOR_POLYFILL(render) +#endif } void uf::Behaviors::destroy() { uf::Object& self = *((uf::Object*) this); diff --git a/engine/src/engine/entity/behavior.cpp b/engine/src/engine/entity/behavior.cpp index 645ea3c0..f96695e6 100644 --- a/engine/src/engine/entity/behavior.cpp +++ b/engine/src/engine/entity/behavior.cpp @@ -3,7 +3,7 @@ #include UF_BEHAVIOR_ENTITY_CPP_BEGIN(uf::Entity) -UF_BEHAVIOR_TRAITS_CPP(uf::EntityBehavior, ticks = true, renders = false, multithread = false) +UF_BEHAVIOR_TRAITS_CPP(uf::EntityBehavior, ticks = false, renders = false, multithread = false) #define this ((uf::Entity*) &self) void uf::EntityBehavior::initialize( uf::Object& self ) { if ( !this->isValid() ) this->setUid(); diff --git a/engine/src/engine/graph/decode.cpp b/engine/src/engine/graph/decode.cpp index 07ed3a0a..4f72ac26 100644 --- a/engine/src/engine/graph/decode.cpp +++ b/engine/src/engine/graph/decode.cpp @@ -306,9 +306,13 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize graph.name = filename; //serializer["name"].as(); graph.metadata = metadata; // serializer["metadata"]; - pod::Thread::container_t jobs; +#if UF_GRAPH_LOAD_MULTITHREAD + auto tasks = uf::thread::schedule("Async"); +#else + auto tasks = uf::thread::schedule("Main"); +#endif - jobs.emplace_back([&]{ + tasks.queue([&]{ // load images UF_DEBUG_TIMER_MULTITRACE("Reading instances..."); graph.instances.reserve( serializer["instances"].size() ); @@ -322,7 +326,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize DC_STATS(); #endif }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // load images UF_DEBUG_TIMER_MULTITRACE("Reading primitives..."); graph.primitives.reserve( serializer["primitives"].size() ); @@ -335,7 +339,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize DC_STATS(); #endif }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // load images UF_DEBUG_TIMER_MULTITRACE("Reading drawCommands..."); graph.drawCommands.reserve( serializer["drawCommands"].size() ); @@ -348,7 +352,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize DC_STATS(); #endif }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // load mesh information UF_DEBUG_TIMER_MULTITRACE("Reading meshes..."); graph.meshes.reserve( serializer["meshes"].size() ); @@ -361,7 +365,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize DC_STATS(); #endif }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // load images UF_DEBUG_TIMER_MULTITRACE("Reading images..."); graph.images.reserve( serializer["images"].size() ); @@ -388,7 +392,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize } #endif }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // load texture information UF_DEBUG_TIMER_MULTITRACE("Reading texture information..."); graph.textures.reserve( serializer["textures"].size() ); @@ -401,7 +405,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize DC_STATS(); #endif }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // load sampler information UF_DEBUG_TIMER_MULTITRACE("Reading sampler information..."); graph.samplers.reserve( serializer["samplers"].size() ); @@ -414,7 +418,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize DC_STATS(); #endif }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // load material information UF_DEBUG_TIMER_MULTITRACE("Reading material information..."); graph.materials.reserve( serializer["materials"].size() ); @@ -427,7 +431,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize DC_STATS(); #endif }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // load light information UF_DEBUG_TIMER_MULTITRACE("Reading lighting information..."); graph.lights.reserve( serializer["lights"].size() ); @@ -439,7 +443,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize DC_STATS(); #endif }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // load animation information UF_DEBUG_TIMER_MULTITRACE("Reading animation information..."); /*graph.storage*/uf::graph::storage.animations.map.reserve( serializer["animations"].size() ); @@ -458,7 +462,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize DC_STATS(); #endif }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // load skin information UF_DEBUG_TIMER_MULTITRACE("Reading skinning information..."); graph.skins.reserve( serializer["skins"].size() ); @@ -471,7 +475,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize DC_STATS(); #endif }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // load node information UF_DEBUG_TIMER_MULTITRACE("Reading nodes..."); graph.nodes.reserve( serializer["nodes"].size() ); @@ -483,11 +487,8 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize DC_STATS(); #endif }); -#if UF_GRAPH_LOAD_MULTITHREAD - if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs ); -#else - for ( auto& job : jobs ) job(); -#endif + + uf::thread::execute( tasks ); // re-reference all transform parents for ( auto& node : graph.nodes ) { diff --git a/engine/src/engine/graph/encode.cpp b/engine/src/engine/graph/encode.cpp index d6459fb9..5228450d 100644 --- a/engine/src/engine/graph/encode.cpp +++ b/engine/src/engine/graph/encode.cpp @@ -261,8 +261,12 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& */ #endif - pod::Thread::container_t jobs; - jobs.emplace_back([&]{ +#if UF_GRAPH_LOAD_MULTITHREAD + auto tasks = uf::thread::schedule("Async"); +#else + auto tasks = uf::thread::schedule("Main"); +#endif + tasks.queue([&]{ ext::json::reserve( serializer["instances"], graph.instances.size() ); for ( size_t i = 0; i < graph.instances.size(); ++i ) { auto& name = graph.instances[i]; @@ -272,7 +276,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& serializer["instances"].emplace_back( json ); } }); - jobs.emplace_back([&]{ + tasks.queue([&]{ ext::json::reserve( serializer["primitives"], graph.primitives.size() ); for ( size_t i = 0; i < graph.primitives.size(); ++i ) { auto& name = graph.primitives[i]; @@ -285,7 +289,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& } } }); - jobs.emplace_back([&]{ + tasks.queue([&]{ ext::json::reserve( serializer["drawCommands"], graph.drawCommands.size() ); for ( size_t i = 0; i < graph.drawCommands.size(); ++i ) { auto& name = graph.drawCommands[i]; @@ -298,7 +302,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& } } }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // store mesh information ext::json::reserve( serializer["meshes"], graph.meshes.size() ); if ( !settings.combined ) { @@ -330,7 +334,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& } }); #if 0 - jobs.emplace_back([&]{ + tasks.queue([&]{ if ( uf::graphs::storage.atlases[graph.atlas].generated() ) { auto atlasName = filename + "/" + "atlas"; auto& atlas = /*graph.storage*/uf::graph::storage.atlases[atlasName]; @@ -344,7 +348,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& } }); #endif - jobs.emplace_back([&]{ + tasks.queue([&]{ ext::json::reserve( serializer["images"], graph.images.size() ); if ( !settings.combined ) { for ( size_t i = 0; i < graph.images.size(); ++i ) { @@ -367,7 +371,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& } } }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // store texture information ext::json::reserve( serializer["textures"], graph.textures.size() ); for ( auto& name : graph.textures ) { @@ -377,7 +381,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& serializer["textures"].emplace_back(json); } }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // store sampler information ext::json::reserve( serializer["samplers"], graph.samplers.size() ); for ( auto& name : graph.samplers ) { @@ -387,7 +391,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& serializer["samplers"].emplace_back(json); } }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // store material information ext::json::reserve( serializer["materials"], graph.materials.size() ); for ( auto& name : graph.materials ) { @@ -397,7 +401,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& serializer["materials"].emplace_back(json); } }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // store light information ext::json::reserve( serializer["lights"], graph.lights.size() ); for ( auto pair : graph.lights ) { @@ -408,7 +412,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& serializer["lights"].emplace_back(json); } }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // store animation information ext::json::reserve( serializer["animations"], graph.animations.size() ); if ( !settings.combined ) { @@ -426,7 +430,7 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& } } }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // store skin information ext::json::reserve( serializer["skins"], graph.skins.size() ); for ( auto& name : graph.skins ) { @@ -434,17 +438,14 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string& serializer["skins"].emplace_back( encode(skin, settings, graph) ); } }); - jobs.emplace_back([&]{ + tasks.queue([&]{ // store node information ext::json::reserve( serializer["nodes"], graph.nodes.size() ); for ( auto& node : graph.nodes ) serializer["nodes"].emplace_back( encode(node, settings, graph) ); serializer["root"] = encode(graph.root, settings, graph); }); -#if UF_GRAPH_LOAD_MULTITHREAD - if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs ); -#else - for ( auto& job : jobs ) job(); -#endif + + uf::thread::execute( tasks ); if ( !settings.combined ) target = directory + "/graph.json"; serializer.writeToFile( target ); diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index eb730ea8..e394917d 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -87,18 +87,10 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity ) { // for ( auto& i : graph.images ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[i] ); // for ( auto pair : uf::graph::storage.texture2Ds.map ) graphic.material.textures.emplace_back().aliasTexture( pair.second ); - #if 1 for ( auto& key : uf::graph::storage.texture2Ds.keys ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[key] ); - #else - uf::stl::map texture2DOrderedMap; // texture2DOrderedMap.reserve( uf::graph::storage.texture2Ds.keys.size() ); - for ( auto key : uf::graph::storage.texture2Ds.keys ) { - texture2DOrderedMap[uf::graph::storage.texture2Ds.indices[key]] = key; - } - for ( auto pair : texture2DOrderedMap ) graphic.material.textures.emplace_back().aliasTexture( uf::graph::storage.texture2Ds.map[pair.second] ); - #endif // bind scene's voxel texture - if ( uf::renderer::settings::experimental::vxgi ) { + if ( uf::renderer::settings::pipelines::vxgi ) { auto& scene = uf::scene::getCurrentScene(); auto& sceneTextures = scene.getComponent(); for ( auto& t : sceneTextures.voxels.id ) graphic.material.textures.emplace_back().aliasTexture(t); @@ -129,7 +121,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity ) { uf::stl::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as(""); uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as("/graph/base.frag.spv"); { std::pair settings[] = { - { uf::renderer::settings::experimental::deferredSampling, "deferredSampling.frag" }, + { uf::renderer::settings::invariant::deferredSampling, "deferredSampling.frag" }, }; FOR_ARRAY(settings) if ( settings[i].first ) fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", settings[i].second ); fragmentShaderFilename = entity.resolveURI( fragmentShaderFilename, root ); @@ -190,7 +182,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity ) { } #if UF_USE_VULKAN // culling pipeline - if ( uf::renderer::settings::experimental::culling ) { + if ( uf::renderer::settings::pipelines::culling ) { uf::renderer::Buffer* indirect = NULL; for ( auto& buffer : graphic.buffers ) if ( !indirect && buffer.usage & uf::renderer::enums::Buffer::INDIRECT ) indirect = &buffer; UF_ASSERT( indirect ); @@ -248,7 +240,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity ) { } } // vxgi pipeline - if ( uf::renderer::settings::experimental::vxgi ) { + if ( uf::renderer::settings::pipelines::vxgi ) { uf::stl::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as("/graph/base.vert.spv"); uf::stl::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as("/graph/voxelize.geom.spv"); uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as("/graph/voxelize.frag.spv"); @@ -359,8 +351,8 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity ) { } #endif - uf::instantiator::bind( "GraphBehavior", entity ); - uf::instantiator::unbind( "RenderBehavior", entity ); + // uf::instantiator::bind( "GraphBehavior", entity ); + // uf::instantiator::unbind( "RenderBehavior", entity ); } void uf::graph::process( pod::Graph& graph ) { @@ -742,9 +734,12 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) { if ( graph.lights.count(node.name) > 0 ) { auto& l = graph.lights[node.name]; - #if UF_ENV_DREAMCAST + #if UF_USE_OPENGL + metadata.system.ignoreGraph = true; + #else metadata.system.ignoreGraph = graph.metadata["debug"]["static"].as(); #endif + uf::Serializer metadataLight; metadataLight["radius"][0] = 0.001; metadataLight["radius"][1] = l.range; // l.range <= 0.001f ? graph.metadata["lights"]["range cap"].as() : l.range; @@ -843,7 +838,7 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) } } if ( (graph.metadata["flags"]["SEPARATE"].as()) && graph.metadata["flags"]["RENDER"].as() ) { - uf::instantiator::bind("RenderBehavior", entity); + // uf::instantiator::bind("RenderBehavior", entity); auto& graphic = entity.getComponent(); graphic.initialize(); @@ -948,7 +943,7 @@ void uf::graph::initialize( pod::Graph& graph ) { initializeShaders( graph, entity->as() ); uf::instantiator::bind( "GraphBehavior", *entity ); - uf::instantiator::unbind( "RenderBehavior", *entity ); + // uf::instantiator::unbind( "RenderBehavior", *entity ); if ( entity->getUid() == 0 ) entity->initialize(); //UF_MSG_DEBUG( "Initialized " << uf::string::toString( entity->as() ) ); */ @@ -1145,10 +1140,32 @@ void uf::graph::tick() { ::newGraphAdded = false; } } -void uf::graph::render() { +void uf::graph::render() { auto& scene = uf::scene::getCurrentScene(); auto& controller = scene.getController(); auto& camera = controller.getComponent(); + +#if 0 + { + static uf::Entity* lastController = NULL; + if ( lastController == &controller ) return; + lastController = &controller; + + uf::graph::storage.buffers.camera.update( (const void*) &camera.data().viewport, sizeof(pod::Camera::Viewports) ); + } +#endif + auto* renderMode = uf::renderer::getCurrentRenderMode(); + if ( !renderMode ) return; + +#if UF_USE_VULKAN + for ( auto& buffer : renderMode->buffers ) { + if ( !(buffer.usage & uf::renderer::enums::Buffer::UNIFORM) ) continue; + if ( buffer.allocationInfo.size != sizeof(pod::Camera::Viewports) ) continue; + buffer.update( (const void*) &camera.data().viewport, sizeof(pod::Camera::Viewports) ); + return; + } +#endif + uf::graph::storage.buffers.camera.update( (const void*) &camera.data().viewport, sizeof(pod::Camera::Viewports) ); } void uf::graph::destroy() { diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index ea919054..bb67ac1a 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -184,6 +184,10 @@ void uf::ObjectBehavior::tick( uf::Object& self ) { auto& audio = this->getComponent(); audio.update(); } + if ( this->hasComponent() ) { + auto& graph = this->getComponent(); + uf::graph::update( graph ); + } auto& metadata = this->getComponent(); #if UF_ENTITY_METADATA_USE_JSON diff --git a/engine/src/engine/object/behaviors/graph.cpp b/engine/src/engine/object/behaviors/graph.cpp index bd534c6e..3c0d6f99 100644 --- a/engine/src/engine/object/behaviors/graph.cpp +++ b/engine/src/engine/object/behaviors/graph.cpp @@ -14,7 +14,7 @@ #include UF_BEHAVIOR_REGISTER_CPP(uf::GraphBehavior) -UF_BEHAVIOR_TRAITS_CPP(uf::GraphBehavior, ticks = true, renders = true, multithread = false) +UF_BEHAVIOR_TRAITS_CPP(uf::GraphBehavior, ticks = false, renders = false, multithread = false) #define this (&self) void uf::GraphBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); @@ -72,11 +72,11 @@ void uf::GraphBehavior::initialize( uf::Object& self ) { } void uf::GraphBehavior::destroy( uf::Object& self ) {} void uf::GraphBehavior::tick( uf::Object& self ) { +#if 0 if ( this->hasComponent() ) { auto& graph = this->getComponent(); uf::graph::update( graph ); } -#if 0 /* Update animations */ if ( this->hasComponent() ) { auto& graph = this->getComponent(); // if ( graph.metadata["flags"]["SKINNED"].as() ) uf::graph::update( graph ); diff --git a/engine/src/engine/object/behaviors/render.cpp b/engine/src/engine/object/behaviors/render.cpp index 71bfb4b9..1be1f05f 100644 --- a/engine/src/engine/object/behaviors/render.cpp +++ b/engine/src/engine/object/behaviors/render.cpp @@ -14,7 +14,7 @@ #define UF_UNIFORMS_UPDATE_WITH_JSON 0 UF_BEHAVIOR_REGISTER_CPP(uf::RenderBehavior) -UF_BEHAVIOR_TRAITS_CPP(uf::RenderBehavior, ticks = true, renders = true, multithread = false) +UF_BEHAVIOR_TRAITS_CPP(uf::RenderBehavior, ticks = false, renders = false, multithread = false) #define this (&self) void uf::RenderBehavior::initialize( uf::Object& self ) {} void uf::RenderBehavior::tick( uf::Object& self ) { diff --git a/engine/src/engine/scene/scene.cpp b/engine/src/engine/scene/scene.cpp index fc249953..4a2259fb 100644 --- a/engine/src/engine/scene/scene.cpp +++ b/engine/src/engine/scene/scene.cpp @@ -17,14 +17,15 @@ namespace { uf::SceneBehavior::Metadata metadata; } #endif + uf::Entity& uf::Scene::getController() { #if !UF_SCENE_GLOBAL_GRAPH auto& metadata = this->getComponent(); #endif -#if 1 + auto currentRenderMode = uf::renderer::getCurrentRenderMode(); uf::Entity* controller = NULL; - if ( uf::renderer::currentRenderMode ) { - auto& renderMode = *uf::renderer::currentRenderMode; + if ( currentRenderMode ) { + auto& renderMode = *currentRenderMode; auto& name = renderMode.getName(); if ( metadata.cache.count(name) > 0 ) { controller = metadata.cache[name]; @@ -43,27 +44,6 @@ uf::Entity& uf::Scene::getController() { } controller = this->findByName("Player"); return *(metadata.cache[""] = controller ? controller : this); -#else - if ( uf::renderer::currentRenderMode ) { - auto& renderMode = *uf::renderer::currentRenderMode; - - if ( metadata.cached.renderMode == &renderMode && metadata.cached.controller && metadata.cached.controller->isValid() ) { - return *metadata.cached.controller; - } - metadata.cached.controller = NULL; - metadata.cached.renderMode = &renderMode; - auto split = uf::string::split( renderMode.getName(), ":" ); - if ( split.front() == "RT" ) { - uint64_t uid = std::stoi( split.back() ); - uf::Entity* ent = this->findByUid( uid ); - if ( ent ) return *(metadata.cached.controller = ent); - } - } - if ( metadata.cached.controller && metadata.cached.controller->isValid() ) return *metadata.cached.controller; - metadata.cached.controller = this->findByName("Player"); - return metadata.cached.controller ? *metadata.cached.controller : *this; - // return this; -#endif } const uf::Entity& uf::Scene::getController() const { uf::Scene& scene = *const_cast(this); @@ -79,6 +59,7 @@ void uf::Scene::invalidateGraph() { metadata.invalidationQueued = true; #if 1 metadata.cache.clear(); + metadata.tasks.clear(); #else metadata.cached.renderMode = NULL; metadata.cached.controller = NULL; @@ -91,12 +72,18 @@ const uf::stl::vector& uf::Scene::getGraph() { if ( metadata.invalidationQueued ) { metadata.invalidationQueued = false; metadata.graph.clear(); + metadata.tasks.clear(); } if ( !metadata.graph.empty() ) return metadata.graph; this->process([&]( uf::Entity* entity ) { if ( !entity->hasComponent() ) return; auto& eMetadata = entity->getComponent(); - if ( !eMetadata.system.ignoreGraph ) metadata.graph.emplace_back(entity); + if ( !eMetadata.system.ignoreGraph ) { + metadata.graph.emplace_back(entity); + + auto& behaviorGraph = entity->getGraph(); + for ( auto& fun : behaviorGraph.tickMT ) metadata.tasks.queue(fun); + } }); uf::renderer::states::rebuild = true; return metadata.graph; @@ -114,7 +101,7 @@ uf::Scene& uf::scene::loadScene( const uf::stl::string& name, const uf::stl::str const uf::stl::string filename = _filename != "" ? _filename : ("/" + uf::string::lowercase(name) + "/scene.json"); scene->load(filename); - if ( uf::renderer::settings::experimental::vxgi ) { + if ( uf::renderer::settings::pipelines::vxgi ) { uf::instantiator::bind( "VoxelizerBehavior", *scene ); } scene->initialize(); @@ -124,7 +111,7 @@ uf::Scene& uf::scene::loadScene( const uf::stl::string& name, const uf::Serializ uf::Scene* scene = uf::instantiator::objects->has( name ) ? (uf::Scene*) &uf::instantiator::instantiate( name ) : new uf::Scene; uf::scene::scenes.emplace_back( scene ); if ( data != "" ) scene->load(data); - if ( uf::renderer::settings::experimental::vxgi ) { + if ( uf::renderer::settings::pipelines::vxgi ) { uf::instantiator::bind( "VoxelizerBehavior", *scene ); } scene->initialize(); @@ -149,8 +136,21 @@ void uf::scene::invalidateGraphs() { void uf::scene::tick() { if ( scenes.empty() ) return; - auto graph = uf::scene::getCurrentScene().getGraph(true); + auto& scene = uf::scene::getCurrentScene(); +#if !UF_SCENE_GLOBAL_GRAPH + auto& metadata = scene.getComponent(); +#endif + auto graph = scene.getGraph(true); +#if 1 for ( auto entity : graph ) entity->tick(); + auto& tasks = metadata.tasks; +#else + pod::Thread::Tasks tasks = metadata.tasks; + tasks.queue([&]{ + for ( auto entity : graph ) entity->tick(); + }); +#endif + uf::thread::execute( tasks ); } void uf::scene::render() { if ( scenes.empty() ) return; diff --git a/engine/src/ext/opengl/commands.cpp b/engine/src/ext/opengl/commands.cpp index 137253cc..73806e8f 100644 --- a/engine/src/ext/opengl/commands.cpp +++ b/engine/src/ext/opengl/commands.cpp @@ -102,10 +102,12 @@ void ext::opengl::CommandBuffer::submit() { switch ( header->type ) { case ext::opengl::enums::Command::CLEAR: { InfoClear* info = (InfoClear*) header; + /* GL_ERROR_CHECK(glClearColor(info->color[0], info->color[1], info->color[2], info->color[3])); GL_ERROR_CHECK(glClearDepth(info->depth)); GL_ERROR_CHECK(glClear(info->bits)); - // GL_ERROR_CHECK(glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &info->color[0])); + GL_ERROR_CHECK(glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &info->color[0])); + */ //UF_TIMER_MULTITRACE("Command::CLEAR"); } break; case ext::opengl::enums::Command::VIEWPORT: { @@ -249,7 +251,7 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: if ( drawInfo.attributes.indirect.pointer && drawInfo.attributes.indirect.length == sizeof(pod::DrawCommand) ) { pod::DrawCommand& drawCommand = *(pod::DrawCommand*) drawInfo.attributes.indirect.pointer; - if ( ext::opengl::settings::experimental::culling && drawInfo.attributes.instance.pointer && drawInfo.attributes.instance.length == sizeof(pod::Instance) ) { + if ( ext::opengl::settings::pipelines::culling && drawInfo.attributes.instance.pointer && drawInfo.attributes.instance.length == sizeof(pod::Instance) ) { pod::Instance& instance = *(pod::Instance*) drawInfo.attributes.instance.pointer; pod::Matrix4f mat = (*drawInfo.matrices.projection) * (*drawInfo.matrices.view) * (*drawInfo.matrices.model); @@ -266,6 +268,7 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: GL_ERROR_CHECK(glMatrixMode(GL_PROJECTION)); GL_ERROR_CHECK(glLoadMatrixf( &projection[0] )); +#if 1 if ( drawInfo.descriptor.cullMode == GL_NONE ) { GL_ERROR_CHECK(glDisable(GL_CULL_FACE)); } else { @@ -279,6 +282,7 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: GL_ERROR_CHECK(glDisable(GL_DEPTH_TEST)); } GL_ERROR_CHECK(glDepthMask(drawInfo.descriptor.depth.write ? GL_TRUE : GL_FALSE)); +#endif // CPU-buffer based command dispatching if ( drawInfo.attributes.normal.pointer ) GL_ERROR_CHECK(glEnableClientState(GL_NORMAL_ARRAY)); @@ -294,10 +298,7 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: GLboolean blending = glIsEnabled(GL_BLEND); - if ( drawInfo.textures.primary.image && drawInfo.attributes.uv.pointer ) { - // static GLuint previous = 0; - // if ( previous != drawInfo.textures.primary.image ) previous = drawInfo.textures.primary.image; - + if ( drawInfo.textures.primary.image && drawInfo.attributes.uv.pointer ) { GL_ERROR_CHECK(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); GL_ERROR_CHECK(glClientActiveTexture(GL_TEXTURE0)); @@ -306,43 +307,41 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: GL_ERROR_CHECK(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); GL_ERROR_CHECK(glBindTexture(drawInfo.textures.primary.viewType, drawInfo.textures.primary.image)); GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.uv.stride, (drawInfo.attributes.uv.pointer + drawInfo.attributes.uv.stride * drawInfo.descriptor.inputs.vertex.first))); - - if ( drawInfo.textures.secondary.image && drawInfo.attributes.st.pointer ) { + + if ( !(drawInfo.textures.secondary.image && drawInfo.attributes.st.pointer) ) { + GL_ERROR_CHECK(glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); + } else { GL_ERROR_CHECK(glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); - // static GLuint previous = 0; - // if ( previous != drawInfo.textures.secondary.image ) previous = drawInfo.textures.secondary.image; - GL_ERROR_CHECK(glClientActiveTexture(GL_TEXTURE1)); GL_ERROR_CHECK(glActiveTexture(GL_TEXTURE1)); GL_ERROR_CHECK(glEnable(drawInfo.textures.secondary.viewType)); GL_ERROR_CHECK(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); GL_ERROR_CHECK(glBindTexture(drawInfo.textures.secondary.viewType, drawInfo.textures.secondary.image)); GL_ERROR_CHECK(glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); - #if UF_ENV_DREAMCAST - if ( blending ) GL_ERROR_CHECK(glDisable(GL_BLEND)); - #endif + GL_ERROR_CHECK(glTexCoordPointer(2, GL_FLOAT, drawInfo.attributes.st.stride, (drawInfo.attributes.st.pointer + drawInfo.attributes.st.stride * drawInfo.descriptor.inputs.vertex.first))); } } - if ( drawInfo.attributes.normal.pointer ) GL_ERROR_CHECK(glNormalPointer(GL_FLOAT, drawInfo.attributes.normal.stride, (drawInfo.attributes.normal.pointer + drawInfo.attributes.normal.stride * drawInfo.descriptor.inputs.vertex.first))); - if ( drawInfo.attributes.color.pointer ) GL_ERROR_CHECK(glColorPointer(4, GL_UNSIGNED_BYTE, drawInfo.attributes.color.stride, (drawInfo.attributes.color.pointer + drawInfo.attributes.color.stride * drawInfo.descriptor.inputs.vertex.first))); + if ( drawInfo.attributes.color.pointer ) { + GLenum format = GL_UNSIGNED_BYTE; + switch ( drawInfo.attributes.color.descriptor.size / drawInfo.attributes.color.descriptor.components ) { + case sizeof(uint8_t): format = GL_UNSIGNED_BYTE; break; + case sizeof(float): format = GL_FLOAT; break; + } + GL_ERROR_CHECK(glColorPointer(drawInfo.attributes.color.descriptor.components, format, drawInfo.attributes.color.stride, (drawInfo.attributes.color.pointer + drawInfo.attributes.color.stride * drawInfo.descriptor.inputs.vertex.first))); + } GL_ERROR_CHECK(glVertexPointer(3, GL_FLOAT, drawInfo.attributes.position.stride, (drawInfo.attributes.position.pointer + drawInfo.attributes.position.stride * drawInfo.descriptor.inputs.vertex.first))); - GL_ERROR_CHECK(glDrawElements(GL_TRIANGLES, drawInfo.descriptor.inputs.index.count, indicesType, (drawInfo.attributes.index.pointer + drawInfo.attributes.index.stride * drawInfo.descriptor.inputs.index.first))); - - if ( drawInfo.textures.secondary.image ) { - #if UF_ENV_DREAMCAST - if ( blending ) GL_ERROR_CHECK(glEnable(GL_BLEND)); - #endif + + if ( drawInfo.descriptor.inputs.index.count ) { + GL_ERROR_CHECK(glDrawElements(GL_TRIANGLES, drawInfo.descriptor.inputs.index.count, indicesType, (drawInfo.attributes.index.pointer + drawInfo.attributes.index.stride * drawInfo.descriptor.inputs.index.first))); + } else { + GL_ERROR_CHECK(glDrawArrays(GL_TRIANGLES, drawInfo.descriptor.inputs.vertex.first, drawInfo.descriptor.inputs.vertex.count)); } -#if 0 if ( drawInfo.textures.secondary.image ) { - #if UF_ENV_DREAMCAST - GL_ERROR_CHECK(glEnable(GL_BLEND)); - #endif GL_ERROR_CHECK(glClientActiveTexture(GL_TEXTURE1)); GL_ERROR_CHECK(glActiveTexture(GL_TEXTURE1)); GL_ERROR_CHECK(glBindTexture(drawInfo.textures.secondary.viewType, 0)); @@ -354,7 +353,6 @@ void ext::opengl::CommandBuffer::drawIndexed( const ext::opengl::CommandBuffer:: GL_ERROR_CHECK(glBindTexture(drawInfo.textures.primary.viewType, 0)); GL_ERROR_CHECK(glDisable(drawInfo.textures.primary.viewType)); } -#endif if ( drawInfo.attributes.normal.pointer ) GL_ERROR_CHECK(glDisableClientState(GL_NORMAL_ARRAY)); if ( drawInfo.attributes.color.pointer ) GL_ERROR_CHECK(glDisableClientState(GL_COLOR_ARRAY)); diff --git a/engine/src/ext/opengl/graphic.cpp b/engine/src/ext/opengl/graphic.cpp index 3cebe44f..8488d9ef 100644 --- a/engine/src/ext/opengl/graphic.cpp +++ b/engine/src/ext/opengl/graphic.cpp @@ -365,16 +365,18 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe CommandBuffer::InfoDraw drawCommandInfoBase = {}; drawCommandInfoBase.type = ext::opengl::enums::Command::DRAW; drawCommandInfoBase.descriptor = descriptor; - drawCommandInfoBase.attributes.index = descriptor.inputs.index.attributes.front(); + if ( descriptor.inputs.index.count ) { + drawCommandInfoBase.attributes.index = descriptor.inputs.index.attributes.front(); + } + for ( uf::Mesh::Attribute attribute : descriptor.inputs.vertex.attributes ) { if ( attribute.descriptor.name == "position" ) drawCommandInfoBase.attributes.position = attribute; else if ( attribute.descriptor.name == "uv" ) drawCommandInfoBase.attributes.uv = attribute; else if ( attribute.descriptor.name == "st" ) drawCommandInfoBase.attributes.st = attribute; - else if ( attribute.descriptor.name == "normal" ) drawCommandInfoBase.attributes.normal = attribute; + // else if ( attribute.descriptor.name == "normal" ) drawCommandInfoBase.attributes.normal = attribute; else if ( attribute.descriptor.name == "color" ) drawCommandInfoBase.attributes.color = attribute; } - drawCommandInfoBase.attributes.index = descriptor.inputs.index.attributes.front(); if ( uniformBufferSize == sizeof(pod::Camera::Viewports) ) { drawCommandInfoBase.matrices.view = &viewports->matrices[0].view; drawCommandInfoBase.matrices.projection = &viewports->matrices[0].projection; @@ -400,7 +402,7 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe pod::Material* materials = (pod::Material*) device->getBuffer( materialBuffer ); pod::Texture* textures = (pod::Texture*) device->getBuffer( textureBuffer ); - const bool optimize = false; + // const bool optimize = false; uf::stl::unordered_map> pool; for ( auto i = 0; i < descriptor.inputs.indirect.count; ++i ) { auto& drawCommand = drawCommands[i]; @@ -410,8 +412,8 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe auto& material = materials[materialID]; auto textureID = material.indexAlbedo; auto& infos = pool[textureID]; - CommandBuffer::InfoDraw& drawCommandInfo = infos.emplace_back( drawCommandInfoBase ); + // CommandBuffer::InfoDraw drawCommandInfo = drawCommandInfoBase; drawCommandInfo.descriptor.inputs.index.first = drawCommand.indexID; drawCommandInfo.descriptor.inputs.index.count = drawCommand.indices; @@ -419,7 +421,6 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe drawCommandInfo.descriptor.inputs.vertex.first = drawCommand.vertexID; drawCommandInfo.descriptor.inputs.vertex.count = drawCommand.vertices; - drawCommandInfo.attributes.instance.pointer = &instance; drawCommandInfo.attributes.instance.length = sizeof(instance); @@ -440,14 +441,17 @@ void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, const GraphicDe commandBuffer.record(drawCommandInfo); } } else { - /* - UF_MSG_DEBUG( viewports << " " << uniformBuffers.size() ); - if ( drawCommandInfoBase.matrices.model ) UF_MSG_DEBUG( "model: " << drawCommandInfoBase.matrices.model << " " << uf::matrix::toString( *drawCommandInfoBase.matrices.model ) ); - if ( drawCommandInfoBase.matrices.view ) UF_MSG_DEBUG( "view: " << drawCommandInfoBase.matrices.view << " " << uf::matrix::toString( *drawCommandInfoBase.matrices.view ) ); - if ( drawCommandInfoBase.matrices.projection ) UF_MSG_DEBUG( "projection: " << drawCommandInfoBase.matrices.projection << " " << uf::matrix::toString( *drawCommandInfoBase.matrices.projection ) ); - */ + CommandBuffer::InfoDraw drawCommandInfo = drawCommandInfoBase; - commandBuffer.record(drawCommandInfoBase); + drawCommandInfoBase.matrices.model = NULL; + drawCommandInfoBase.matrices.view = NULL; + drawCommandInfoBase.matrices.projection = NULL; + + if ( !material.textures.empty() ) { + drawCommandInfo.textures.primary = material.textures.front().descriptor; + } + + commandBuffer.record(drawCommandInfo); } } void ext::opengl::Graphic::destroy() { @@ -485,7 +489,7 @@ ext::opengl::GraphicDescriptor::hash_t ext::opengl::GraphicDescriptor::hash() co size_t hash{}; hash += std::hash{}(subpass); - if ( settings::experimental::individualPipelines ) + if ( settings::invariant::individualPipelines ) hash += std::hash{}(renderMode); hash += std::hash{}(renderTarget); diff --git a/engine/src/ext/opengl/opengl.cpp b/engine/src/ext/opengl/opengl.cpp index b33769b1..45ad4267 100644 --- a/engine/src/ext/opengl/opengl.cpp +++ b/engine/src/ext/opengl/opengl.cpp @@ -27,21 +27,27 @@ uf::stl::vector ext::opengl::settings::requestedInstanceExtensi ext::opengl::enums::Filter::type_t ext::opengl::settings::swapchainUpscaleFilter = ext::opengl::enums::Filter::LINEAR; +// these go hand in hand for the above +bool ext::opengl::settings::experimental::dedicatedThread = false; bool ext::opengl::settings::experimental::rebuildOnTickBegin = false; -bool ext::opengl::settings::experimental::waitOnRenderEnd = false; -bool ext::opengl::settings::experimental::individualPipelines = true; -bool ext::opengl::settings::experimental::multithreadedCommandRecording = true; -bool ext::opengl::settings::experimental::multithreadedCommandRendering = false; -uf::stl::string ext::opengl::settings::experimental::deferredMode = ""; -bool ext::opengl::settings::experimental::deferredReconstructPosition = false; -bool ext::opengl::settings::experimental::deferredAliasOutputToSwapchain = true; -bool ext::opengl::settings::experimental::multiview = true; -bool ext::opengl::settings::experimental::vsync = true; -bool ext::opengl::settings::experimental::hdr = true; -bool ext::opengl::settings::experimental::vxgi = true; -bool ext::opengl::settings::experimental::deferredSampling = false; -bool ext::opengl::settings::experimental::culling = false; -bool ext::opengl::settings::experimental::bloom = false; + +// not so experimental +bool ext::opengl::settings::invariant::waitOnRenderEnd = false; +bool ext::opengl::settings::invariant::individualPipelines = true; +bool ext::opengl::settings::invariant::multithreadedRecording = true; + +uf::stl::string ext::opengl::settings::invariant::deferredMode = ""; +bool ext::opengl::settings::invariant::deferredReconstructPosition = false; +bool ext::opengl::settings::invariant::deferredAliasOutputToSwapchain = true; +bool ext::opengl::settings::invariant::deferredSampling = true; + +bool ext::opengl::settings::invariant::multiview = true; +// pipelines +bool ext::opengl::settings::pipelines::vsync = true; +bool ext::opengl::settings::pipelines::hdr = true; +bool ext::opengl::settings::pipelines::vxgi = true; +bool ext::opengl::settings::pipelines::culling = false; +bool ext::opengl::settings::pipelines::bloom = false; GLhandle(VkColorSpaceKHR) ext::opengl::settings::formats::colorSpace; ext::opengl::enums::Format::type_t ext::opengl::settings::formats::color = ext::opengl::enums::Format::R8G8B8A8_UNORM; @@ -56,9 +62,9 @@ std::mutex ext::opengl::immediateModeMutex; bool ext::opengl::states::resized = false; bool ext::opengl::states::rebuild = false; uint32_t ext::opengl::states::currentBuffer = 0; +uf::ThreadUnique ext::opengl::currentRenderMode; + -uf::stl::vector ext::opengl::scenes; -ext::opengl::RenderMode* ext::opengl::currentRenderMode = NULL; uf::stl::vector ext::opengl::renderModes = { new ext::opengl::BaseRenderMode, }; @@ -131,6 +137,18 @@ void UF_API ext::opengl::removeRenderMode( ext::opengl::RenderMode* mode, bool f if ( free ) delete mode; ext::opengl::states::rebuild = true; } +ext::opengl::RenderMode* UF_API ext::opengl::getCurrentRenderMode() { + return getCurrentRenderMode( std::this_thread::get_id() ); +} +ext::opengl::RenderMode* UF_API ext::opengl::getCurrentRenderMode( std::thread::id id ) { + return ext::opengl::currentRenderMode.get(id); +} +void UF_API ext::opengl::setCurrentRenderMode( ext::opengl::RenderMode* renderMode ) { + return setCurrentRenderMode( renderMode, std::this_thread::get_id() ); +} +void UF_API ext::opengl::setCurrentRenderMode( ext::opengl::RenderMode* renderMode, std::thread::id id ) { + ext::opengl::currentRenderMode.get(id) = renderMode; +} void UF_API ext::opengl::initialize() { device.initialize(); @@ -166,17 +184,18 @@ void UF_API ext::opengl::initialize() { } uf::graph::initialize(); - - pod::Thread::container_t jobs; - for ( auto& renderMode : renderModes ) { - if ( !renderMode ) continue; - if ( settings::experimental::individualPipelines ) renderMode->bindPipelines(); - if ( settings::experimental::multithreadedCommandRecording ) { - jobs.emplace_back([&](){renderMode->createCommandBuffers();}); - } else renderMode->createCommandBuffers(); + + auto tasks = uf::thread::schedule(settings::invariant::multithreadedRecording ? "Aux" : "Main"); + for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; + tasks.queue([&]{ + if ( settings::invariant::individualPipelines ) renderMode->bindPipelines(); + renderMode->createCommandBuffers(); + }); } - if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); + uf::thread::execute( tasks ); + // bind shaders +#if 0 /* { ext::opengl::Shader::bind( uf::io::root + "shaders/graph/cull.comp.spv", []( const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic ) { @@ -186,7 +205,6 @@ void UF_API ext::opengl::initialize() { }); } */ -#if 0 { ext::opengl::Shader::bind( uf::io::root + "shaders/graph/instanced.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) { if ( !userdata ) return; @@ -338,16 +356,16 @@ void UF_API ext::opengl::tick(){ } renderMode->tick(); } - pod::Thread::container_t jobs; - for ( auto& renderMode : renderModes ) { - if ( !renderMode ) continue; - if ( ext::opengl::states::rebuild || renderMode->rebuild ) { - if ( settings::experimental::individualPipelines ) renderMode->bindPipelines(); - if ( settings::experimental::multithreadedCommandRecording ) jobs.emplace_back([&](){renderMode->createCommandBuffers();}); - else renderMode->createCommandBuffers(); - } + + auto tasks = uf::thread::schedule(settings::invariant::multithreadedRecording ? "Aux" : "Main"); + for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; + if ( ext::opengl::states::rebuild || renderMode->rebuild ) tasks.queue([&]{ + if ( settings::invariant::individualPipelines ) renderMode->bindPipelines(); + renderMode->createCommandBuffers(); + }); } - if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); + uf::thread::execute( tasks ); + /* ext::opengl::device.activateContext(); ext::opengl::device.commandBuffer.end(); @@ -362,12 +380,7 @@ void UF_API ext::opengl::tick(){ void UF_API ext::opengl::render(){ ext::opengl::mutex.lock(); #if !UF_ENV_DREAMCAST -#if 0 - if ( hasRenderMode("Gui", true) ) { - RenderMode& primary = getRenderMode("Gui", true); - auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); - if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() ); - } +#if 1 if ( hasRenderMode("", true) ) { RenderMode& primary = getRenderMode("", true); auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); @@ -377,19 +390,66 @@ void UF_API ext::opengl::render(){ auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() ); } + if ( hasRenderMode("Gui", true) ) { + RenderMode& primary = getRenderMode("Gui", true); + auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); + if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() ); + } #endif ext::opengl::device.activateContext(); #endif + + { + auto& scene = uf::scene::getCurrentScene(); + auto& sceneMetadata = scene.getComponent(); + + CommandBuffer::InfoClear clearCommandInfo = {}; + clearCommandInfo.type = enums::Command::CLEAR; + clearCommandInfo.color = {1.0f, 1.0f, 1.0f, 1.0f}; + clearCommandInfo.bits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; + clearCommandInfo.depth = uf::matrix::reverseInfiniteProjection ? 0.0f : 1.0f; + + #if 1 + if ( !ext::json::isNull( sceneMetadata["system"]["renderer"]["clear values"][0] ) ) { + clearCommandInfo.color = uf::vector::decode( sceneMetadata["system"]["renderer"]["clear values"][0], pod::Vector4f{0,0,0,0} ); + } + if ( !ext::json::isNull( sceneMetadata["light"]["ambient"] ) ) { + clearCommandInfo.color = uf::vector::decode( sceneMetadata["light"]["ambient"], pod::Vector4f{0,0,0,0} ); + // auto ambient = uf::vector::decode( sceneMetadata["light"]["ambient"], pod::Vector4f{1,1,1,1} ); + // GL_ERROR_CHECK(glLightfv(GL_LIGHT0, GL_AMBIENT, &ambient[0])); + } + #endif + + GL_ERROR_CHECK(glClearColor(clearCommandInfo.color[0], clearCommandInfo.color[1], clearCommandInfo.color[2], clearCommandInfo.color[3])); + GL_ERROR_CHECK(glClearDepth(clearCommandInfo.depth)); + GL_ERROR_CHECK(glClear(clearCommandInfo.bits)); + } + for ( auto& renderMode : renderModes ) { if ( !renderMode || !renderMode->execute ) continue; - ext::opengl::currentRenderMode = renderMode; + ext::opengl::setCurrentRenderMode( renderMode ); + uf::graph::render(); uf::scene::render(); renderMode->render(); - renderMode->executed = true; + + ext::opengl::setCurrentRenderMode(NULL); } - ext::opengl::currentRenderMode = NULL; - if ( ext::opengl::settings::experimental::waitOnRenderEnd ) synchronize(); + + if ( ext::opengl::settings::invariant::waitOnRenderEnd ) synchronize(); + + { + #if UF_ENV_DREAMCAST + #if UF_USE_OPENGL_GLDC + glKosSwapBuffers(); + #else + glutSwapBuffers(); + #endif + #else + device.activateContext().display(); + #endif + } + #if UF_USE_OPENVR // if ( ext::openvr::context ) ext::openvr::postSubmit(); #endif diff --git a/engine/src/ext/opengl/rendermode.cpp b/engine/src/ext/opengl/rendermode.cpp index f29c6b2d..f5699ad7 100644 --- a/engine/src/ext/opengl/rendermode.cpp +++ b/engine/src/ext/opengl/rendermode.cpp @@ -130,6 +130,8 @@ void ext::opengl::RenderMode::render() { auto& commands = getCommands(this->mostRecentCommandPoolId); commands.submit(); + this->executed = true; +#if 0 if ( ext::opengl::renderModes.back() != this ) return; #if UF_ENV_DREAMCAST @@ -141,6 +143,7 @@ void ext::opengl::RenderMode::render() { #else if ( device ) device->activateContext().display(); #endif + auto& scene = uf::scene::getCurrentScene(); auto& sceneMetadata = scene.getComponent(); @@ -161,7 +164,7 @@ void ext::opengl::RenderMode::render() { GL_ERROR_CHECK(glClearColor(clearCommandInfo.color[0], clearCommandInfo.color[1], clearCommandInfo.color[2], clearCommandInfo.color[3])); GL_ERROR_CHECK(glClearDepth(clearCommandInfo.depth)); GL_ERROR_CHECK(glClear(clearCommandInfo.bits)); - +#endif } void ext::opengl::RenderMode::initialize( Device& device ) { diff --git a/engine/src/ext/opengl/rendermodes/base.cpp b/engine/src/ext/opengl/rendermodes/base.cpp index 0501948b..990a52ad 100644 --- a/engine/src/ext/opengl/rendermodes/base.cpp +++ b/engine/src/ext/opengl/rendermodes/base.cpp @@ -41,12 +41,12 @@ void ext::opengl::BaseRenderMode::createCommandBuffers( const uf::stl::vectordescriptor.renderMode != "" ) continue; GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass ); @@ -71,10 +71,13 @@ void ext::opengl::BaseRenderMode::initialize( Device& device ) { } GL_ERROR_CHECK(glEnable(GL_DEPTH_TEST)); GL_ERROR_CHECK(glEnable(GL_TEXTURE_2D)); + + GL_ERROR_CHECK(glEnable(GL_ALPHA_TEST)); + GL_ERROR_CHECK(glAlphaFunc(GL_GREATER, 0.1f)); GL_ERROR_CHECK(glEnable(GL_BLEND)); GL_ERROR_CHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - GL_ERROR_CHECK(glEnable(GL_LIGHTING)); +// GL_ERROR_CHECK(glEnable(GL_LIGHTING)); // GL_ERROR_CHECK(glEnable(GL_NORMALIZE)); // GL_ERROR_CHECK(glEnable(GL_COLOR_MATERIAL)); @@ -103,8 +106,6 @@ void ext::opengl::BaseRenderMode::tick() { ext::opengl::RenderMode::tick(); } void ext::opengl::BaseRenderMode::render() { -// if ( ext::opengl::renderModes.size() > 1 ) return; -// if ( ext::opengl::renderModes.back() != this ) return; ext::opengl::RenderMode::render(); } diff --git a/engine/src/ext/opengl/rendermodes/compute.cpp b/engine/src/ext/opengl/rendermodes/compute.cpp deleted file mode 100644 index fd1d1345..00000000 --- a/engine/src/ext/opengl/rendermodes/compute.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#if UF_USE_OPENGL - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -const uf::stl::string ext::opengl::ComputeRenderMode::getType() const { - return "Compute"; -} -const size_t ext::opengl::ComputeRenderMode::blitters() const { - return 1; -} -ext::opengl::Graphic* ext::opengl::ComputeRenderMode::getBlitter( size_t i ) { - return &this->blitter; -} -uf::stl::vector ext::opengl::ComputeRenderMode::getBlitters() { - return { &this->blitter }; -} - -void ext::opengl::ComputeRenderMode::initialize( Device& device ) { - ext::opengl::RenderMode::initialize( device ); -} -void ext::opengl::ComputeRenderMode::render() { -} -void ext::opengl::ComputeRenderMode::tick() { - ext::opengl::RenderMode::tick(); -} -void ext::opengl::ComputeRenderMode::destroy() { - ext::opengl::RenderMode::destroy(); -} -void ext::opengl::ComputeRenderMode::pipelineBarrier( GLhandle(VkCommandBuffer) commandBuffer, uint8_t state ) { -} -void ext::opengl::ComputeRenderMode::createCommandBuffers( ) { -} -void ext::opengl::ComputeRenderMode::bindPipelines() { -} - -#endif \ No newline at end of file diff --git a/engine/src/ext/opengl/rendermodes/deferred.cpp b/engine/src/ext/opengl/rendermodes/deferred.cpp index 8282233e..1e964bbf 100644 --- a/engine/src/ext/opengl/rendermodes/deferred.cpp +++ b/engine/src/ext/opengl/rendermodes/deferred.cpp @@ -34,6 +34,9 @@ void ext::opengl::DeferredRenderMode::initialize( Device& device ) { void ext::opengl::DeferredRenderMode::tick() { ext::opengl::RenderMode::tick(); } +void ext::opengl::DeferredRenderMode::render() { + ext::opengl::RenderMode::render(); +} void ext::opengl::DeferredRenderMode::destroy() { ext::opengl::RenderMode::destroy(); } diff --git a/engine/src/ext/opengl/rendermodes/rendertarget.cpp b/engine/src/ext/opengl/rendermodes/rendertarget.cpp index 2ebd5e47..38bfe2c0 100644 --- a/engine/src/ext/opengl/rendermodes/rendertarget.cpp +++ b/engine/src/ext/opengl/rendermodes/rendertarget.cpp @@ -82,7 +82,7 @@ void ext::opengl::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v clearCommandInfo.bits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; commands.record(clearCommandInfo); #endif - #if 0 + #if 1 CommandBuffer::InfoViewport viewportCommandInfo = {}; viewportCommandInfo.type = enums::Command::VIEWPORT; viewportCommandInfo.corner = pod::Vector2ui{0, 0}; diff --git a/engine/src/ext/openvr/openvr.cpp b/engine/src/ext/openvr/openvr.cpp index 9e60a692..39f5bbb2 100644 --- a/engine/src/ext/openvr/openvr.cpp +++ b/engine/src/ext/openvr/openvr.cpp @@ -467,7 +467,9 @@ void ext::openvr::submit() { bool invert = swapEyes; #endif } void ext::openvr::synchronize( bool async ) { - if ( async ) uf::thread::add( uf::thread::fetchWorker(), [](){ vr::VRCompositor()->WaitGetPoses(nullptr, 0, nullptr, 0); return true; }, true ); + if ( async ) uf::thread::queue( uf::thread::fetchWorker(), [](){ + vr::VRCompositor()->WaitGetPoses(nullptr, 0, nullptr, 0); + }); else vr::VRCompositor()->WaitGetPoses(nullptr, 0, nullptr, 0); ext::openvr::updateTracking(1); diff --git a/engine/src/ext/reactphysics/reactphysics.cpp b/engine/src/ext/reactphysics/reactphysics.cpp index 54b50e22..046edf7a 100644 --- a/engine/src/ext/reactphysics/reactphysics.cpp +++ b/engine/src/ext/reactphysics/reactphysics.cpp @@ -220,10 +220,18 @@ void ext::reactphysics::tick( float delta ) { accumulator += uf::physics::time::delta; +#if 0 + delta = delta * ext::reactphysics::timescale / 12; + for ( size_t i = 0; i < 12; ++i ) { + ::world->update(ext::reactphysics::timescale); + accumulator -= delta; + } +#else while ( accumulator >= ext::reactphysics::timescale ) { ::world->update(ext::reactphysics::timescale); accumulator -= ext::reactphysics::timescale; } +#endif TIMER(ext::reactphysics::debugDraw::rate, ext::reactphysics::debugDraw::enabled && ) { auto& scene = uf::scene::getCurrentScene(); diff --git a/engine/src/ext/vulkan/device.cpp b/engine/src/ext/vulkan/device.cpp index 0eb2159d..a6c2dd54 100644 --- a/engine/src/ext/vulkan/device.cpp +++ b/engine/src/ext/vulkan/device.cpp @@ -263,10 +263,109 @@ int ext::vulkan::Device::rate( VkPhysicalDevice device ) { vkGetPhysicalDeviceFeatures(device, &deviceFeatures); int score = 0; // Discrete GPUs have a significant performance advantage - if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - score += 1000; - // Maximum possible size of textures affects graphics quality - score += deviceProperties.limits.maxImageDimension2D; + if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) score += 1000; + { + score += deviceProperties.limits.maxImageDimension1D; + score += deviceProperties.limits.maxImageDimension2D; + score += deviceProperties.limits.maxImageDimension3D; + score += deviceProperties.limits.maxImageDimensionCube; + score += deviceProperties.limits.maxImageArrayLayers; + score += deviceProperties.limits.maxTexelBufferElements; + score += deviceProperties.limits.maxUniformBufferRange; + score += deviceProperties.limits.maxStorageBufferRange; + score += deviceProperties.limits.maxPushConstantsSize; + score += deviceProperties.limits.maxMemoryAllocationCount; + score += deviceProperties.limits.maxSamplerAllocationCount; + score += deviceProperties.limits.bufferImageGranularity; + score += deviceProperties.limits.sparseAddressSpaceSize; + score += deviceProperties.limits.maxBoundDescriptorSets; + score += deviceProperties.limits.maxPerStageDescriptorSamplers; + score += deviceProperties.limits.maxPerStageDescriptorUniformBuffers; + score += deviceProperties.limits.maxPerStageDescriptorStorageBuffers; + score += deviceProperties.limits.maxPerStageDescriptorSampledImages; + score += deviceProperties.limits.maxPerStageDescriptorStorageImages; + score += deviceProperties.limits.maxPerStageDescriptorInputAttachments; + score += deviceProperties.limits.maxPerStageResources; + score += deviceProperties.limits.maxDescriptorSetSamplers; + score += deviceProperties.limits.maxDescriptorSetUniformBuffers; + score += deviceProperties.limits.maxDescriptorSetUniformBuffersDynamic; + score += deviceProperties.limits.maxDescriptorSetStorageBuffers; + score += deviceProperties.limits.maxDescriptorSetStorageBuffersDynamic; + score += deviceProperties.limits.maxDescriptorSetSampledImages; + score += deviceProperties.limits.maxDescriptorSetStorageImages; + score += deviceProperties.limits.maxDescriptorSetInputAttachments; + score += deviceProperties.limits.maxVertexInputAttributes; + score += deviceProperties.limits.maxVertexInputBindings; + score += deviceProperties.limits.maxVertexInputAttributeOffset; + score += deviceProperties.limits.maxVertexInputBindingStride; + score += deviceProperties.limits.maxVertexOutputComponents; + score += deviceProperties.limits.maxTessellationGenerationLevel; + score += deviceProperties.limits.maxTessellationPatchSize; + score += deviceProperties.limits.maxTessellationControlPerVertexInputComponents; + score += deviceProperties.limits.maxTessellationControlPerVertexOutputComponents; + score += deviceProperties.limits.maxTessellationControlPerPatchOutputComponents; + score += deviceProperties.limits.maxTessellationControlTotalOutputComponents; + score += deviceProperties.limits.maxTessellationEvaluationInputComponents; + score += deviceProperties.limits.maxTessellationEvaluationOutputComponents; + score += deviceProperties.limits.maxGeometryShaderInvocations; + score += deviceProperties.limits.maxGeometryInputComponents; + score += deviceProperties.limits.maxGeometryOutputComponents; + score += deviceProperties.limits.maxGeometryOutputVertices; + score += deviceProperties.limits.maxGeometryTotalOutputComponents; + score += deviceProperties.limits.maxFragmentInputComponents; + score += deviceProperties.limits.maxFragmentOutputAttachments; + score += deviceProperties.limits.maxFragmentDualSrcAttachments; + score += deviceProperties.limits.maxFragmentCombinedOutputResources; + score += deviceProperties.limits.maxComputeSharedMemorySize; + score += deviceProperties.limits.maxComputeWorkGroupInvocations; + score += deviceProperties.limits.subPixelPrecisionBits; + score += deviceProperties.limits.subTexelPrecisionBits; + score += deviceProperties.limits.mipmapPrecisionBits; + score += deviceProperties.limits.maxDrawIndexedIndexValue; + score += deviceProperties.limits.maxDrawIndirectCount; + score += deviceProperties.limits.maxSamplerLodBias; + score += deviceProperties.limits.maxSamplerAnisotropy; + score += deviceProperties.limits.maxViewports; + score += deviceProperties.limits.viewportSubPixelBits; + score += deviceProperties.limits.minMemoryMapAlignment; + score += deviceProperties.limits.minTexelBufferOffsetAlignment; + score += deviceProperties.limits.minUniformBufferOffsetAlignment; + score += deviceProperties.limits.minStorageBufferOffsetAlignment; + score += deviceProperties.limits.minTexelOffset; + score += deviceProperties.limits.maxTexelOffset; + score += deviceProperties.limits.minTexelGatherOffset; + score += deviceProperties.limits.maxTexelGatherOffset; + score += deviceProperties.limits.minInterpolationOffset; + score += deviceProperties.limits.maxInterpolationOffset; + score += deviceProperties.limits.subPixelInterpolationOffsetBits; + score += deviceProperties.limits.maxFramebufferWidth; + score += deviceProperties.limits.maxFramebufferHeight; + score += deviceProperties.limits.maxFramebufferLayers; + score += deviceProperties.limits.framebufferColorSampleCounts; + score += deviceProperties.limits.framebufferDepthSampleCounts; + score += deviceProperties.limits.framebufferStencilSampleCounts; + score += deviceProperties.limits.framebufferNoAttachmentsSampleCounts; + score += deviceProperties.limits.maxColorAttachments; + score += deviceProperties.limits.sampledImageColorSampleCounts; + score += deviceProperties.limits.sampledImageIntegerSampleCounts; + score += deviceProperties.limits.sampledImageDepthSampleCounts; + score += deviceProperties.limits.sampledImageStencilSampleCounts; + score += deviceProperties.limits.storageImageSampleCounts; + score += deviceProperties.limits.maxSampleMaskWords; + score += deviceProperties.limits.timestampComputeAndGraphics; + score += deviceProperties.limits.timestampPeriod; + score += deviceProperties.limits.maxClipDistances; + score += deviceProperties.limits.maxCullDistances; + score += deviceProperties.limits.maxCombinedClipAndCullDistances; + score += deviceProperties.limits.discreteQueuePriorities; + score += deviceProperties.limits.pointSizeGranularity; + score += deviceProperties.limits.lineWidthGranularity; + score += deviceProperties.limits.strictLines; + score += deviceProperties.limits.standardSampleLocations; + score += deviceProperties.limits.optimalBufferCopyOffsetAlignment; + score += deviceProperties.limits.optimalBufferCopyRowPitchAlignment; + score += deviceProperties.limits.nonCoherentAtomSize; + } // Application can't function without geometry shaders if ( !deviceFeatures.geometryShader ) return 0; // @@ -307,6 +406,10 @@ int ext::vulkan::Device::rate( VkPhysicalDevice device ) { } if ( formats.empty() || presentModes.empty() ) return 0; } + if ( settings::gpuID != -1 && deviceProperties.deviceID == settings::gpuID ) { + score = std::numeric_limits::max(); + } + UF_MSG_VALIDATION("Device name: " << deviceProperties.deviceName << " (" << deviceProperties.deviceID << ") has a score of " << score); return score; } @@ -605,6 +708,16 @@ void ext::vulkan::Device::initialize() { uf::stl::vector devices(deviceCount); vkEnumeratePhysicalDevices( this->instance, &deviceCount, devices.data() ); + + int bestScore = 0; + for ( const VkPhysicalDevice& device : devices ) { + int score = rate( device ); + if ( score <= bestScore ) continue; + bestScore = score; + physicalDevice = device; + } + + /* // Use an ordered map to automatically sort candidates by increasing score std::multimap candidates; for ( const VkPhysicalDevice& device : devices ) { @@ -614,6 +727,7 @@ void ext::vulkan::Device::initialize() { // Check if the best candidate is suitable at all if ( candidates.rbegin()->first <= 0 ) UF_EXCEPTION("Vulkan error: failed to find a suitable GPU!"); this->physicalDevice = candidates.rbegin()->second; + */ } // Update properties { @@ -624,6 +738,7 @@ void ext::vulkan::Device::initialize() { // Memory properties are used regularly for creating all kinds of buffers vkGetPhysicalDeviceMemoryProperties( this->physicalDevice, &memoryProperties ); } + UF_MSG_VALIDATION("Using device " << properties.deviceName << " (" << properties.deviceID << ")"); { properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; @@ -856,7 +971,7 @@ void ext::vulkan::Device::initialize() { bool SRGB = true; auto TARGET_FORMAT = SRGB ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; auto TARGET_COLORSPACE = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - if ( ext::vulkan::settings::experimental::hdr ) { + if ( ext::vulkan::settings::pipelines::hdr ) { TARGET_FORMAT = VK_FORMAT_R32G32B32A32_SFLOAT; TARGET_COLORSPACE = VK_COLOR_SPACE_HDR10_ST2084_EXT; } diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index 4aa6009e..84270047 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -280,9 +280,9 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes PIPELINE_INITIALIZATION_INVALID: VK_DEBUG_VALIDATION_MESSAGE("Pipeline initialization invalid, updating next tick..."); - uf::thread::add( uf::thread::get("Main"), [&]() -> int { + uf::thread::queue( uf::thread::get("Main"), [&]{ this->initialize( graphic, descriptor ); - return 0;}, true ); + }); return; } void ext::vulkan::Pipeline::record( const Graphic& graphic, VkCommandBuffer commandBuffer, size_t pass, size_t draw ) const { @@ -376,9 +376,24 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip for ( auto* shader : shaders ) { auto& infos = INFOS.emplace_back(); - uf::stl::vector types; + // add per-rendermode buffers + for ( auto& buffer : renderMode.buffers ) { + if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor); + if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor); + } + // add per-shader buffers + for ( auto& buffer : shader->buffers ) { + if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor); + if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor); + } + // add per-pipeline buffers + for ( auto& buffer : this->buffers ) { + if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor); + if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor); + } + if ( descriptor.subpass < renderTarget.passes.size() ) { auto& subpass = renderTarget.passes[descriptor.subpass]; for ( auto& input : subpass.inputs ) { @@ -404,13 +419,8 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip infos.sampler.emplace_back(sampler.descriptor.info); } - size_t consumes = 0; - for ( auto& buffer : shader->buffers ) { - if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor); - if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor); - } - // check if we can even consume that many infos + size_t consumes = 0; for ( auto& layout : shader->descriptorSetLayoutBindings ) { switch ( layout.descriptorType ) { // consume an texture image info @@ -635,9 +645,9 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip PIPELINE_UPDATE_INVALID: // graphic.process = false; VK_DEBUG_VALIDATION_MESSAGE("Pipeline update invalid, updating next tick..."); - uf::thread::add( uf::thread::get("Main"), [&]() -> int { + uf::thread::queue( uf::thread::get("Main"), [&]{ this->update( graphic, descriptor ); - return 0;}, true ); + }); return; } void ext::vulkan::Pipeline::destroy() { @@ -659,6 +669,8 @@ void ext::vulkan::Pipeline::destroy() { vkDestroyDescriptorSetLayout( *device, descriptorSetLayout, nullptr ); descriptorSetLayout = VK_NULL_HANDLE; } + + if ( settings::experimental::dedicatedThread ) ext::vulkan::states::rebuild = true; } uf::stl::vector ext::vulkan::Pipeline::getShaders( uf::stl::vector& shaders ) { uf::stl::unordered_map map; @@ -1103,7 +1115,7 @@ ext::vulkan::GraphicDescriptor::hash_t ext::vulkan::GraphicDescriptor::hash() co size_t hash{}; hash += std::hash{}(subpass); - if ( settings::experimental::individualPipelines ) + if ( settings::invariant::individualPipelines ) hash += std::hash{}(renderMode); hash += std::hash{}(renderTarget); diff --git a/engine/src/ext/vulkan/rendermode.cpp b/engine/src/ext/vulkan/rendermode.cpp index da6480dd..e6226ae9 100644 --- a/engine/src/ext/vulkan/rendermode.cpp +++ b/engine/src/ext/vulkan/rendermode.cpp @@ -196,7 +196,11 @@ void ext::vulkan::RenderMode::createCommandBuffers() { this->synchronize(); // bindPipelines( graphics ); + + //lockMutex(); createCommandBuffers( graphics ); + //unlockMutex(); + this->mostRecentCommandPoolId = std::this_thread::get_id(); this->rebuild = false; } @@ -219,6 +223,18 @@ ext::vulkan::RenderMode::commands_container_t& ext::vulkan::RenderMode::getComma } return commands; } +void ext::vulkan::RenderMode::lockMutex() { + return lockMutex( std::this_thread::get_id() ); +} +void ext::vulkan::RenderMode::lockMutex( std::thread::id id ) { + this->commands.lock( id ); +} +void ext::vulkan::RenderMode::unlockMutex() { + return unlockMutex( std::this_thread::get_id() ); +} +void ext::vulkan::RenderMode::unlockMutex( std::thread::id id ) { + this->commands.unlock( id ); +} void ext::vulkan::RenderMode::createCommandBuffers( const uf::stl::vector& graphics ) { } @@ -239,6 +255,7 @@ void ext::vulkan::RenderMode::bindPipelines() { this->bindPipelines( graphics ); } void ext::vulkan::RenderMode::bindPipelines( const uf::stl::vector& graphics ) { + //lockMutex(); for ( auto* pointer : graphics ) { auto& graphic = *pointer; for ( size_t currentPass = 0; currentPass < renderTarget.passes.size(); ++currentPass ) { @@ -261,39 +278,23 @@ void ext::vulkan::RenderMode::bindPipelines( const uf::stl::vectormostRecentCommandPoolId ); - // Get next image in the swap chain (back/front buffer) - VK_CHECK_RESULT(swapchain.acquireNextImage(&states::currentBuffer, swapchain.presentCompleteSemaphore)); - - // Use a fence to wait until the command buffer has finished execution before using it again - VK_CHECK_RESULT(vkWaitForFences(*device, 1, &fences[states::currentBuffer], VK_TRUE, UINT64_MAX)); - VK_CHECK_RESULT(vkResetFences(*device, 1, &fences[states::currentBuffer])); - - // Pipeline stage at which the queue submission will wait (via pWaitSemaphores) - VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - // The submit info structure specifices a command buffer queue submission batch VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.pWaitDstStageMask = &waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at - submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing - submitInfo.waitSemaphoreCount = 1; // One wait semaphore - submitInfo.pSignalSemaphores = &renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed - submitInfo.signalSemaphoreCount = 1; // One signal semaphore - submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission) + submitInfo.pWaitDstStageMask = NULL; // Pointer to the list of pipeline stages that the semaphore waits will occur at + submitInfo.pWaitSemaphores = NULL; // Semaphore(s) to wait upon before the submitted command buffer starts executing + submitInfo.waitSemaphoreCount = 0; // One wait semaphore + submitInfo.pSignalSemaphores = NULL; // Semaphore(s) to be signaled when command buffers have completed + submitInfo.signalSemaphoreCount = 0; // One signal semaphore + submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission) submitInfo.commandBufferCount = 1; - // Submit to the graphics queue passing a wait fence - VK_CHECK_RESULT(vkQueueSubmit( device->getQueue( Device::QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer])); - //vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[states::currentBuffer]); - - // Present the current buffer to the swap chain - // Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation - // This ensures that the image is not presented to the windowing system until all commands have been submitted - VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( Device::QueueEnum::PRESENT ), states::currentBuffer, renderCompleteSemaphore)); - VK_CHECK_RESULT(vkQueueWaitIdle(device->getQueue( Device::QueueEnum::PRESENT ))); + return submitInfo; } void ext::vulkan::RenderMode::initialize( Device& device ) { @@ -338,6 +339,10 @@ void ext::vulkan::RenderMode::tick() { this->synchronize(); } +void ext::vulkan::RenderMode::render() { + this->synchronize(); +} + void ext::vulkan::RenderMode::destroy() { this->synchronize(); @@ -360,9 +365,13 @@ void ext::vulkan::RenderMode::destroy() { fences.clear(); } void ext::vulkan::RenderMode::synchronize( uint64_t timeout ) { +/* if ( !device ) return; if ( fences.empty() ) return; + lockMutex(); VK_CHECK_RESULT(vkWaitForFences( *device, fences.size(), fences.data(), VK_TRUE, timeout )); + unlockMutex(); +*/ } void ext::vulkan::RenderMode::pipelineBarrier( VkCommandBuffer command, uint8_t stage ) { } diff --git a/engine/src/ext/vulkan/rendermodes/base.cpp b/engine/src/ext/vulkan/rendermodes/base.cpp index 6ba02340..418fdd23 100644 --- a/engine/src/ext/vulkan/rendermodes/base.cpp +++ b/engine/src/ext/vulkan/rendermodes/base.cpp @@ -94,7 +94,42 @@ void ext::vulkan::BaseRenderMode::tick() { void ext::vulkan::BaseRenderMode::render() { // if ( ext::vulkan::renderModes.size() > 1 ) return; if ( ext::vulkan::renderModes.back() != this ) return; - ext::vulkan::RenderMode::render(); + + //lockMutex( this->mostRecentCommandPoolId ); + auto& commands = getCommands( this->mostRecentCommandPoolId ); + // Get next image in the swap chain (back/front buffer) + VK_CHECK_RESULT(swapchain.acquireNextImage(&states::currentBuffer, swapchain.presentCompleteSemaphore)); + + // Use a fence to wait until the command buffer has finished execution before using it again + VK_CHECK_RESULT(vkWaitForFences(*device, 1, &fences[states::currentBuffer], VK_TRUE, UINT64_MAX)); + VK_CHECK_RESULT(vkResetFences(*device, 1, &fences[states::currentBuffer])); + + // Pipeline stage at which the queue submission will wait (via pWaitSemaphores) + VkPipelineStageFlags waitStageMask[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; + // The submit info structure specifices a command buffer queue submission batch + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pWaitDstStageMask = waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at + submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing + submitInfo.waitSemaphoreCount = 1; // One wait semaphore + submitInfo.pSignalSemaphores = &renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed + submitInfo.signalSemaphoreCount = 1; // One signal semaphore + submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission) + submitInfo.commandBufferCount = 1; + + // Submit to the graphics queue passing a wait fence + VK_CHECK_RESULT(vkQueueSubmit( device->getQueue( Device::QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer])); + //vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[states::currentBuffer]); + + // Present the current buffer to the swap chain + // Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation + // This ensures that the image is not presented to the windowing system until all commands have been submitted + VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( Device::QueueEnum::PRESENT ), states::currentBuffer, renderCompleteSemaphore)); + VK_CHECK_RESULT(vkQueueWaitIdle(device->getQueue( Device::QueueEnum::PRESENT ))); + + this->executed = true; + + //unlockMutex( this->mostRecentCommandPoolId ); } void ext::vulkan::BaseRenderMode::initialize( Device& device ) { diff --git a/engine/src/ext/vulkan/rendermodes/compute.cpp b/engine/src/ext/vulkan/rendermodes/compute.cpp deleted file mode 100644 index bf5bb287..00000000 --- a/engine/src/ext/vulkan/rendermodes/compute.cpp +++ /dev/null @@ -1,260 +0,0 @@ -#if UF_USE_VULKAN - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -const uf::stl::string ext::vulkan::ComputeRenderMode::getType() const { - return "Compute"; -} -const size_t ext::vulkan::ComputeRenderMode::blitters() const { - return 1; -} -ext::vulkan::Graphic* ext::vulkan::ComputeRenderMode::getBlitter( size_t i ) { - return &this->blitter; -} -uf::stl::vector ext::vulkan::ComputeRenderMode::getBlitters() { - return { &this->blitter }; -} - -void ext::vulkan::ComputeRenderMode::initialize( Device& device ) { - ext::vulkan::RenderMode::initialize( device ); - -// this->width = 3840; -// this->height = 2160; - - { - auto width = this->width > 0 ? this->width : ext::vulkan::settings::width; - auto height = this->height > 0 ? this->height : ext::vulkan::settings::height; - - compute.device = &device; - compute.material.device = &device; - compute.descriptor.renderMode = this->getName(); - compute.material.initializeShaders({ - {uf::io::root+"/shaders/raytracing/comp.spv", VK_SHADER_STAGE_COMPUTE_BIT}, - }); - #if UF_USE_OPENVR - size_t eyes = (ext::openvr::context ? 2 : 1); - #else - size_t eyes = 1; - #endif - for ( size_t i = 0; i < eyes; ++i ) { - Texture2D& texture = compute.material.textures.emplace_back(); - texture.asRenderTarget( device, width, height ); - } - - { - auto& scene = uf::scene::getCurrentScene(); - auto& metadata = scene.getComponent(); - - auto& shader = compute.material.shaders.front(); - - struct SpecializationConstant { - uint32_t maxLights = 16; - uint32_t eyes = 2; - }; - auto& specializationConstants = shader.specializationConstants.get(); - specializationConstants.maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(); - specializationConstants.eyes = eyes; - for ( auto& binding : shader.descriptorSetLayoutBindings ) { - if ( binding.descriptorCount > 1 ) { - binding.descriptorCount = specializationConstants.eyes; - } - } - } - - // update buffers - if ( !compute.buffers.empty() ) { - // compute.getPipeline().update( compute ); - compute.updatePipelines(); - } - } - { - uf::Mesh mesh; - mesh.bind(); - mesh.insertVertices({ - { {-1.0f, 1.0f}, {0.0f, 1.0f}, }, - { {-1.0f, -1.0f}, {0.0f, 0.0f}, }, - { {1.0f, -1.0f}, {1.0f, 0.0f}, }, - { {1.0f, 1.0f}, {1.0f, 1.0f}, } - }); - mesh.insertIndices({ - 0, 1, 2, 2, 3, 0 - }); - /* - uf::Mesh mesh; - mesh.vertices = { - { {-1.0f, 1.0f}, {0.0f, 1.0f}, }, - { {-1.0f, -1.0f}, {0.0f, 0.0f}, }, - { {1.0f, -1.0f}, {1.0f, 0.0f}, }, - { {1.0f, 1.0f}, {1.0f, 1.0f}, } - }; - mesh.indices = { - 0, 1, 2, 2, 3, 0 - }; - */ - - blitter.device = &device; - blitter.material.device = &device; - blitter.descriptor.subpass = 1; - blitter.descriptor.inputs.dispatch = { (width / 32) + 1, (height / 32) + 1, 1 }; - - blitter.descriptor.depth.test = false; - blitter.descriptor.depth.write = false; - - blitter.initializeMesh( mesh ); - blitter.material.initializeShaders({ - {uf::io::root+"/shaders/display/blit.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, - {uf::io::root+"/shaders/display/blit.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} - }); - for ( auto& computeTexture : compute.material.textures ) { - Texture2D& texture = blitter.material.textures.emplace_back(); - texture = computeTexture; - texture.device = NULL; - } - blitter.initializePipeline(); - } -} -void ext::vulkan::ComputeRenderMode::render() { - if ( compute.buffers.empty() ) return; - - auto& commands = getCommands( this->mostRecentCommandPoolId ); - // Submit compute commands - // Use a fence to ensure that compute command buffer has finished executing before using it again - VK_CHECK_RESULT(vkWaitForFences( *device, 1, &fences[states::currentBuffer], VK_TRUE, UINT64_MAX )); - VK_CHECK_RESULT(vkResetFences( *device, 1, &fences[states::currentBuffer] )); - - VkSubmitInfo submitInfo = ext::vulkan::initializers::submitInfo(); - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commands[states::currentBuffer]; - - VK_CHECK_RESULT(vkQueueSubmit(device->getQueue( Device::QueueEnum::COMPUTE ), 1, &submitInfo, fences[states::currentBuffer])); - //vkQueueSubmit(device->queues.compute, 1, &submitInfo, fences[states::currentBuffer]); -} -void ext::vulkan::ComputeRenderMode::tick() { - ext::vulkan::RenderMode::tick(); - -#if UF_USE_OPENVR - size_t eyes = (ext::openvr::context ? 2 : 1); -#else - size_t eyes = 1; -#endif - if ( ext::vulkan::states::resized ) { - // auto-resize texture - if ( this->width == 0 && this->height == 0 ) { - auto width = this->width > 0 ? this->width : ext::vulkan::settings::width; - auto height = this->height > 0 ? this->height : ext::vulkan::settings::height; - for ( auto& texture : compute.material.textures ) { - texture.destroy(); - } - compute.material.textures.clear(); - for ( size_t i = 0; i < eyes; ++i ) { - Texture2D& texture = compute.material.textures.emplace_back(); - texture.asRenderTarget( *device, width, height ); - } - } - // update blitter descriptor set - if ( blitter.initialized ) { - blitter.material.textures.clear(); - for ( auto& computeTexture : compute.material.textures ) { - Texture2D& texture = blitter.material.textures.emplace_back(); - texture = computeTexture; - texture.device = NULL; - } - blitter.getPipeline().update( blitter ); - // blitter.updatePipelines(); - } - if ( !compute.buffers.empty() ) { - compute.getPipeline().update( compute ); - // compute.updatePipelines(); - } - } -} -void ext::vulkan::ComputeRenderMode::destroy() { - ext::vulkan::RenderMode::destroy(); - blitter.destroy(); - compute.destroy(); -} -void ext::vulkan::ComputeRenderMode::pipelineBarrier( VkCommandBuffer commandBuffer, uint8_t state ) { - if ( compute.buffers.empty() ) return; - - VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; - imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - - for ( auto& texture : compute.material.textures ) { - VkPipelineStageFlags srcStageMask, dstStageMask; - imageMemoryBarrier.image = texture.image; - imageMemoryBarrier.oldLayout = texture.descriptor.imageLayout; - imageMemoryBarrier.newLayout = texture.descriptor.imageLayout; - - switch ( state ) { - case 0: { - imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; - srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - } break; - case 1: { - imageMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; - srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - } break; - // ensure - default: { - imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - } - } - - vkCmdPipelineBarrier( commandBuffer, - srcStageMask, dstStageMask, - VK_FLAGS_NONE, - 0, NULL, - 0, NULL, - 1, &imageMemoryBarrier - ); - - texture.descriptor.imageLayout = imageMemoryBarrier.newLayout; - } -} -void ext::vulkan::ComputeRenderMode::createCommandBuffers( ) { - this->synchronize(); - - float width = this->width > 0 ? this->width : ext::vulkan::settings::width; - float height = this->height > 0 ? this->height : ext::vulkan::settings::height; - - VkCommandBufferBeginInfo cmdBufInfo = ext::vulkan::initializers::commandBufferBeginInfo(); - auto& pipeline = compute.getPipeline(); - auto& commands = getCommands(); - if ( compute.buffers.empty() ) return; - for (size_t i = 0; i < commands.size(); ++i) { - VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo)); - pipeline.record(compute, commands[i]); - VK_CHECK_RESULT(vkEndCommandBuffer(commands[i])); - } - - this->mostRecentCommandPoolId = std::this_thread::get_id(); -} -void ext::vulkan::ComputeRenderMode::bindPipelines() { - -} - -#endif \ No newline at end of file diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index c1af58b4..7b0db63e 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -34,11 +34,13 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { float height = this->height > 0 ? this->height : ext::vulkan::settings::height; auto& swapchainRender = ext::vulkan::getRenderMode("Swapchain"); if ( swapchainRender.renderTarget.width != width || swapchainRender.renderTarget.height != height ) { - settings::experimental::deferredAliasOutputToSwapchain = false; + settings::invariant::deferredAliasOutputToSwapchain = false; } } - if ( settings::experimental::bloom ) settings::experimental::deferredAliasOutputToSwapchain = false; + // buffers.emplace_back().initialize( NULL, sizeof(pod::Camera::Viewports), uf::renderer::enums::Buffer::UNIFORM ); + + if ( settings::pipelines::bloom ) settings::invariant::deferredAliasOutputToSwapchain = false; auto HDR_FORMAT = VK_FORMAT_R32G32B32A32_SFLOAT; auto SDR_FORMAT = VK_FORMAT_R16G16B16A16_SFLOAT; @@ -52,7 +54,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { size_t id, normals, uvs, mips, albedo, depth, color, bright, scratch, output; } attachments = {}; - bool blend = true; // !ext::vulkan::settings::experimental::deferredSampling; + bool blend = true; // !ext::vulkan::settings::invariant::deferredSampling; attachments.id = renderTarget.attach(RenderTarget::Attachment::Descriptor{ /*.format = */VK_FORMAT_R16G16_UINT, /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, @@ -68,7 +70,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.blend = */false, /*.samples = */msaa, }); - if ( ext::vulkan::settings::experimental::deferredSampling ) { + if ( ext::vulkan::settings::invariant::deferredSampling ) { attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{ // /*.format = */VK_FORMAT_R32G32B32A32_SFLOAT, /*.format = */VK_FORMAT_R16G16B16A16_SFLOAT, @@ -87,7 +89,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { }); } else { attachments.albedo = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */ext::vulkan::settings::experimental::hdr ? HDR_FORMAT : VK_FORMAT_R8G8B8A8_UNORM, + /*.format = */ext::vulkan::settings::pipelines::hdr ? HDR_FORMAT : VK_FORMAT_R8G8B8A8_UNORM, /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, /*.blend = */blend, @@ -102,21 +104,21 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.samples = */msaa, }); attachments.color = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format =*/ ext::vulkan::settings::experimental::hdr ? HDR_FORMAT : SDR_FORMAT, + /*.format =*/ ext::vulkan::settings::pipelines::hdr ? HDR_FORMAT : SDR_FORMAT, /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT, /*.blend =*/ blend, /*.samples =*/ 1, }); attachments.bright = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format =*/ ext::vulkan::settings::experimental::hdr ? HDR_FORMAT : SDR_FORMAT, + /*.format =*/ ext::vulkan::settings::pipelines::hdr ? HDR_FORMAT : SDR_FORMAT, /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT, /*.blend =*/ blend, /*.samples =*/ 1, }); attachments.scratch = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format =*/ ext::vulkan::settings::experimental::hdr ? HDR_FORMAT : SDR_FORMAT, + /*.format =*/ ext::vulkan::settings::pipelines::hdr ? HDR_FORMAT : SDR_FORMAT, /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT, /*.blend =*/ blend, @@ -124,7 +126,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { }); // Attach swapchain's image as output - if ( settings::experimental::deferredAliasOutputToSwapchain ) { + if ( settings::invariant::deferredAliasOutputToSwapchain ) { attachments.output = renderTarget.attachments.size(); auto& swapchainAttachment = renderTarget.attachments.emplace_back(); swapchainAttachment.descriptor.format = ext::vulkan::settings::formats::color; //device.formats.color; @@ -150,7 +152,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { } } else { attachments.output = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format =*/ ext::vulkan::settings::experimental::hdr ? HDR_FORMAT : SDR_FORMAT, + /*.format =*/ ext::vulkan::settings::pipelines::hdr ? HDR_FORMAT : SDR_FORMAT, /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, /*.blend =*/ blend, @@ -161,7 +163,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { // metadata.outputs.emplace_back(attachments.output); for ( size_t eye = 0; eye < metadata.eyes; ++eye ) { - if ( ext::vulkan::settings::experimental::deferredSampling ) { + if ( ext::vulkan::settings::invariant::deferredSampling ) { // First pass: fill the G-Buffer { renderTarget.addPass( @@ -242,9 +244,9 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { uf::stl::string vertexShaderFilename = uf::io::root+"/shaders/display/subpass.vert.spv"; uf::stl::string fragmentShaderFilename = uf::io::root+"/shaders/display/subpass.frag.spv"; { std::pair settings[] = { - { uf::renderer::settings::experimental::vxgi, "vxgi.frag" }, + { uf::renderer::settings::pipelines::vxgi, "vxgi.frag" }, { msaa > 1, "msaa.frag" }, - { uf::renderer::settings::experimental::deferredSampling, "deferredSampling.frag" }, + { uf::renderer::settings::invariant::deferredSampling, "deferredSampling.frag" }, }; FOR_ARRAY( settings ) if ( settings[i].first ) fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", settings[i].second ); } @@ -257,7 +259,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { auto& scene = uf::scene::getCurrentScene(); auto& sceneMetadataJson = scene.getComponent(); - if ( settings::experimental::bloom ) { + if ( settings::pipelines::bloom ) { uf::stl::string computeShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/bloom.comp.spv"); blitter.material.attachShader(computeShaderFilename, uf::renderer::enums::Shader::COMPUTE, "bloom"); @@ -288,7 +290,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture ); shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light ); - if ( ext::vulkan::settings::experimental::vxgi ) { + if ( ext::vulkan::settings::pipelines::vxgi ) { uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; for ( auto pair : shader.metadata.definitions.specializationConstants ) { auto& sc = pair.second; @@ -330,7 +332,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { descriptor.subpass = (renderTarget.passes.size() / metadata.eyes) * eye + 1; if ( !blitter.hasPipeline( descriptor ) ) blitter.initializePipeline( descriptor ); - if ( settings::experimental::bloom ) { + if ( settings::pipelines::bloom ) { descriptor.inputs.dispatch = { (width / 8) + 1, (height / 8) + 1, 1 }; descriptor.pipeline = "bloom"; descriptor.subpass = 0; @@ -350,7 +352,7 @@ void ext::vulkan::DeferredRenderMode::tick() { if ( resized ) { renderTarget.initialize( *renderTarget.device ); - if ( settings::experimental::bloom ) { + if ( settings::pipelines::bloom ) { auto& shader = blitter.material.getShader("compute", "bloom"); #if 1 shader.textures.clear(); @@ -371,7 +373,7 @@ void ext::vulkan::DeferredRenderMode::tick() { descriptor.subpass = (renderTarget.passes.size() / metadata.eyes) * eye + 1; if ( blitter.hasPipeline( blitter.descriptor ) ) blitter.getPipeline( blitter.descriptor ).update( blitter, blitter.descriptor ); - if ( settings::experimental::bloom ) { + if ( settings::pipelines::bloom ) { descriptor.inputs.dispatch = { (width / 8) + 1, (height / 8) + 1, 1 }; descriptor.pipeline = "bloom"; descriptor.subpass = 0; @@ -382,6 +384,61 @@ void ext::vulkan::DeferredRenderMode::tick() { } } } +VkSubmitInfo ext::vulkan::DeferredRenderMode::queue() { + //lockMutex( this->mostRecentCommandPoolId ); + auto& commands = getCommands( this->mostRecentCommandPoolId ); + // Pipeline stage at which the queue submission will wait (via pWaitSemaphores) + static VkPipelineStageFlags waitStageMask[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; + // The submit info structure specifices a command buffer queue submission batch + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pWaitDstStageMask = waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at + submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing + submitInfo.waitSemaphoreCount = 1; // One wait semaphore + submitInfo.pSignalSemaphores = &renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed + submitInfo.signalSemaphoreCount = 1; // One signal semaphore + submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission) + submitInfo.commandBufferCount = 1; + + return submitInfo; +} +void ext::vulkan::DeferredRenderMode::render() { + //lockMutex( this->mostRecentCommandPoolId ); + auto& commands = getCommands( this->mostRecentCommandPoolId ); + // Get next image in the swap chain (back/front buffer) + VK_CHECK_RESULT(swapchain.acquireNextImage(&states::currentBuffer, swapchain.presentCompleteSemaphore)); + + // Use a fence to wait until the command buffer has finished execution before using it again + VK_CHECK_RESULT(vkWaitForFences(*device, 1, &fences[states::currentBuffer], VK_TRUE, UINT64_MAX)); + VK_CHECK_RESULT(vkResetFences(*device, 1, &fences[states::currentBuffer])); + + // Pipeline stage at which the queue submission will wait (via pWaitSemaphores) + VkPipelineStageFlags waitStageMask[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; + // The submit info structure specifices a command buffer queue submission batch + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.pWaitDstStageMask = waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at + submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing + submitInfo.waitSemaphoreCount = 1; // One wait semaphore + submitInfo.pSignalSemaphores = &renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed + submitInfo.signalSemaphoreCount = 1; // One signal semaphore + submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission) + submitInfo.commandBufferCount = 1; + + // Submit to the graphics queue passing a wait fence + VK_CHECK_RESULT(vkQueueSubmit( device->getQueue( Device::QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer])); + //vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[states::currentBuffer]); + + // Present the current buffer to the swap chain + // Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation + // This ensures that the image is not presented to the windowing system until all commands have been submitted + VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( Device::QueueEnum::PRESENT ), states::currentBuffer, renderCompleteSemaphore)); + VK_CHECK_RESULT(vkQueueWaitIdle(device->getQueue( Device::QueueEnum::PRESENT ))); + + this->executed = true; + + //unlockMutex( this->mostRecentCommandPoolId ); +} void ext::vulkan::DeferredRenderMode::destroy() { ext::vulkan::RenderMode::destroy(); blitter.destroy(); @@ -536,7 +593,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto // post-renderpass commands if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) commandBufferCallbacks[CALLBACK_END]( commands[i] ); - if ( settings::experimental::bloom ) { + if ( settings::pipelines::bloom ) { ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; descriptor.inputs.dispatch = { (width / 8) + 1, (height / 8) + 1, 1 }; descriptor.pipeline = "bloom"; @@ -591,7 +648,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto layer->pipelineBarrier( commands[i], 1 ); } - if ( !settings::experimental::deferredAliasOutputToSwapchain ) { + if ( !settings::invariant::deferredAliasOutputToSwapchain ) { { auto& renderTarget = swapchainRender.renderTarget; float width = renderTarget.width; diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 968670c1..50d5b592 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -8,6 +8,7 @@ #include #include #include +#include const uf::stl::string ext::vulkan::RenderTargetRenderMode::getTarget() const { // auto& metadata = *const_cast(&this->metadata); @@ -60,6 +61,12 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { if ( metadata.subpasses == 0 ) metadata.subpasses = 1; renderTarget.device = &device; renderTarget.views = metadata.views; + + // + if ( metadata.type == "depth" ) { + buffers.emplace_back().initialize( NULL, sizeof(pod::Camera::Viewports), uf::renderer::enums::Buffer::UNIFORM ); + } + if ( metadata.type == "depth" || metadata.type == "vxgi" ) { renderTarget.views = metadata.subpasses; struct { @@ -86,28 +93,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { } } else { for ( size_t currentPass = 0; currentPass < metadata.subpasses; ++currentPass ) { - if ( metadata.type == "depth" || metadata.type == "vxgi" ) { - struct { - size_t depth; - } attachments = {}; - - attachments.depth = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */ ext::vulkan::settings::formats::depth, - /*.layout = */ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - /*.usage = */ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - /*.blend = */ false, - /*.samples = */ 1, - }); - renderTarget.addPass( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - {}, - {}, - {}, - attachments.depth, - 0, - true - ); - } else if ( metadata.type == "single" ) { + if ( metadata.type == "single" ) { struct { size_t albedo, depth; } attachments = {}; @@ -136,62 +122,6 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { true ); } else { - #if 0 - struct { - size_t albedo, normals, position, depth; - } attachments = {}; - - attachments.albedo = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */ ext::vulkan::settings::formats::color, - /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - /*.blend = */ true, - /*.samples = */ 1, - }); - attachments.normals = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */ ext::vulkan::settings::formats::normal, - /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - /*.blend = */ false, - /*.samples = */ 1, - }); - - if ( !settings::experimental::deferredReconstructPosition ) - attachments.position = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */ ext::vulkan::settings::formats::position, - /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - /*.blend = */ false, - /*.samples = */ 1, - }); - - attachments.depth = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */ ext::vulkan::settings::formats::depth, - /*.layout = */ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - /*.usage = */ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - /*.blend = */ false, - /*.samples = */ 1, - }); - - // First pass: write to target - if ( settings::experimental::deferredReconstructPosition ) { - renderTarget.addPass( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - { attachments.albedo, attachments.normals }, - {}, - {}, - attachments.depth - ); - } else { - renderTarget.addPass( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - { attachments.albedo, attachments.normals, attachments.position }, - {}, - {}, - attachments.depth - ); - } - #else struct { size_t id, normals, uvs, albedo, depth, output; } attachments = {}; @@ -210,7 +140,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { /*.blend = */false, /*.samples = */msaa, }); - if ( !true && ext::vulkan::settings::experimental::deferredMode != "" ) { + if ( !true && ext::vulkan::settings::invariant::deferredMode != "" ) { attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{ /*.format = */VK_FORMAT_R16G16B16A16_UNORM, /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, @@ -241,7 +171,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { /*.blend =*/ true, /*.samples =*/ 1, }); - if ( !true && ext::vulkan::settings::experimental::deferredMode != "" ) { + if ( !true && ext::vulkan::settings::invariant::deferredMode != "" ) { // First pass: fill the G-Buffer { renderTarget.addPass( @@ -293,7 +223,6 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { } } metadata.outputs.emplace_back(attachments.output); - #endif } } } @@ -373,7 +302,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { std::pair settings[] = { { msaa > 1, "msaa.frag" }, // I don't actually have support for deferred sampling within a render target - // { uf::renderer::settings::experimental::deferredSampling, "deferredSampling.frag" }, + // { uf::renderer::settings::invariant::deferredSampling, "deferredSampling.frag" }, }; FOR_ARRAY( settings ) if ( settings[i].first ) fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", settings[i].second ); } @@ -514,12 +443,7 @@ void ext::vulkan::RenderTargetRenderMode::tick() { } } } -} -void ext::vulkan::RenderTargetRenderMode::destroy() { - ext::vulkan::RenderMode::destroy(); - blitter.destroy(); -} -void ext::vulkan::RenderTargetRenderMode::render() { + if ( metadata.limiter.frequency > 0 ) { if ( metadata.limiter.timer > metadata.limiter.frequency ) { metadata.limiter.timer = 0; @@ -529,44 +453,38 @@ void ext::vulkan::RenderTargetRenderMode::render() { metadata.limiter.execute = false; } } +} +void ext::vulkan::RenderTargetRenderMode::destroy() { + ext::vulkan::RenderMode::destroy(); + blitter.destroy(); +} - if ( !metadata.limiter.execute ) return; - +void ext::vulkan::RenderTargetRenderMode::render() { if ( commandBufferCallbacks.count(EXECUTE_BEGIN) > 0 ) commandBufferCallbacks[EXECUTE_BEGIN]( VkCommandBuffer{} ); + //lockMutex( this->mostRecentCommandPoolId ); auto& commands = getCommands( this->mostRecentCommandPoolId ); // Submit commands // Use a fence to ensure that command buffer has finished executing before using it again VK_CHECK_RESULT(vkWaitForFences( *device, 1, &fences[states::currentBuffer], VK_TRUE, UINT64_MAX )); VK_CHECK_RESULT(vkResetFences( *device, 1, &fences[states::currentBuffer] )); - // Pipeline stage at which the queue submission will wait (via pWaitSemaphores) - VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - // The submit info structure specifices a command buffer queue submission batch VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.pWaitDstStageMask = &waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at + submitInfo.pWaitDstStageMask = NULL; // Pointer to the list of pipeline stages that the semaphore waits will occur at submitInfo.pWaitSemaphores = NULL; // Semaphore(s) to wait upon before the submitted command buffer starts executing submitInfo.waitSemaphoreCount = 0; // One wait semaphore -// submitInfo.pSignalSemaphores = &renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed -// submitInfo.signalSemaphoreCount = 1; // One signal semaphore submitInfo.pSignalSemaphores = NULL; // Semaphore(s) to be signaled when command buffers have completed submitInfo.signalSemaphoreCount = 0; // One signal semaphore submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission) submitInfo.commandBufferCount = 1; VK_CHECK_RESULT(vkQueueSubmit(device->getQueue( Device::QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer])); -/* - VkSemaphoreWaitInfo waitInfo = {}; - waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; - waitInfo.flags = VK_SEMAPHORE_WAIT_ANY_BIT; - waitInfo.semaphoreCount = 1; - waitInfo.pSemaphores = &renderCompleteSemaphore; - waitInfo.pValues = NULL; - VK_CHECK_RESULT(vkWaitSemaphores( *device, &waitInfo, UINT64_MAX )); -*/ if ( commandBufferCallbacks.count(EXECUTE_END) > 0 ) commandBufferCallbacks[EXECUTE_END]( VkCommandBuffer{} ); + + this->executed = true; + //unlockMutex( this->mostRecentCommandPoolId ); } void ext::vulkan::RenderTargetRenderMode::pipelineBarrier( VkCommandBuffer commandBuffer, uint8_t state ) { VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; diff --git a/engine/src/ext/vulkan/swapchain.cpp b/engine/src/ext/vulkan/swapchain.cpp index 1a418dc2..19521d73 100644 --- a/engine/src/ext/vulkan/swapchain.cpp +++ b/engine/src/ext/vulkan/swapchain.cpp @@ -44,7 +44,7 @@ void ext::vulkan::Swapchain::initialize( Device& device ) { uf::stl::vector presentModes(presentModeCount); VK_CHECK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(device.physicalDevice, device.surface, &presentModeCount, presentModes.data())); #if 1 - if ( settings::experimental::vsync ) { + if ( settings::pipelines::vsync ) { swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; for ( size_t i = 0; i < presentModeCount; i++ ) { if ( presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR ) { @@ -62,7 +62,7 @@ void ext::vulkan::Swapchain::initialize( Device& device ) { } } #else - if ( !settings::experimental::vsync ) { + if ( !settings::pipelines::vsync ) { for ( size_t i = 0; i < presentModeCount; i++ ) { if ( presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR ) { swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; diff --git a/engine/src/ext/vulkan/vulkan.cpp b/engine/src/ext/vulkan/vulkan.cpp index 172fe210..a83d24aa 100644 --- a/engine/src/ext/vulkan/vulkan.cpp +++ b/engine/src/ext/vulkan/vulkan.cpp @@ -13,12 +13,17 @@ #include #include +namespace { + uf::stl::vector auxFences; +} + uint32_t ext::vulkan::settings::width = 1280; uint32_t ext::vulkan::settings::height = 720; uint8_t ext::vulkan::settings::msaa = 1; bool ext::vulkan::settings::validation = true; // constexpr size_t ext::vulkan::settings::maxViews = 6; size_t ext::vulkan::settings::viewCount = 2; +size_t ext::vulkan::settings::gpuID = -1; uf::stl::vector ext::vulkan::settings::validationFilters; uf::stl::vector ext::vulkan::settings::requestedDeviceFeatures; @@ -27,21 +32,28 @@ uf::stl::vector ext::vulkan::settings::requestedInstanceExtensi VkFilter ext::vulkan::settings::swapchainUpscaleFilter = VK_FILTER_LINEAR; +// these go hand in hand for the above +bool ext::vulkan::settings::experimental::dedicatedThread = false; bool ext::vulkan::settings::experimental::rebuildOnTickBegin = false; -bool ext::vulkan::settings::experimental::waitOnRenderEnd = false; -bool ext::vulkan::settings::experimental::individualPipelines = true; -bool ext::vulkan::settings::experimental::multithreadedCommandRecording = true; -bool ext::vulkan::settings::experimental::multithreadedCommandRendering = false; -uf::stl::string ext::vulkan::settings::experimental::deferredMode = ""; -bool ext::vulkan::settings::experimental::deferredReconstructPosition = false; -bool ext::vulkan::settings::experimental::deferredAliasOutputToSwapchain = true; -bool ext::vulkan::settings::experimental::multiview = true; -bool ext::vulkan::settings::experimental::vsync = true; -bool ext::vulkan::settings::experimental::hdr = true; -bool ext::vulkan::settings::experimental::vxgi = true; -bool ext::vulkan::settings::experimental::deferredSampling = true; -bool ext::vulkan::settings::experimental::culling = false; -bool ext::vulkan::settings::experimental::bloom = false; +bool ext::vulkan::settings::experimental::batchQueueSubmissions = false; + +// not so experimental +bool ext::vulkan::settings::invariant::waitOnRenderEnd = false; +bool ext::vulkan::settings::invariant::individualPipelines = true; +bool ext::vulkan::settings::invariant::multithreadedRecording = true; + +uf::stl::string ext::vulkan::settings::invariant::deferredMode = ""; +bool ext::vulkan::settings::invariant::deferredReconstructPosition = false; +bool ext::vulkan::settings::invariant::deferredAliasOutputToSwapchain = true; +bool ext::vulkan::settings::invariant::deferredSampling = true; + +bool ext::vulkan::settings::invariant::multiview = true; +// pipelines +bool ext::vulkan::settings::pipelines::vsync = true; +bool ext::vulkan::settings::pipelines::hdr = true; +bool ext::vulkan::settings::pipelines::vxgi = true; +bool ext::vulkan::settings::pipelines::culling = false; +bool ext::vulkan::settings::pipelines::bloom = false; VkColorSpaceKHR ext::vulkan::settings::formats::colorSpace; ext::vulkan::enums::Format::type_t ext::vulkan::settings::formats::color = ext::vulkan::enums::Format::R8G8B8A8_UNORM; @@ -57,9 +69,8 @@ std::mutex ext::vulkan::mutex; bool ext::vulkan::states::resized = false; bool ext::vulkan::states::rebuild = false; uint32_t ext::vulkan::states::currentBuffer = 0; +uf::ThreadUnique ext::vulkan::currentRenderMode; -uf::stl::vector ext::vulkan::scenes; -ext::vulkan::RenderMode* ext::vulkan::currentRenderMode = NULL; uf::stl::vector ext::vulkan::renderModes = { new ext::vulkan::BaseRenderMode, }; @@ -146,8 +157,25 @@ bool ext::vulkan::hasRenderMode( const uf::stl::string& name, bool isName ) { ext::vulkan::RenderMode& ext::vulkan::addRenderMode( ext::vulkan::RenderMode* mode, const uf::stl::string& name ) { mode->metadata.name = name; renderModesMap[name] = renderModes.emplace_back(mode); + VK_VALIDATION_MESSAGE("Adding RenderMode: " << name << ": " << mode->getType()); + // reorder + if ( hasRenderMode("Gui", true) ) { + RenderMode& primary = getRenderMode("Gui", true); + auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); + if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() ); + } + if ( hasRenderMode("", true) ) { + RenderMode& primary = getRenderMode("", true); + auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); + if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() ); + } else { + RenderMode& primary = getRenderMode("Swapchain", true); + auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); + if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() ); + } + ext::vulkan::states::rebuild = true; return *mode; } @@ -193,6 +221,21 @@ void ext::vulkan::removeRenderMode( ext::vulkan::RenderMode* mode, bool free ) { if ( free ) delete mode; ext::vulkan::states::rebuild = true; } +ext::vulkan::RenderMode* UF_API ext::vulkan::getCurrentRenderMode() { + return getCurrentRenderMode( std::this_thread::get_id() ); +} +ext::vulkan::RenderMode* UF_API ext::vulkan::getCurrentRenderMode( std::thread::id id ) { +// bool exists = ext::vulkan::currentRenderMode.has(id); +// auto& currentRenderMode = ext::vulkan::currentRenderMode.get(id); +// return currentRenderMode; + return ext::vulkan::currentRenderMode.get(id); +} +void UF_API ext::vulkan::setCurrentRenderMode( ext::vulkan::RenderMode* renderMode ) { + return setCurrentRenderMode( renderMode, std::this_thread::get_id() ); +} +void UF_API ext::vulkan::setCurrentRenderMode( ext::vulkan::RenderMode* renderMode, std::thread::id id ) { + ext::vulkan::currentRenderMode.get(id) = renderMode; +} void ext::vulkan::initialize() { ext::vulkan::mutex.lock(); @@ -252,6 +295,16 @@ void ext::vulkan::initialize() { TextureCube::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST; TextureCube::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, 1, 6, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL ); } + + { + ::auxFences.resize( swapchain.buffers ); + + VkFenceCreateInfo fenceCreateInfo = {}; + fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + for ( auto& fence : ::auxFences ) VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence)); + } uf::graph::initialize(); @@ -259,14 +312,18 @@ void ext::vulkan::initialize() { if ( !renderMode ) continue; renderMode->initialize(device); } - pod::Thread::container_t jobs; - for ( auto& renderMode : renderModes ) { - if ( !renderMode ) continue; - if ( settings::experimental::individualPipelines ) renderMode->bindPipelines(); - if ( settings::experimental::multithreadedCommandRecording ) jobs.emplace_back([&](){renderMode->createCommandBuffers();}); - else renderMode->createCommandBuffers(); + + auto tasks = uf::thread::schedule(settings::experimental::dedicatedThread ? "Aux" : "Main"); + for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; + tasks.queue([&]{ + renderMode->lockMutex(); + if ( settings::invariant::individualPipelines ) renderMode->bindPipelines(); + renderMode->createCommandBuffers(); + renderMode->unlockMutex(); + }); } - if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); + uf::thread::execute( tasks ); + ext::vulkan::mutex.unlock(); } void ext::vulkan::tick() { @@ -274,34 +331,78 @@ void ext::vulkan::tick() { if ( ext::vulkan::states::resized || ext::vulkan::settings::experimental::rebuildOnTickBegin ) { ext::vulkan::states::rebuild = true; } - auto& scene = uf::scene::getCurrentScene(); - auto& graph = scene.getGraph(); - for ( auto entity : graph ) { - if ( !entity->hasComponent() ) continue; - ext::vulkan::Graphic& graphic = entity->getComponent(); - if ( graphic.initialized || !graphic.process || graphic.initialized ) continue; - graphic.initializePipeline(); - ext::vulkan::states::rebuild = true; + #if 0 + { + auto& scene = uf::scene::getCurrentScene(); + auto& graph = scene.getGraph(); + auto tasks = uf::thread::schedule(settings::experimental::dedicatedThread ? "Aux" : "Main"); + for ( auto entity : graph ) { + if ( !entity->hasComponent() ) continue; + ext::vulkan::Graphic& graphic = entity->getComponent(); + if ( graphic.initialized || !graphic.process || graphic.initialized ) continue; + tasks.queue([&]{ + graphic.initializePipeline(); + ext::vulkan::states::rebuild = true; + }); + } + uf::thread::execute( tasks ); } - for ( auto& renderMode : renderModes ) { - if ( !renderMode ) continue; - if ( !renderMode->device ) { - renderMode->initialize(ext::vulkan::device); + #else + { + auto& scene = uf::scene::getCurrentScene(); + auto& graph = scene.getGraph(); + for ( auto entity : graph ) { + if ( !entity->hasComponent() ) continue; + ext::vulkan::Graphic& graphic = entity->getComponent(); + if ( graphic.initialized || !graphic.process || graphic.initialized ) continue; + graphic.initializePipeline(); ext::vulkan::states::rebuild = true; } - renderMode->tick(); } - - pod::Thread::container_t jobs; - for ( auto& renderMode : renderModes ) { - if ( !renderMode ) continue; - if ( ext::vulkan::states::rebuild || renderMode->rebuild ) { - if ( settings::experimental::individualPipelines ) renderMode->bindPipelines(); - if ( settings::experimental::multithreadedCommandRecording ) jobs.emplace_back([&](){renderMode->createCommandBuffers();}); - else renderMode->createCommandBuffers(); + #endif + #if 0 + { + auto tasks = uf::thread::schedule(settings::experimental::dedicatedThread ? "Aux" : "Main"); + for ( auto& renderMode : renderModes ) { + if ( !renderMode ) continue; + if ( !renderMode->device ) { + tasks.queue([&]{ + renderMode->initialize(ext::vulkan::device); + ext::vulkan::states::rebuild = true; + renderMode->tick(); + }); + } else { + tasks.queue([&]{ + renderMode->tick(); + }); + } + } + uf::thread::execute( tasks ); + } + #else + { + for ( auto& renderMode : renderModes ) { + if ( !renderMode ) continue; + if ( !renderMode->device ) { + renderMode->initialize(ext::vulkan::device); + ext::vulkan::states::rebuild = true; + } + renderMode->tick(); } } - if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); + #endif + { + auto tasks = uf::thread::schedule(settings::experimental::dedicatedThread ? "Aux" : "Main"); + for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; + if ( ext::vulkan::states::rebuild || renderMode->rebuild ) tasks.queue([&]{ + renderMode->lockMutex(); + if ( settings::invariant::individualPipelines ) renderMode->bindPipelines(); + renderMode->createCommandBuffers(); + renderMode->unlockMutex(); + }); + } + uf::thread::execute( tasks ); + } ext::vulkan::states::rebuild = false; ext::vulkan::states::resized = false; @@ -309,66 +410,85 @@ void ext::vulkan::tick() { } void ext::vulkan::render() { ext::vulkan::mutex.lock(); - if ( hasRenderMode("Gui", true) ) { - RenderMode& primary = getRenderMode("Gui", true); - auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); - if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() ); - } - if ( hasRenderMode("", true) ) { - RenderMode& primary = getRenderMode("", true); - auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); - if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() ); - } else { - RenderMode& primary = getRenderMode("Swapchain", true); - auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); - if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() ); - } -#if 1 - pod::Thread::container_t jobs; - for ( auto& renderMode : renderModes ) { - if ( !renderMode || !renderMode->execute ) continue; - ext::vulkan::currentRenderMode = renderMode; - if ( settings::experimental::multithreadedCommandRendering ) { - jobs.emplace_back([&]{ + if ( settings::experimental::batchQueueSubmissions ) { + uf::stl::vector auxRenderModes; auxRenderModes.reserve( renderModes.size() ); + uf::stl::vector specialRenderModes; specialRenderModes.reserve( renderModes.size() ); + + for ( auto renderMode : renderModes ) { + if ( !renderMode || !renderMode->execute || !renderMode->metadata.limiter.execute ) continue; + renderMode->lockMutex( renderMode->mostRecentCommandPoolId ); + if ( renderMode->commandBufferCallbacks.count(RenderMode::EXECUTE_BEGIN) > 0 ) renderMode->commandBufferCallbacks[RenderMode::EXECUTE_BEGIN]( VkCommandBuffer{} ); + + if ( renderMode->getName() == "Gui" || renderMode->getName() == "" || renderMode->getName() == "Swapchain" ) + specialRenderModes.emplace_back(renderMode); + else + auxRenderModes.emplace_back(renderMode); + } + + // stuff we can batch + { + // Get next image in the swap chain (back/front buffer) + uf::stl::vector submits; submits.reserve( auxRenderModes.size() ); + for ( auto renderMode : auxRenderModes ) { + auto submitInfo = renderMode->queue(); + if ( submitInfo.sType != VK_STRUCTURE_TYPE_SUBMIT_INFO ) continue; + + ext::vulkan::setCurrentRenderMode(renderMode); + uf::graph::render(); + uf::scene::render(); + + submits.emplace_back(submitInfo); + renderMode->executed = true; + ext::vulkan::setCurrentRenderMode(NULL); + } + + if ( !submits.empty() ) { + VK_CHECK_RESULT(vkWaitForFences(device, 1, &::auxFences[states::currentBuffer], VK_TRUE, UINT64_MAX)); + VK_CHECK_RESULT(vkResetFences(device, 1, &::auxFences[states::currentBuffer])); + VK_CHECK_RESULT(vkQueueSubmit(device.getQueue( Device::QueueEnum::GRAPHICS ), submits.size(), submits.data(), ::auxFences[states::currentBuffer])); + } + } + // stuff we can't batch + { + for ( auto renderMode : specialRenderModes ) { + ext::vulkan::setCurrentRenderMode(renderMode); uf::graph::render(); uf::scene::render(); renderMode->render(); - renderMode->executed = true; - }); - } else { + ext::vulkan::setCurrentRenderMode(NULL); + } + } + + for ( auto renderMode : renderModes ) { + if ( renderMode->commandBufferCallbacks.count(RenderMode::EXECUTE_END) > 0 ) renderMode->commandBufferCallbacks[RenderMode::EXECUTE_END]( VkCommandBuffer{} ); + renderMode->unlockMutex( renderMode->mostRecentCommandPoolId ); + } + } else { + for ( auto& renderMode : renderModes ) { + if ( !renderMode || !renderMode->execute || !renderMode->metadata.limiter.execute ) continue; + + renderMode->lockMutex( renderMode->mostRecentCommandPoolId ); + ext::vulkan::setCurrentRenderMode(renderMode); uf::graph::render(); uf::scene::render(); renderMode->render(); - renderMode->executed = true; + ext::vulkan::setCurrentRenderMode(NULL); + renderMode->unlockMutex( renderMode->mostRecentCommandPoolId ); } } - if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); -#else - for ( auto& renderMode : renderModes ) { - if ( !renderMode || !renderMode->execute ) continue; - ext::vulkan::currentRenderMode = renderMode; - uf::scene::render(); - renderMode->render(); - renderMode->executed = true; - } -#endif - ext::vulkan::currentRenderMode = NULL; - if ( ext::vulkan::settings::experimental::waitOnRenderEnd ) { - synchronize(); - } -/* - if ( ext::openvr::context ) { - ext::openvr::postSubmit(); - } -*/ + + if ( ext::vulkan::settings::invariant::waitOnRenderEnd ) synchronize(); +// if ( ext::openvr::context ) ext::openvr::postSubmit(); ext::vulkan::mutex.unlock(); } void ext::vulkan::destroy() { ext::vulkan::mutex.lock(); synchronize(); + for ( auto& fence : ::auxFences ) vkDestroyFence( device, fence, nullptr); + Texture2D::empty.destroy(); Texture3D::empty.destroy(); TextureCube::empty.destroy(); diff --git a/engine/src/ext/xatlas/xatlas.cpp b/engine/src/ext/xatlas/xatlas.cpp index 349b933d..0045f78c 100644 --- a/engine/src/ext/xatlas/xatlas.cpp +++ b/engine/src/ext/xatlas/xatlas.cpp @@ -143,13 +143,16 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) { packOptions.resolution = graph.metadata["baking"]["resolution"].as(packOptions.resolution); // pack - pod::Thread::container_t jobs; - +#if UF_XATLAS_UNWRAP_MULTITHREAD + auto tasks = uf::thread::schedule("Async"); +#else + auto tasks = uf::thread::schedule("Main"); +#endif for ( auto& pair : atlases ) { - jobs.emplace_back([&]{ + tasks.queue([&]{ auto& atlas = pair.second; ::xatlas::Generate(atlas.pointer, chartOptions, packOptions); - /* + #if !UF_XATLAS_LAZY // get vertices size ahead of time for ( auto i = 0; i < atlas.pointer->meshCount; ++i ) { auto& xmesh = atlas.pointer->meshes[i]; @@ -157,15 +160,10 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) { // atlas.vertices += xmesh.vertexCount; sizes[entry.index] += xmesh.vertexCount; } - */ + #endif }); } - -#if UF_XATLAS_UNWRAP_MULTITHREAD - if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs ); -#else - for ( auto& job : jobs ) job(); -#endif + uf::thread::execute( tasks ); #if !UF_XATLAS_LAZY for ( auto& pair : atlases ) { diff --git a/engine/src/utils/thread/thread.cpp b/engine/src/utils/thread/thread.cpp index ef58dfc2..20153d49 100644 --- a/engine/src/utils/thread/thread.cpp +++ b/engine/src/utils/thread/thread.cpp @@ -9,8 +9,7 @@ uint uf::thread::workers = 1; std::thread::id uf::thread::mainThreadId = std::this_thread::get_id(); bool uf::thread::async = false; -#define UF_THREAD_ANNOUNCE(x)\ - //uf::iostream << x << "\n"; +#define UF_THREAD_ANNOUNCE(x) //UF_MSG_DEBUG(x) void UF_API uf::thread::start( pod::Thread& thread ) { if ( thread.running ) return; thread.thread = std::thread( uf::thread::tick, std::ref(thread) ); @@ -34,7 +33,7 @@ void UF_API uf::thread::tick( pod::Thread& thread ) { while ( thread.running ) { uf::thread::process( thread ); - if ( thread.terminates && thread.temps.empty() && thread.consts.empty() ) uf::thread::quit( thread ); + if ( thread.terminates && thread.queue.empty() && thread.container.empty() ) uf::thread::quit( thread ); if ( thread.limiter > 0 ) { long long sleep = (thread.limiter * 1000) - thread.timer.elapsed().asMilliseconds(); @@ -55,13 +54,54 @@ pod::Thread& UF_API uf::thread::fetchWorker( const uf::stl::string& name ) { if ( ++current >= limit ) current = 0; uf::stl::string thread = name; if ( current > 0 ) thread += " " + std::to_string(current); - bool exists = uf::thread::has(thread); - auto& pod = exists ? uf::thread::get(thread) : uf::thread::create(thread, true); + auto& pod = uf::thread::get(thread); if ( std::this_thread::get_id() != pod.thread.get_id() ) return pod; } - return uf::thread::has("Main") ? uf::thread::get("Main") : uf::thread::create("Main", true); + return uf::thread::get("Main"); } +pod::Thread::Tasks UF_API uf::thread::schedule( const uf::stl::string& name, bool wait ) { + pod::Thread::Tasks tasks = { + .name = name, + .waits = wait, + }; + + return tasks; +} +void UF_API uf::thread::execute( pod::Thread::Tasks& tasks ) { + if ( tasks.container.empty() ) return; + if ( tasks.name == "Main" ) { + // for ( auto& task : tasks.container ) task(); + while ( !tasks.container.empty() ) { + auto& task = tasks.container.front(); + task(); + tasks.container.pop(); + } + + } else if ( tasks.name == "Async" ) { + uf::stl::vector> futures; + futures.reserve(tasks.container.size()); + // for ( auto& task : tasks.container ) { + while ( !tasks.container.empty() ) { + auto task = tasks.container.front(); + futures.emplace_back(std::async( std::launch::async, task )); + tasks.container.pop(); + } + if ( tasks.waits ) for ( auto& future : futures ) future.wait(); + } else { + uf::stl::vector workers; + // for ( auto& task : tasks.container ) { + while ( !tasks.container.empty() ) { + auto task = tasks.container.front(); + auto& worker = uf::thread::fetchWorker( tasks.name ); + uf::thread::queue( worker, task ); + workers.emplace_back(&worker); + tasks.container.pop(); + } + if ( tasks.waits ) for ( auto& worker : workers ) uf::thread::wait( *worker ); + } +} +/* void UF_API uf::thread::batchWorker( const pod::Thread::function_t& function, const uf::stl::string& name ) { return batchWorkers( { function }, false, name ); } @@ -70,7 +110,7 @@ void UF_API uf::thread::batchWorkers( const uf::stl::vectorlock(); - temporary ? thread.temps.push( function ) : thread.consts.push_back( function ); + queue ? thread.queue.push( function ) : thread.container.push_back( function ); + if ( thread.mutex != NULL ) thread.mutex->unlock(); +} +*/ +void UF_API uf::thread::add( pod::Thread& thread, const pod::Thread::function_t& function ) { + if ( thread.mutex != NULL ) thread.mutex->lock(); + thread.container.emplace_back( function ); + if ( thread.mutex != NULL ) thread.mutex->unlock(); +} +void UF_API uf::thread::queue( const pod::Thread::container_t& functions ) { + for ( auto& function : functions ) + uf::thread::queue( uf::thread::fetchWorker(), function ); +} +void UF_API uf::thread::queue( const pod::Thread::function_t& function ) { + return uf::thread::queue( uf::thread::fetchWorker(), function ); +} +void UF_API uf::thread::queue( pod::Thread& thread, const pod::Thread::function_t& function ) { + if ( thread.mutex != NULL ) thread.mutex->lock(); + thread.queue.emplace( function ); if ( thread.mutex != NULL ) thread.mutex->unlock(); } void UF_API uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(uf::thread::uid(thread)) ) { UF_THREAD_ANNOUNCE("Bad Thread: " << thread.uid << " " << thread.name); return; } //ops - while ( !thread.temps.empty() ) { - auto& function = thread.temps.front(); + while ( !thread.queue.empty() ) { + auto& function = thread.queue.front(); if ( function ) #if UF_EXCEPTIONS try { @@ -100,9 +160,9 @@ void UF_API uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(u UF_MSG_ERROR("Thread " << thread.name << " (UID: " << thread.uid << ") caught exception: " << e.what()); } #endif - thread.temps.pop(); + thread.queue.pop(); } - for ( auto function : thread.consts ) { + for ( auto function : thread.container ) { if ( function ) #if UF_EXCEPTIONS try { @@ -119,10 +179,10 @@ void UF_API uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(u void UF_API uf::thread::wait( pod::Thread& thread ) { if ( thread.mutex != NULL ) { std::unique_lock lock(*thread.mutex); - thread.condition.wait(lock, [&]{return thread.temps.empty();}); + thread.condition.wait(lock, [&]{return thread.queue.empty();}); return; } - while ( !thread.temps.empty() ); + while ( !thread.queue.empty() ); } const uf::stl::string& UF_API uf::thread::name( const pod::Thread& thread ) { @@ -142,6 +202,8 @@ void UF_API uf::thread::terminate() { } } pod::Thread& UF_API uf::thread::create( const uf::stl::string& name, bool start, bool locks ) { + if ( name == "Main" ) start = false; + pod::Thread* pointer = NULL; uf::thread::threads.emplace_back(pointer = new pod::Thread); pod::Thread& thread = *pointer; @@ -154,11 +216,11 @@ pod::Thread& UF_API uf::thread::create( const uf::stl::string& name, bool start, thread.terminates = false; thread.running = false; thread.mutex = NULL; - thread.mutex = locks ? new std::mutex() : NULL; + thread.mutex = locks ? new std::mutex : NULL; thread.limiter = uf::thread::limiter; thread.affinity = (thread.uid % limit) + 1; - UF_THREAD_ANNOUNCE("Creating Thread #" << thread.uid << " (" << name << ") " << &thread << " (Affinity: " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)"); + UF_THREAD_ANNOUNCE("Creating Thread #" << thread.uid << " (" << name << ") " << &thread << " (Affinity: " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)" << (locks ? " with mutex" : "")); if ( start ) uf::thread::start( thread ); @@ -169,7 +231,6 @@ void UF_API uf::thread::destroy( pod::Thread& thread ) { UF_THREAD_ANNOUNCE("Quitting Thread #" << thread.uid << " (" << thread.name << ")"); uf::thread::quit( thread ); - UF_THREAD_ANNOUNCE("Quitted Thread #" << thread.uid << " (" << thread.name << ")"); if ( thread.mutex != NULL ) delete thread.mutex; @@ -193,6 +254,7 @@ pod::Thread& UF_API uf::thread::get( uint uid ) { UF_EXCEPTION("Thread error: invalid call"); } pod::Thread& UF_API uf::thread::get( const uf::stl::string& name ) { + if ( !uf::thread::has(name) ) return uf::thread::create(name); for ( pod::Thread* thread : uf::thread::threads ) if ( uf::thread::name(*thread) == name ) return *thread; UF_EXCEPTION("Thread error: invalid call"); } diff --git a/ext/behaviors/baking/behavior.cpp b/ext/behaviors/baking/behavior.cpp index d24caa2e..385e90c0 100644 --- a/ext/behaviors/baking/behavior.cpp +++ b/ext/behaviors/baking/behavior.cpp @@ -54,7 +54,6 @@ void ext::BakingBehavior::initialize( uf::Object& self ) { metadata.cull = metadataJson["baking"]["cull"].as(); auto& renderMode = this->getComponent(); - uf::renderer::addRenderMode( &renderMode, metadata.renderModeName ); renderMode.execute = false; renderMode.metadata.type = "single"; @@ -90,6 +89,9 @@ void ext::BakingBehavior::initialize( uf::Object& self ) { shader.textures.emplace_back().aliasTexture( metadata.buffers.baked ); }); UF_MSG_DEBUG("Finished initialiation."); + uf::thread::queue([&]{ + uf::renderer::addRenderMode( &renderMode, metadata.renderModeName ); + }); }); this->queueHook( "entity:PostInitialization.%UID%", ext::json::null(), 1 ); @@ -124,10 +126,14 @@ SAVE: { renderMode.execute = false; UF_MSG_DEBUG("Baking..."); - pod::Thread::container_t jobs; - - for ( size_t i = 0; i < metadata.max.layers; ++i ) { - jobs.emplace_back([&, i]{ +#if UF_BAKER_SAVE_MULTITHREAD + auto tasks = uf::thread::schedule("Async"); +#else + auto tasks = uf::thread::schedule("Main"); +#endif + // 0 is always broken, do not save it + for ( size_t i = 1; i < metadata.max.layers; ++i ) { + tasks.queue([&, i]{ // auto image = renderMode.screenshot(0, i); auto image = metadata.buffers.baked.screenshot(i); uf::stl::string filename = uf::string::replace( metadata.output, "%i", std::to_string(i) ); @@ -135,11 +141,8 @@ SAVE: { UF_MSG_DEBUG("Writing to " << filename << ": " << status); }); } -#if UF_BAKER_SAVE_MULTITHREAD - if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs ); -#else - for ( auto& job : jobs ) job(); -#endif + uf::thread::execute( tasks ); + UF_MSG_DEBUG("Baked."); metadata.initialized.map = true; diff --git a/ext/behaviors/hands/behavior.cpp b/ext/behaviors/hands/behavior.cpp deleted file mode 100644 index 1fae550d..00000000 --- a/ext/behaviors/hands/behavior.cpp +++ /dev/null @@ -1,525 +0,0 @@ -#include -#if UF_USE_OPENVR -#include "behavior.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace { - struct { - uf::Object* left; - uf::Object* right; - } hands, lines, lights; -} - -UF_BEHAVIOR_REGISTER_CPP(ext::PlayerHandBehavior) -UF_BEHAVIOR_TRAITS_CPP(ext::PlayerHandBehavior, ticks = true, renders = true, multithread = false) -#define this (&self) -void ext::PlayerHandBehavior::initialize( uf::Object& self ) { -#if UF_USE_OPENVR - uf::Serializer& metadata = this->getComponent(); - { - ::hands.left = (uf::Object*) &uf::instantiator::instantiate("Object"); - ::hands.right = (uf::Object*) &uf::instantiator::instantiate("Object"); - - ::lines.left = (uf::Object*) &uf::instantiator::instantiate("Object"); - ::lines.right = (uf::Object*) &uf::instantiator::instantiate("Object"); - - this->addChild(::hands.left); - this->addChild(::hands.right); - - ::hands.left->addChild(::lines.left); - ::hands.right->addChild(::lines.right); - } - { - bool loaded = true; - for ( auto it = metadata["hands"].begin(); it != metadata["hands"].end(); ++it ) { - uf::stl::string key = it.key(); - if ( !ext::openvr::requestRenderModel(metadata["hands"][key]["controller"]["model"].as()) ) loaded = false; - } - if ( !loaded ) { - this->addHook( "VR:Model.Loaded", [&](pod::payloads::assetLoad& payload){ - uf::stl::string name = payload.filename; // json["name"].as(); - uf::stl::string side = ""; - if ( name == metadata["hands"]["left"]["controller"]["model"].as() ) { - side = "left"; - } else if ( name == metadata["hands"]["right"]["controller"]["model"].as() ) { - side = "right"; - }; - if ( side == "" ) return; - - uf::Object& hand = *(side == "left" ? ::hands.left : ::hands.right); - uf::Object& line = *(side == "left" ? ::lines.left : ::lines.right); - { - uf::Graphic& graphic = (hand.getComponent() = ext::openvr::getRenderModel( name )); - - graphic.process = true; - - graphic.descriptor.frontFace = uf::renderer::enums::Face::CCW; - graphic.material.attachShader(uf::io::root+"/shaders/base/base.vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader(uf::io::root+"/shaders/base/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); - - uf::instantiator::bind( "EntityBehavior", hand ); - uf::instantiator::bind( "ObjectBehavior", hand ); - hand.initialize(); - } - if ( metadata["hands"][side]["pointer"]["length"].as() > 0 ) { - // line.addAlias(); - - pod::Transform<>& transform = line.getComponent>(); - transform.orientation = uf::quaternion::axisAngle( - { - metadata["hands"][side]["pointer"]["orientation"]["axis"][0].as(), - metadata["hands"][side]["pointer"]["orientation"]["axis"][1].as(), - metadata["hands"][side]["pointer"]["orientation"]["axis"][2].as() - }, - metadata["hands"][side]["pointer"]["orientation"]["angle"].as() * 3.14159f / 180.0f - ); - transform.position = { - metadata["hands"][side]["pointer"]["offset"][0].as(), - metadata["hands"][side]["pointer"]["offset"][1].as(), - metadata["hands"][side]["pointer"]["offset"][2].as() - }; - - auto& mesh = line.getComponent(); - auto& graphic = line.getComponent(); - - mesh.vertices = { - { {0.0f, 0.0f, 0.0f} }, - { {0.0f, 0.0f, metadata["hands"][side]["pointer"]["length"].as()} }, - }; - graphic.initialize(); - graphic.initializeMesh(mesh); - - graphic.material.attachShader(uf::io::root+"/shaders/line/base.vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader(uf::io::root+"/shaders/line/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); - graphic.descriptor.topology = uf::renderer::enums::PrimitiveTopology::LINE_STRIP; - graphic.descriptor.fill = uf::renderer::enums::PolygonMode::LINE; - graphic.descriptor.lineWidth = metadata["hands"][side]["pointer"]["width"].as(); - - line.initialize(); - } - if ( metadata["hands"][side]["light"]["should"].as() ){ - auto& child = hand.loadChild("/light.json", false); - if (side == "left" ) - lights.left = &child; - else - lights.right = &child; - - auto& json = metadata["hands"][side]["light"]; - auto& light = side == "left" ? *lights.left : *lights.right; - - auto& metadata = light.getComponent(); - if ( !ext::json::isNull( json["color"] ) ) metadata["light"]["color"] = json["color"]; - if ( !ext::json::isNull( json["radius"] ) ) metadata["light"]["radius"] = json["radius"]; - if ( !ext::json::isNull( json["power"] ) ) metadata["light"]["power"] = json["power"]; - if ( !ext::json::isNull( json["type"] ) ) metadata["light"]["type"] = json["type"]; - if ( !ext::json::isNull( json["shadows"] ) ) metadata["light"]["shadows"] = json["shadows"]; - metadata["lights"]["external update"] = true; - - // light.initialize(); - /* - auto* child = (uf::Object*) hand.findByUid(hand.loadChild("/light.json", false)); - if ( child ) { - if (side == "left" ) lights.left = child; else lights.right = child; - auto& json = metadata["hands"][side]["light"]; - auto& light = side == "left" ? *lights.left : *lights.right; - - auto& metadata = light.getComponent(); - if ( !ext::json::isNull( json["color"] ) ) metadata["light"]["color"] = json["color"]; - if ( !ext::json::isNull( json["radius"] ) ) metadata["light"]["radius"] = json["radius"]; - if ( !ext::json::isNull( json["power"] ) ) metadata["light"]["power"] = json["power"]; - if ( !ext::json::isNull( json["shadows"] ) ) metadata["light"]["shadows"] = json["shadows"]; - metadata["lights"]["external update"] = true; - - light.initialize(); - } - */ - } - - - }); - } - uf::stl::vector vHands = { ::hands.left, ::hands.right }; - for ( auto pointer : vHands ) { - auto& hand = *pointer; - hand.addHook("VR:Input.Digital", [&]( pod::payloads::vrInputDigital& payload){ - int_fast8_t side = &hand == hands.left ? -1 : 1; - if ( payload.side != side ) return; - - // fire mouse click - if ( payload.name == "click" ) { - pod::payloads::windowMouseClick pload; - pload.type = "window:Mouse.Click"; - pload.invoker = "vr"; - pload.mouse.position = uf::vector::encode( metadata["hands"][side]["cursor"]["position"], pload.mouse.position ); - pload.mouse.delta = {}; - pload.mouse.button = side == -1 ? "Right" : "Left"; - pload.mouse.state = payload.state; - - uf::hooks.call( pload.type, payload ); - } - }); - - hand.addHook("world:Collision.%UID%", [&]( pod::payloads::worldCollision& payload){ - uf::stl::string side = &hand == hands.left ? "left" : "right"; - - pod::payloads::vrHaptics pload; - pload.delay = 0; - pload.duration = uf::physics::time::delta; - pload.frequency = 1; - pload.amplitude = fmin(1.0f, 1000.0f * payload.depth); - plaod.side = &hand == hands.left ? -1 : 1;; - uf::hooks.call( "VR:Haptics." + side, payload ); - }); - - auto& transform = hand.getComponent>(); - auto& collider = hand.getComponent(); - - // auto* box = new uf::BoundingBox( transform.position, {0.25, 0.25, 0.25} ); - // box->getTransform().reference = &transform; - // collider.add(box); - } - } -#endif -} -void ext::PlayerHandBehavior::tick( uf::Object& self ) { -#if UF_USE_OPENVR - auto& scene = uf::scene::getCurrentScene(); - auto& controller = scene.getController(); - auto& controllerCamera = controller.getComponent(); - auto& controllerTransform = controller.getComponent>(); - auto& controllerCameraTransform = controllerCamera.getTransform(); - - auto& scene = uf::scene::getCurrentScene(); - auto& controller = scene.getController(); - auto& camera = controller.getComponent(); - - pod::Matrix4f playerModel = uf::matrix::identity(); { - auto& controller = this->getParent(); - auto& camera = controller.getComponent(); - pod::Matrix4f translation = uf::matrix::translate( uf::matrix::identity(), camera.getTransform().position + controller.getComponent>().position ); - pod::Matrix4f rotation = uf::quaternion::matrix( controller.getComponent>().orientation ); - playerModel = translation * rotation; - } - - { - pod::Transform<>& transform = ::hands.left->getComponent>(); - transform.position = ext::openvr::controllerPosition( vr::Controller_Hand::Hand_Left ); - transform.orientation = ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Left ); - transform.scale = { 1, 1, 1 }; - transform.reference = &controllerTransform; - - auto& collider = ::hands.left->getComponent(); - for ( auto* box : collider.getContainer() ) { - box->getTransform().position = transform.position + controllerTransform.position + controllerCameraTransform.position; - } - } - { - pod::Transform<>& transform = ::hands.right->getComponent>(); - transform.position = ext::openvr::controllerPosition( vr::Controller_Hand::Hand_Right ); - transform.orientation = ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Right ); - transform.scale = { 1, 1, 1 }; - transform.reference = &controllerTransform; - - auto& collider = ::hands.right->getComponent(); - for ( auto* box : collider.getContainer() ) { - box->getTransform().position = transform.position + controllerTransform.position + controllerCameraTransform.position; - } - } - { - pod::Transform<>& transform = ::lines.left->getComponent>(); - transform.position = ext::openvr::controllerPosition( vr::Controller_Hand::Hand_Left, true ); - transform.orientation = ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Left, true ); - transform.scale = { 1, 1, 1 }; - transform.reference = &controllerTransform; - - if ( lights.left ) { - if ( lights.left->getUid() == 0 ) { - lights.left->initialize(); - } - auto& light = *lights.left; - auto& lightTransform = light.getComponent>(); - lightTransform.position = controllerCameraTransform.position + controller.getComponent>().position + transform.position; - - auto& lightCamera = light.getComponent(); - pod::Matrix4f playerModel = uf::matrix::identity(); - pod::Matrix4f translation = uf::matrix::translate( uf::matrix::identity(), controllerCameraTransform.position + controllerTransform.position ); - pod::Matrix4f rotation = uf::quaternion::matrix( controllerTransform.orientation ); - playerModel = translation * rotation; - - pod::Matrix4f model = uf::matrix::inverse( playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Left, true ) ); - for ( size_t i = 0; i < 2; ++i ) lightCamera.setView( model, i ); - } - } - { - pod::Transform<>& transform = ::lines.right->getComponent>(); - transform.position = ext::openvr::controllerPosition( vr::Controller_Hand::Hand_Right, true ); - transform.orientation = ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Right, true ); - transform.scale = { 1, 1, 1 }; - transform.reference = &controllerTransform; - - if ( lights.right ) { - if ( lights.right->getUid() == 0 ) { - lights.right->initialize(); - } - auto& light = *lights.right; - auto& lightTransform = light.getComponent>(); - lightTransform.position = controllerCameraTransform.position + controllerTransform.position + transform.position; - - auto& lightCamera = light.getComponent(); - pod::Matrix4f playerModel = uf::matrix::identity(); - pod::Matrix4f translation = uf::matrix::translate( uf::matrix::identity(), controllerCameraTransform.position + controllerTransform.position ); - pod::Matrix4f rotation = uf::quaternion::matrix( controllerTransform.orientation ); - playerModel = translation * rotation; - - pod::Matrix4f model = uf::matrix::inverse( playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Right, true ) ); - for ( size_t i = 0; i < 2; ++i ) lightCamera.setView( model, i ); - } - } - // - if ( ::hands.left && ::hands.left->hasComponent() ) { - auto& graphic = ::hands.left->getComponent(); - auto& transform = ::hands.left->getComponent>(); - graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Left ); - pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Left, false ); - if ( graphic.initialized && graphic.material.hasShader("vertex") ) { - struct UniformDescriptor { - /*alignas(16)*/ pod::Matrix4f model; - }; - auto& shader = graphic.material.getShader("vertex"); - auto& uniforms = uniform.get(); - uniforms.model = model; - // uniforms.color = uf::vector::decode( metadata["hands"]["left"]["controller"]["color"], pod::Vector4f{1,1,1,1} ); - - if ( uf::renderer::currentRenderMode ) { - auto& renderMode = *uf::renderer::currentRenderMode; - if ( renderMode.getName() == "" ) uniforms.model = pod::Matrix4f{}; - } else uniforms.model = pod::Matrix4f{}; - - shader.updateUniform( "UBO", uniform ); - } - } - if ( ::hands.right && ::hands.right->hasComponent() ) { - auto& graphic = ::hands.right->getComponent(); - auto& transform = ::hands.right->getComponent>(); - graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Right ); - pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Right, false ); - if ( graphic.initialized && graphic.material.hasShader("vertex") ) { - struct UniformDescriptor { - /*alignas(16)*/ pod::Matrix4f model; - }; - auto& shader = graphic.material.getShader("vertex"); - auto& uniforms = uniform.get(); - uniforms.model = model; - // uniforms.color = uf::vector::decode( metadata["hands"]["right"]["controller"]["color"], pod::Vector4f{1,1,1,1} ); - - if ( uf::renderer::currentRenderMode ) { - auto& renderMode = *uf::renderer::currentRenderMode; - if ( renderMode.getName() == "" ) uniforms.model = pod::Matrix4f{}; - } else uniforms.model = pod::Matrix4f{}; - - shader.updateUniform( "UBO", uniform ); - } - } - if ( ::lines.left && ::lines.left->hasComponent() ) { - auto& graphic = ::lines.left->getComponent(); - auto& transform = ::lines.left->getComponent>(); - graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Left ); - pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Left, true ); - if ( graphic.initialized && graphic.material.hasShader("vertex") ) { - struct UniformDescriptor { - /*alignas(16)*/ pod::Matrix4f model; - }; - auto& shader = graphic.material.getShader("vertex"); - auto& uniforms = uniform.get(); - uniforms.model = model; - // uniforms.color = uf::vector::decode( metadata["hands"]["left"]["pointer"]["color"], pod::Vector4f{1,1,1,1} ); - - if ( uf::renderer::currentRenderMode ) { - auto& renderMode = *uf::renderer::currentRenderMode; - if ( renderMode.getName() == "" ) uniforms.model = pod::Matrix4f{}; - } else uniforms.model = pod::Matrix4f{}; - - shader.updateUniform( "UBO", uniform ); - } - } - if ( ::lines.right && ::lines.right->hasComponent() ) { - auto& graphic = ::lines.right->getComponent(); - auto& transform = ::lines.right->getComponent>(); - graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Right ); - pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Right, true ); - if ( graphic.initialized && graphic.material.hasShader("vertex") ) { - struct UniformDescriptor { - /*alignas(16)*/ pod::Matrix4f model; - }; - auto& shader = graphic.material.getShader("vertex"); - auto& uniforms = uniform.get(); - uniforms.model = model; - // uniforms.color = uf::vector::decode( metadata["hands"]["right"]["pointer"]["color"], pod::Vector4f{1,1,1,1} ); - - if ( uf::renderer::currentRenderMode ) { - auto& renderMode = *uf::renderer::currentRenderMode; - if ( renderMode.getName() == "" ) uniforms.model = pod::Matrix4f{}; - } else uniforms.model = pod::Matrix4f{}; - - shader.updateUniform( "UBO", uniform ); - } - } - // raytrace pointer / hand collision - { - uf::stl::vector handPointers = { ::hands.left, ::hands.right }; - for ( auto pointer : handPointers ) { auto& hand = *pointer; - uf::stl::string side = &hand == ::hands.left ? "left" : "right"; - if ( !ext::openvr::controllerActive( side == "left" ? vr::Controller_Hand::Hand_Left : vr::Controller_Hand::Hand_Right ) ) continue; - { - pod::Transform<>& transform = (side == "left" ? ::lines.left : ::lines.right)->getComponent>(); - struct { - pod::Vector3f origin; - pod::Vector3f direction; - } ray; - struct { - pod::Vector3f center; - pod::Vector3f normal; - } plane; - - transform = uf::transform::reorient( transform ); - ray.origin = transform.position; - ray.direction = transform.forward; - - pod::Transform<> gtransform; - pod::Matrix4f mvp; - uf::Serializer& cMetadata = controller.getComponent(); - if ( ext::json::isArray( cMetadata["overlay"]["position"] ) ) - gtransform.position = { - cMetadata["overlay"]["position"][0].as(), - cMetadata["overlay"]["position"][1].as(), - cMetadata["overlay"]["position"][2].as(), - }; - if ( ext::json::isArray( cMetadata["overlay"]["scale"] ) ) - gtransform.scale = { - cMetadata["overlay"]["scale"][0].as(), - cMetadata["overlay"]["scale"][1].as(), - cMetadata["overlay"]["scale"][2].as(), - }; - if ( ext::json::isArray( cMetadata["overlay"]["orientation"] ) ) - gtransform.orientation = { - cMetadata["overlay"]["orientation"][0].as(), - cMetadata["overlay"]["orientation"][1].as(), - cMetadata["overlay"]["orientation"][2].as(), - cMetadata["overlay"]["orientation"][3].as(), - }; - - plane.center = gtransform.position; - { - auto rotated = uf::quaternion::multiply( gtransform.orientation, pod::Vector4f{ 0, 0, 1, 1 } ); - plane.normal.x = rotated.x; - plane.normal.y = rotated.y; - plane.normal.z = rotated.z; - plane.normal = uf::vector::normalize( plane.normal ); - } - - float denom = uf::vector::dot(plane.normal, ray.direction); - if (abs(denom) > 0.0001f) { - float t = uf::vector::dot( uf::vector::subtract(plane.center, ray.origin), plane.normal ) / denom; - if ( t >= 0 ) { - pod::Vector3f hit = ray.origin + (ray.direction * t); - pod::Vector3f translated = uf::matrix::multiply( uf::matrix::inverse( uf::matrix::scale( uf::matrix::identity(), gtransform.scale ) ), uf::vector::subtract( plane.center, hit ) ); - { - auto& metadata = this->getComponent(); - cMetadata["overlay"]["cursor"]["type"] = "vr"; - cMetadata["overlay"]["cursor"]["position"][0] = translated.x; - cMetadata["overlay"]["cursor"]["position"][1] = translated.y; - cMetadata["overlay"]["cursor"]["position"][2] = translated.z; - - metadata["hands"][side]["cursor"] = cMetadata["overlay"]["cursor"]; - } - } - } - } - } - } -#endif -} - -void ext::PlayerHandBehavior::render( uf::Object& self ){ -#if UF_USE_OPENVR - uf::Serializer& metadata = this->getComponent(); - auto& scene = uf::scene::getCurrentScene(); - auto& controller = scene.getController(); - auto& camera = controller.getComponent(); - - if ( ::hands.left && ::hands.left->hasComponent() ) { - auto& graphic = ::hands.left->getComponent(); - auto& transform = ::hands.left->getComponent>(); - graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Left ); - pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Left, false ); - if ( graphic.initialized && graphic.material.hasShader("vertex") ) { - auto& shader = graphic.material.getShader("vertex"); - auto& uniform = shader.getUniform("Camera"); - auto& uniforms = uniform.get(); - uniforms = camera.data().viewport; - shader.updateUniform("Camera", uniform); - } - } - if ( ::hands.right && ::hands.right->hasComponent() ) { - auto& graphic = ::hands.right->getComponent(); - auto& transform = ::hands.right->getComponent>(); - graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Right ); - pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Right, false ); - if ( graphic.initialized && graphic.material.hasShader("vertex") ) { - auto& shader = graphic.material.getShader("vertex"); - auto& uniform = shader.getUniform("Camera"); - auto& uniforms = uniform.get(); - uniforms = camera.data().viewport; - shader.updateUniform("Camera", uniform); - } - } - if ( ::lines.left && ::lines.left->hasComponent() ) { - auto& graphic = ::lines.left->getComponent(); - auto& transform = ::lines.left->getComponent>(); - graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Left ); - pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Left, true ); - if ( graphic.initialized && graphic.material.hasShader("vertex") ) { - auto& shader = graphic.material.getShader("vertex"); - auto& uniform = shader.getUniform("Camera"); - auto& uniforms = uniform.get(); - uniforms = camera.data().viewport; - shader.updateUniform("Camera", uniform); - } - } - if ( ::lines.right && ::lines.right->hasComponent() ) { - auto& graphic = ::lines.right->getComponent(); - auto& transform = ::lines.right->getComponent>(); - graphic.process = ext::openvr::controllerActive( vr::Controller_Hand::Hand_Right ); - pod::Matrix4f model = playerModel * ext::openvr::controllerModelMatrix( vr::Controller_Hand::Hand_Right, true ); - if ( graphic.initialized && graphic.material.hasShader("vertex") ) { - auto& shader = graphic.material.getShader("vertex"); - auto& uniform = shader.getUniform("Camera"); - auto& uniforms = uniform.get(); - uniforms = camera.data().viewport; - shader.updateUniform("Camera", uniform); - } - } -#endif -} -void ext::PlayerHandBehavior::destroy( uf::Object& self ){} -void ext::PlayerHandBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ) {} -void ext::PlayerHandBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer& serializer ) {} -#undef this -#endif \ No newline at end of file diff --git a/ext/behaviors/hands/behavior.h b/ext/behaviors/hands/behavior.h deleted file mode 100644 index 0740af04..00000000 --- a/ext/behaviors/hands/behavior.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace ext { - namespace PlayerHandBehavior { - UF_BEHAVIOR_DEFINE_TYPE(); - EXT_BEHAVIOR_DEFINE_TRAITS(); - EXT_BEHAVIOR_DEFINE_FUNCTIONS(); - UF_BEHAVIOR_DEFINE_METADATA( - - ); - } -} \ No newline at end of file diff --git a/ext/behaviors/light/behavior.cpp b/ext/behaviors/light/behavior.cpp index 89575fa9..aa8fc7f1 100644 --- a/ext/behaviors/light/behavior.cpp +++ b/ext/behaviors/light/behavior.cpp @@ -65,7 +65,7 @@ void ext::LightBehavior::initialize( uf::Object& self ) { auto& renderMode = this->getComponent(); renderMode.metadata.type = "depth"; renderMode.metadata.pipeline = "depth"; - if ( uf::renderer::settings::experimental::culling ) { + if ( uf::renderer::settings::pipelines::culling ) { renderMode.metadata.pipelines.emplace_back("culling"); } renderMode.metadata.json["descriptor"]["depth bias"] = metadataJson["light"]["bias"]; @@ -93,10 +93,10 @@ void ext::LightBehavior::initialize( uf::Object& self ) { camera.update(true); uf::stl::string name = "RT:" + std::to_string((int) this->getUid()); - uf::renderer::addRenderMode( &renderMode, name ); renderMode.blitter.process = false; renderMode.width = size.x; renderMode.height = size.y; + uf::renderer::addRenderMode( &renderMode, name ); } this->addHook( "object:Serialize.%UID%", [&](ext::json::Value& json){ metadata.serialize(self, metadataJson); }); @@ -173,36 +173,43 @@ void ext::LightBehavior::tick( uf::Object& self ) { } #endif // limit updating our shadow map +#if UF_USE_VULKAN if ( this->hasComponent() ) { - auto& renderMode = this->getComponent(); // enable renderer every X seconds if ( metadata.renderer.limiter > 0 ) { if ( metadata.renderer.timer > metadata.renderer.limiter ) { metadata.renderer.timer = 0; renderMode.execute = true; + renderMode.metadata.limiter.execute = true; } else { metadata.renderer.timer = metadata.renderer.timer + uf::physics::time::delta; renderMode.execute = false; + renderMode.metadata.limiter.execute = false; } } else { // round robin, enable if it's the light's current turn if ( metadata.renderer.mode == "round robin" ) { - if ( ::roundRobin.current < ::roundRobin.lights.size() ) + if ( ::roundRobin.current < ::roundRobin.lights.size() ) { renderMode.execute = ::roundRobin.lights[::roundRobin.current] == this; + renderMode.metadata.limiter.execute = ::roundRobin.lights[::roundRobin.current] == this; + } // render only if the light is used } else if ( metadata.renderer.mode == "occlusion" ) { renderMode.execute = metadata.renderer.rendered; + renderMode.metadata.limiter.execute = metadata.renderer.rendered; // light baking, but sadly re-bakes every time the command buffer is recorded } else if ( metadata.renderer.mode == "once" ) { renderMode.execute = !metadata.renderer.rendered; + renderMode.metadata.limiter.execute = !metadata.renderer.rendered; + metadata.renderer.rendered = true; } else if ( metadata.renderer.mode == "in-range" ) { metadata.renderer.rendered = false; } } // skip if we're handling the camera view matrix position ourselves - if ( renderMode.execute && !metadata.renderer.external ) { + if ( /*renderMode.execute*/ renderMode.metadata.limiter.execute && !metadata.renderer.external ) { auto& camera = this->getComponent(); // omni light if ( metadata.shadows && std::abs(metadata.type) == 1 ) { @@ -217,6 +224,7 @@ void ext::LightBehavior::tick( uf::Object& self ) { } } } +#endif #if UF_ENTITY_METADATA_USE_JSON metadata.serialize(self, metadataJson); #endif diff --git a/ext/behaviors/player/behavior.cpp b/ext/behaviors/player/behavior.cpp index e144ec8e..11f9567f 100644 --- a/ext/behaviors/player/behavior.cpp +++ b/ext/behaviors/player/behavior.cpp @@ -71,6 +71,7 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { // sloppy metadata.mouse.sensitivity = uf::vector::decode( ext::config["window"]["cursor"]["sensitivity"], metadata.mouse.sensitivity ); + metadata.mouse.smoothing = uf::vector::decode( ext::config["window"]["cursor"]["smoothing"], metadata.mouse.smoothing ); this->addHook( "window:Mouse.CursorVisibility", [&](pod::payloads::windowMouseCursorVisibility& payload){ metadata.system.control = !payload.mouse.visible; @@ -78,28 +79,39 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { // Rotate Camera this->addHook( "window:Mouse.Moved", [&](pod::payloads::windowMouseMoved& payload ){ - pod::Vector2 relta = { (float) metadata.mouse.sensitivity.x * payload.mouse.delta.x / payload.window.size.x, (float) metadata.mouse.sensitivity.y * payload.mouse.delta.y / payload.window.size.y }; - // pod::Vector2 relta = { (float) metadata.mouse.sensitivity.x * payload.mouse.delta.x * uf::physics::time::delta, (float) metadata.mouse.sensitivity.y * payload.mouse.delta.y * uf::physics::time::delta }; + const pod::Vector2ui deadZone{6, 6}; + + pod::Vector2f delta = { + (float) metadata.mouse.sensitivity.x * (abs(payload.mouse.delta.x) < deadZone.x ? 0 : payload.mouse.delta.x) / payload.window.size.x, + (float) metadata.mouse.sensitivity.y * (abs(payload.mouse.delta.y) < deadZone.y ? 0 : payload.mouse.delta.y) / payload.window.size.y + }; + + // pod::Vector2f delta = metadata.mouse.sensitivity * payload.mouse.delta / payload.window.size; if ( (payload.mouse.delta.x == 0 && payload.mouse.delta.y == 0) || !metadata.system.control ) return; - // relta *= uf::physics::time::delta; - - if ( payload.mouse.delta.x != 0 ) { + metadata.camera.queued += delta; + + // UF_MSG_DEBUG( "Window size: " << uf::vector::toString( payload.window.size )); + // UF_MSG_DEBUG( "Delta: " << uf::vector::toString( payload.mouse.delta )); + // UF_MSG_DEBUG( "Sensitivity: " << uf::vector::toString( metadata.mouse.sensitivity ) ); + /* + if ( relta.x != 0 ) { if ( metadata.camera.invert.x ) relta.x *= -1; metadata.camera.limit.current.x += relta.x; if ( metadata.camera.limit.current.x != metadata.camera.limit.current.x || ( metadata.camera.limit.current.x < metadata.camera.limit.max.x && metadata.camera.limit.current.x > metadata.camera.limit.min.x ) ) { - if ( collider.body ) uf::physics::impl::applyRotation( collider, transform.up, relta.x ); else - uf::transform::rotate( transform, transform.up, relta.x ); + if ( collider.body ) uf::physics::impl::applyRotation( collider, transform.up, relta.x ); else + uf::transform::rotate( transform, transform.up, relta.x ); } else metadata.camera.limit.current.x -= relta.x; } - if ( payload.mouse.delta.y != 0 ) { + if ( relta.y != 0 ) { if ( metadata.camera.invert.y ) relta.y *= -1; metadata.camera.limit.current.y += relta.y; - if ( metadata.camera.limit.current.y != metadata.camera.limit.current.y || ( metadata.camera.limit.current.y < metadata.camera.limit.max.y && metadata.camera.limit.current.y > metadata.camera.limit.min.y ) ) { - // if ( collider.body && !collider.shared ) uf::physics::impl::applyRotation( collider, cameraTransform.right, relta.y ); else + if ( metadata.camera.limit.current.y != metadata.camera.limit.current.y || ( metadata.camera.limit.current.y < metadata.camera.limit.max.y && metadata.camera.limit.current.y > metadata.camera.limit.min.y ) ) { + // if ( collider.body && !collider.shared ) uf::physics::impl::applyRotation( collider, cameraTransform.right, relta.y ); else uf::transform::rotate( cameraTransform, cameraTransform.right, relta.y ); } else metadata.camera.limit.current.y -= relta.y; } camera.update(true); + */ }); #if UF_USE_DISCORD @@ -369,7 +381,28 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { metadata.system.crouching = false; } - if ( keys.lookRight ^ keys.lookLeft ) { + if ( metadata.camera.queued.x != 0 || metadata.camera.queued.y != 0 ) { + auto lookDelta = metadata.camera.queued; + if ( abs(lookDelta.x) > uf::physics::time::delta / metadata.mouse.smoothing.x ) lookDelta.x *= uf::physics::time::delta * metadata.mouse.smoothing.x; + if ( abs(lookDelta.y) > uf::physics::time::delta / metadata.mouse.smoothing.y ) lookDelta.y *= uf::physics::time::delta * metadata.mouse.smoothing.y; + metadata.camera.queued -= lookDelta; + if ( lookDelta.x != 0 ) { + if ( metadata.camera.invert.x ) lookDelta.x *= -1; + metadata.camera.limit.current.x += lookDelta.x; + if ( metadata.camera.limit.current.x != metadata.camera.limit.current.x || ( metadata.camera.limit.current.x < metadata.camera.limit.max.x && metadata.camera.limit.current.x > metadata.camera.limit.min.x ) ) { + if ( collider.body ) uf::physics::impl::applyRotation( collider, transform.up, lookDelta.x ); else + uf::transform::rotate( transform, transform.up, lookDelta.x ); + } else metadata.camera.limit.current.x -= lookDelta.x; + } + if ( lookDelta.y != 0 ) { + if ( metadata.camera.invert.y ) lookDelta.y *= -1; + metadata.camera.limit.current.y += lookDelta.y; + if ( metadata.camera.limit.current.y != metadata.camera.limit.current.y || ( metadata.camera.limit.current.y < metadata.camera.limit.max.y && metadata.camera.limit.current.y > metadata.camera.limit.min.y ) ) { + // if ( collider.body && !collider.shared ) uf::physics::impl::applyRotation( collider, cameraTransform.right, lookDelta.y ); else + uf::transform::rotate( cameraTransform, cameraTransform.right, lookDelta.y ); + } else metadata.camera.limit.current.y -= lookDelta.y; + } + } else if ( keys.lookRight ^ keys.lookLeft ) { if ( collider.body ) uf::physics::impl::applyRotation( collider, transform.up, speed.rotate * (keys.lookRight ? 1 : -1) ); else uf::transform::rotate( transform, transform.up, speed.rotate * (keys.lookRight ? 1 : -1) ); } diff --git a/ext/behaviors/player/behavior.h b/ext/behaviors/player/behavior.h index 10a6df58..f1c6083e 100644 --- a/ext/behaviors/player/behavior.h +++ b/ext/behaviors/player/behavior.h @@ -35,9 +35,11 @@ namespace ext { pod::Vector3f max = {NAN, NAN, NAN}; } limit; pod::Vector3t invert; + pod::Vector2f queued; } camera; struct { - pod::Vector2f sensitivity; + pod::Vector2f sensitivity = {1,1}; + pod::Vector2f smoothing = {10,10}; } mouse; struct { struct { diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index 4d1226a6..4f44cfd9 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -226,6 +226,12 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { } } } + /* Mark as ready for multithreading */ { + TIMER(1, uf::inputs::kbm::states::M && ) { + uf::renderer::settings::experimental::dedicatedThread = !uf::renderer::settings::experimental::dedicatedThread; + UF_MSG_DEBUG("Toggling multithreaded rendering..."); + } + } #endif #if 0 /* Print World Tree */ { @@ -416,7 +422,10 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { bool hasRT = entity->hasComponent(); if ( hasRT ) { auto& renderMode = entity->getComponent(); - if ( metadata.renderer.mode == "in-range" ) renderMode.execute = false; + if ( metadata.renderer.mode == "in-range" ) { + renderMode.execute = false; + renderMode.metadata.limiter.execute = false; + } } if ( metadata.power <= 0 ) continue; auto flatten = uf::transform::flatten( entity->getComponent>() ); @@ -468,7 +477,10 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { auto& lightMetadata = entity->getComponent(); lightMetadata.renderer.rendered = true; // activate our shadow mapper if it's range-basedd - if ( lightMetadata.renderer.mode == "in-range" && shadowUpdateThreshold-- > 0 ) renderMode.execute = true; + if ( lightMetadata.renderer.mode == "in-range" && shadowUpdateThreshold-- > 0 ) { + renderMode.execute = true; + renderMode.metadata.limiter.execute = true; + } // if point light, and combining is requested if ( metadata.shadow.experimentalMode > 0 && renderMode.renderTarget.views == 6 ) { int32_t index = -1; @@ -531,7 +543,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { uf::graph::storage.buffers.light.update( (const void*) uf::graph::storage.lights.data(), uf::graph::storage.lights.size() * sizeof(pod::Light) ); } #endif - /* Update lights */ if ( !uf::renderer::settings::experimental::vxgi ) { + /* Update lights */ if ( !uf::renderer::settings::pipelines::vxgi ) { ext::ExtSceneBehavior::bindBuffers( *this ); } } @@ -638,7 +650,7 @@ void ext::ExtSceneBehavior::Metadata::deserialize( uf::Object& self, uf::Seriali } #endif - if ( uf::renderer::settings::experimental::bloom ) { + if ( uf::renderer::settings::pipelines::bloom ) { auto& renderMode = uf::renderer::getRenderMode("", true); auto& blitter = *renderMode.getBlitters().front(); auto& shader = blitter.material.getShader("compute", "bloom"); @@ -778,7 +790,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string textures3D.emplace_back().aliasTexture(sceneTextures.noise); // attach VXGI voxels - if ( uf::renderer::settings::experimental::vxgi ) { + if ( uf::renderer::settings::pipelines::vxgi ) { for ( auto& t : sceneTextures.voxels.id ) textures3D.emplace_back().aliasTexture(t); for ( auto& t : sceneTextures.voxels.normal ) textures3D.emplace_back().aliasTexture(t); for ( auto& t : sceneTextures.voxels.uv ) textures3D.emplace_back().aliasTexture(t); diff --git a/ext/behaviors/voxelizer/behavior.cpp b/ext/behaviors/voxelizer/behavior.cpp index 81b001a2..c264bdd6 100644 --- a/ext/behaviors/voxelizer/behavior.cpp +++ b/ext/behaviors/voxelizer/behavior.cpp @@ -110,7 +110,7 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { renderMode.metadata.type = "vxgi"; renderMode.metadata.pipeline = "vxgi"; renderMode.metadata.pipelines.emplace_back("vxgi"); - if ( uf::renderer::settings::experimental::culling ) { + if ( uf::renderer::settings::pipelines::culling ) { renderMode.metadata.pipelines.emplace_back("culling"); } renderMode.metadata.samples = 1; @@ -126,7 +126,7 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { if ( renderMode.metadata.samples > 1 ) { computeShaderFilename = uf::string::replace( computeShaderFilename, "frag", "msaa.frag" ); } - if ( uf::renderer::settings::experimental::deferredSampling ) { + if ( uf::renderer::settings::invariant::deferredSampling ) { computeShaderFilename = uf::string::replace( computeShaderFilename, "frag", "deferredSampling.frag" ); } renderMode.metadata.json["shaders"]["compute"] = computeShaderFilename; @@ -253,6 +253,7 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { } } ); #endif + #if 0 auto& deferredRenderMode = uf::renderer::getRenderMode("", true); deferredRenderMode.bindCallback( renderMode.CALLBACK_BEGIN, [&]( VkCommandBuffer commandBuffer ){ VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; @@ -330,6 +331,7 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { ); } }); + #endif } #endif } diff --git a/ext/gui/behavior.cpp b/ext/gui/behavior.cpp index dcbad543..1843ca1f 100644 --- a/ext/gui/behavior.cpp +++ b/ext/gui/behavior.cpp @@ -33,6 +33,8 @@ #include #include +#define EXT_COLOR_FLOATS 1 + namespace { #if UF_USE_FREETYPE struct { @@ -40,7 +42,6 @@ namespace { uf::stl::unordered_map> cache; } glyphs; #endif - uf::stl::string defaultRenderMode = "Gui"; uf::Serializer defaultSettings; @@ -65,7 +66,26 @@ namespace { "clickable", "hoverable" }; + + struct /*UF_API*/ GuiMesh { + pod::Vector3f position; + pod::Vector2f uv; + #if EXT_COLOR_FLOATS + pod::Vector4f color; + #else + pod::ColorRgba color; + #endif + + static uf::stl::vector descriptor; + }; } + +UF_VERTEX_DESCRIPTOR(GuiMesh, + UF_VERTEX_DESCRIPTION(GuiMesh, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(GuiMesh, R32G32_SFLOAT, uv) + UF_VERTEX_DESCRIPTION(GuiMesh, R8G8B8A8_UNORM, color) +) + uf::stl::vector ext::Gui::generateGlyphs( const uf::stl::string& _string ) { uf::stl::vector gs; #if UF_USE_FREETYPE @@ -324,16 +344,28 @@ void ext::Gui::load( const uf::Image& image ) { auto& texture = graphic.material.textures.emplace_back(); texture.loadFromImage( image ); -// auto& mesh = this->getComponent(); auto& transform = this->getComponent>(); - uf::stl::vector vertices = { - { pod::Vector3f{ 1.0f, -1.0f, 0.0f}, pod::Vector2f{1.0f, 0.0f}, metadata.color }, - { pod::Vector3f{-1.0f, -1.0f, 0.0f}, pod::Vector2f{0.0f, 0.0f}, metadata.color }, - { pod::Vector3f{-1.0f, 1.0f, 0.0f}, pod::Vector2f{0.0f, 1.0f}, metadata.color }, +#if 0 + uf::stl::vector<::GuiMesh> vertices = { +#else + auto& vertices = this->getComponent>(); +#if EXT_COLOR_FLOATS + auto& color = metadata.color; +#else + pod::ColorRgba color = { metadata.color[0] * 255, metadata.color[1] * 255, metadata.color[2] * 255, metadata.color[3] * 255 }; +#endif + vertices = { +#endif + { pod::Vector3f{ 1.0f, -1.0f, 0.0f}, pod::Vector2f{1.0f, 0.0f}, color }, + { pod::Vector3f{-1.0f, -1.0f, 0.0f}, pod::Vector2f{0.0f, 0.0f}, color }, + { pod::Vector3f{-1.0f, 1.0f, 0.0f}, pod::Vector2f{0.0f, 1.0f}, color }, - { pod::Vector3f{-1.0f, 1.0f, 0.0f}, pod::Vector2f{0.0f, 1.0f}, metadata.color }, - { pod::Vector3f{ 1.0f, 1.0f, 0.0f}, pod::Vector2f{1.0f, 1.0f}, metadata.color }, - { pod::Vector3f{ 1.0f, -1.0f, 0.0f}, pod::Vector2f{1.0f, 0.0f}, metadata.color }, + { pod::Vector3f{-1.0f, 1.0f, 0.0f}, pod::Vector2f{0.0f, 1.0f}, color }, + { pod::Vector3f{ 1.0f, 1.0f, 0.0f}, pod::Vector2f{1.0f, 1.0f}, color }, + { pod::Vector3f{ 1.0f, -1.0f, 0.0f}, pod::Vector2f{1.0f, 0.0f}, color }, + }; + uf::stl::vector indices = { + 0, 1, 2, 3, 4, 5 }; pod::Vector2f raidou = { 1, 1 }; @@ -350,16 +382,23 @@ void ext::Gui::load( const uf::Image& image ) { } if ( metadataJson["world"].as() ) { - + // metadataJson["gui layer"] = false; + } else { + #if UF_USE_OPENGL + if ( ext::json::isNull(metadataJson["cull mode"]) ) metadataJson["cull mode"] = "front"; + #else + if ( uf::matrix::reverseInfiniteProjection ) { + // metadata.depth = -metadata.depth; + } else { + } + if ( metadataJson["flip uv"].as() ) for ( auto& v : vertices ) v.uv.y = 1 - v.uv.y; + #endif + if ( metadata.depth != 0.0f ) for ( auto& v : vertices ) v.position.z = metadata.depth; + else for ( auto& v : vertices ) v.position.z = 0; } graphic.descriptor.parse( metadataJson ); - if ( uf::matrix::reverseInfiniteProjection ) { - } else { - metadata.depth = -metadata.depth; - } - if ( metadataJson["flip uv"].as() ) for ( auto& v : vertices ) v.uv.y = 1 - v.uv.y; - if ( metadata.depth != 0.0f ) for ( auto& v : vertices ) v.position.z = metadata.depth; + if ( metadataJson["scaling"].is() ) { uf::stl::string mode = metadataJson["scaling"].as(); @@ -376,6 +415,7 @@ void ext::Gui::load( const uf::Image& image ) { transform.scale.x = raidou.x; transform.scale.y = raidou.y; } +#if 1 if ( metadataJson["layer"].is() ) { graphic.initialize( metadataJson["layer"].as() ); } else if ( !ext::json::isNull( metadataJson["gui layer"] ) && !metadataJson["gui layer"].as() ) { @@ -385,11 +425,13 @@ void ext::Gui::load( const uf::Image& image ) { } else { graphic.initialize( ::defaultRenderMode ); } +#endif +// graphic.initialize(); auto& mesh = this->getComponent(); - mesh.bind(); + mesh.bind<::GuiMesh>(); mesh.insertVertices( vertices ); - +// mesh.insertIndices( indices ); graphic.initializeMesh( mesh ); struct { @@ -653,21 +695,31 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { auto& transform = this->getComponent>(); transform.scale.x = scale; transform.scale.y = scale; - - uf::stl::vector vertices; + #if 0 + uf::stl::vector<::GuiMesh> vertices; + #else + auto& vertices = this->getComponent>(); + #endif + uf::stl::vector indices; vertices.reserve( glyphs.size() * 6 ); - + indices.reserve( glyphs.size() * 6 ); + for ( auto& g : glyphs ) { auto glyphKey = std::to_string((uint64_t) g.code) + ";"+key; auto& glyph = ::glyphs.cache[font][glyphKey]; auto hash = glyphHashMap[glyphKey]; + #if EXT_COLOR_FLOATS + auto& color = g.color; + #else + pod::ColorRgba color = { g.color[0] * 255, g.color[1] * 255, g.color[2] * 255, g.color[3] * 255 }; + #endif // add vertices - vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 0.0f }, hash ), g.color}); - vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 1.0f }, hash ), g.color}); - vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x + g.box.w, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 1.0f }, hash ), g.color}); - vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 0.0f }, hash ), g.color}); - vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x + g.box.w, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 1.0f }, hash ), g.color}); - vertices.emplace_back(pod::Vertex_3F2F3F{pod::Vector3f{ g.box.x + g.box.w, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 0.0f }, hash ), g.color}); + vertices.emplace_back(::GuiMesh{pod::Vector3f{ g.box.x, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 0.0f }, hash ), color}); indices.emplace_back( indices.size() ); + vertices.emplace_back(::GuiMesh{pod::Vector3f{ g.box.x, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 1.0f }, hash ), color}); indices.emplace_back( indices.size() ); + vertices.emplace_back(::GuiMesh{pod::Vector3f{ g.box.x + g.box.w, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 1.0f }, hash ), color}); indices.emplace_back( indices.size() ); + vertices.emplace_back(::GuiMesh{pod::Vector3f{ g.box.x, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 0.0f, 0.0f }, hash ), color}); indices.emplace_back( indices.size() ); + vertices.emplace_back(::GuiMesh{pod::Vector3f{ g.box.x + g.box.w, g.box.y , 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 1.0f }, hash ), color}); indices.emplace_back( indices.size() ); + vertices.emplace_back(::GuiMesh{pod::Vector3f{ g.box.x + g.box.w, g.box.y + g.box.h, 0 }, atlas.mapUv( pod::Vector2f{ 1.0f, 0.0f }, hash ), color}); indices.emplace_back( indices.size() ); } for ( size_t i = 0; i < vertices.size(); i += 6 ) { for ( size_t j = 0; j < 6; ++j ) { @@ -677,8 +729,9 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { vertex.position.z = metadata.depth; } } - mesh.bind(); + mesh.bind<::GuiMesh>(); mesh.insertVertices( vertices ); + // mesh.insertIndices( indices ); auto& texture = graphic.material.textures.emplace_back(); texture.loadFromImage( atlas.getAtlas() ); @@ -746,17 +799,20 @@ void ext::GuiBehavior::tick( uf::Object& self ) { auto& graphic = this->getComponent(); auto& controller = scene.getController(); auto& camera = controller.getComponent(); - auto& transform = this->getComponent>(); + auto transform = this->getComponent>(); if ( !graphic.initialized ) return; bool isGlyph = this->hasComponent(); #if UF_USE_OPENGL - auto model = transform.model; + if ( metadata.mode == 0 ) { + transform.position.y = -transform.position.y; + } + auto model = uf::transform::model( transform ); auto& shader = graphic.material.getShader("vertex"); pod::Uniform uniform; if ( metadata.mode == 1 ) { - uniform.modelView = transform.model; + uniform.modelView = model; uniform.projection = uf::matrix::identity(); } else if ( metadata.mode == 2 ) { auto& scene = uf::scene::getCurrentScene(); @@ -784,6 +840,7 @@ void ext::GuiBehavior::tick( uf::Object& self ) { shader.updateUniform( "UBO", (const void*) &uniform, sizeof(uniform) ); pod::Uniform* uniformBuffer = (pod::Uniform*) shader.device->getBuffer(shader.getUniformBuffer("UBO").descriptor.buffer); + #if 0 UF_MSG_DEBUG( "buffer: " << uniformBuffer ); UF_MSG_DEBUG( "modelView: " << &uniformBuffer->modelView << " " << uf::matrix::toString( uniformBuffer->modelView ) ); @@ -949,7 +1006,91 @@ void ext::GuiBehavior::tick( uf::Object& self ) { metadata.box.max.y = max.y; } } -void ext::GuiBehavior::render( uf::Object& self ){} +void ext::GuiBehavior::render( uf::Object& self ){ +#if 0 && UF_USE_OPENGL + if ( !this->hasComponent() ) return; + if ( ext::opengl::currentRenderMode->getName() != "Gui" ) return; + + auto& metadata = this->getComponent(); + auto& metadataJson = this->getComponent(); + auto& scene = uf::scene::getCurrentScene(); + auto& graphic = this->getComponent(); + auto& controller = scene.getController(); + auto& camera = controller.getComponent(); + auto& transform = this->getComponent>(); + if ( !graphic.initialized ) return; + auto& shader = graphic.material.getShader("vertex"); + auto& mesh = this->getComponent(); + + bool isGlyph = this->hasComponent(); + + auto model = transform.model; + auto projection = uf::matrix::identity(); + pod::Uniform uniform; + + if ( metadata.mode == 1 ) { + uniform.modelView = transform.model; + uniform.projection = uf::matrix::identity(); + } else if ( metadata.mode == 2 ) { + auto& scene = uf::scene::getCurrentScene(); + auto& controller = scene.getController(); + auto& camera = controller.getComponent(); + uniform.modelView = camera.getView() * uf::transform::model( transform ); + uniform.projection = camera.getProjection(); + } else if ( metadata.mode == 3 ) { + pod::Transform<> flatten = uf::transform::flatten( transform ); + uniform.modelView = + uf::matrix::translate( uf::matrix::identity(), flatten.position ) * + uf::matrix::scale( uf::matrix::identity(), flatten.scale ) * + uf::quaternion::matrix( flatten.orientation ) * + flatten.model; + uniform.projection = camera.getProjection(); + } else { + pod::Transform<> flatten = uf::transform::flatten( transform ); + uniform.modelView = + uf::matrix::translate( uf::matrix::identity(), flatten.position ) * + uf::matrix::scale( uf::matrix::identity(), flatten.scale ) * + uf::quaternion::matrix( flatten.orientation ) * + flatten.model; + uniform.projection = uf::matrix::identity(); + } + + GL_ERROR_CHECK(glMatrixMode(GL_MODELVIEW)); + GL_ERROR_CHECK(glLoadMatrixf( &mat[0] )); + GL_ERROR_CHECK(glMatrixMode(GL_PROJECTION)); + GL_ERROR_CHECK(glLoadMatrixf( &mat[0] )); + + if ( !graphic.material.textures.empty() ) { + GL_ERROR_CHECK(glClientActiveTexture(GL_TEXTURE0)); + GL_ERROR_CHECK(glActiveTexture(GL_TEXTURE0)); + GL_ERROR_CHECK(glEnable(GL_TEXTURE_2D)); + GL_ERROR_CHECK(glBindTexture(GL_TEXTURE_2D, graphic.material.textures.front().descriptor)); + } + + glBegin(GL_TRIANGLES); + glTexCoord2f(0.0f, 0.0f); + glVertex3f(-0.5f, 0.5f, 0.0f); + glTexCoord2f(1.0f, 0.0f); + glVertex3f( 0.5f, 0.5f, 0.0f); + glTexCoord2f(1.0f, 1.0f); + glVertex3f( 0.5f,-0.5f, 0.0f); + + glTexCoord2f(1.0f, 1.0f); + glVertex3f( 0.5f,-0.5f, 0.0f); + glTexCoord2f(0.0f, 1.0f); + glVertex3f(-0.5f,-0.5f, 0.0f); + glTexCoord2f(0.0f, 0.0f); + glVertex3f(-0.5f, 0.5f, 0.0f); + glEnd(); + + if ( !graphic.material.textures.empty() ) { + GL_ERROR_CHECK(glClientActiveTexture(GL_TEXTURE0)); + GL_ERROR_CHECK(glActiveTexture(GL_TEXTURE0)); + GL_ERROR_CHECK(glBindTexture(GL_TEXTURE_2D, 0)); + GL_ERROR_CHECK(glDisable(GL_TEXTURE_2D)); + } +#endif +} void ext::GuiBehavior::destroy( uf::Object& self ){} void ext::GuiBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ){ serializer["gui"]["color"] = uf::vector::encode( color ); diff --git a/ext/main.cpp b/ext/main.cpp index 28a9a667..2592a001 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -92,6 +92,8 @@ namespace { } limiter, fps; } engine; } config; + + bool requestDedicatedRenderThread = false; } void EXT_API ext::load() { @@ -265,12 +267,12 @@ void EXT_API ext::initialize() { // Set worker threads if ( configEngineThreadJson["workers"].as() == "async" ) { uf::thread::async = true; - auto threads = std::max( 1, (int) std::thread::hardware_concurrency() - 1 ); + auto threads = std::max( 1, (int) std::thread::hardware_concurrency() - 1 ) / 2; configEngineThreadJson["workers"] = threads; uf::thread::workers = configEngineThreadJson["workers"].as(); UF_MSG_DEBUG("Using async worker threads"); } else if ( configEngineThreadJson["workers"].as() == "auto" ) { - auto threads = std::max( 1, (int) std::thread::hardware_concurrency() - 1 ); + auto threads = std::max( 1, (int) std::thread::hardware_concurrency() - 1 ) / 2; configEngineThreadJson["workers"] = threads; uf::thread::workers = configEngineThreadJson["workers"].as(); UF_MSG_DEBUG("Using " << threads << " worker threads"); @@ -346,7 +348,9 @@ void EXT_API ext::initialize() { #else auto& configRenderJson = ::json["engine"]["ext"]["software"]; #endif + auto& configRenderInvariantJson = configRenderJson["invariant"]; auto& configRenderExperimentalJson = configRenderJson["experimental"]; + auto& configRenderPipelinesJson = configRenderJson["pipelines"]; uf::renderer::settings::validation = configRenderJson["validation"]["enabled"].as( uf::renderer::settings::validation ); uf::renderer::settings::msaa = configRenderJson["framebuffer"]["msaa"].as( uf::renderer::settings::msaa ); @@ -365,6 +369,11 @@ void EXT_API ext::initialize() { } #if UF_USE_VULKAN + if ( configRenderJson["gpu"].as() == "auto" ) { + uf::renderer::settings::gpuID = -1; + } else { + uf::renderer::settings::gpuID = configRenderJson["gpu"].as(uf::renderer::settings::gpuID); + } for ( int i = 0; i < configRenderJson["validation"]["filters"].size(); ++i ) { uf::renderer::settings::validationFilters.emplace_back( configRenderJson["validation"]["filters"][i].as() ); } @@ -377,21 +386,37 @@ void EXT_API ext::initialize() { for ( int i = 0; i < configRenderJson["features"].size(); ++i ) { uf::renderer::settings::requestedDeviceFeatures.emplace_back( configRenderJson["features"][i].as() ); } + /* + "rebuild on tick begin": false, + "wait on render end": false, + "multithreaded recording": true, + "individual pipelines": true, + "deferred mode": "", + "deferred reconstruct position": true, + "deferred alias output to swapchain": false, + */ + + ::requestDedicatedRenderThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread ); + #if 0 + uf::renderer::settings::experimental::dedicatedThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread ); uf::renderer::settings::experimental::rebuildOnTickBegin = configRenderExperimentalJson["rebuild on tick begin"].as( uf::renderer::settings::experimental::rebuildOnTickBegin ); - uf::renderer::settings::experimental::waitOnRenderEnd = configRenderExperimentalJson["wait on render end"].as( uf::renderer::settings::experimental::waitOnRenderEnd ); - uf::renderer::settings::experimental::individualPipelines = configRenderExperimentalJson["individual pipelines"].as( uf::renderer::settings::experimental::individualPipelines ); - uf::renderer::settings::experimental::multithreadedCommandRecording = configRenderExperimentalJson["multithreaded command recording"].as( uf::renderer::settings::experimental::multithreadedCommandRecording ); - uf::renderer::settings::experimental::multithreadedCommandRendering = configRenderExperimentalJson["multithreaded command rendering"].as( uf::renderer::settings::experimental::multithreadedCommandRendering ); - uf::renderer::settings::experimental::deferredMode = configRenderExperimentalJson["deferred mode"].as( uf::renderer::settings::experimental::deferredMode ); - uf::renderer::settings::experimental::deferredReconstructPosition = configRenderExperimentalJson["deferred reconstruct position"].as( uf::renderer::settings::experimental::deferredReconstructPosition ); - uf::renderer::settings::experimental::deferredAliasOutputToSwapchain = configRenderExperimentalJson["deferred alias output to swapchain"].as( uf::renderer::settings::experimental::deferredAliasOutputToSwapchain ); - uf::renderer::settings::experimental::vsync = configRenderExperimentalJson["vsync"].as( uf::renderer::settings::experimental::vsync ); - uf::renderer::settings::experimental::hdr = configRenderExperimentalJson["hdr"].as( uf::renderer::settings::experimental::hdr ); - uf::renderer::settings::experimental::vxgi = configRenderExperimentalJson["vxgi"].as( uf::renderer::settings::experimental::vxgi ); - uf::renderer::settings::experimental::deferredSampling = configRenderExperimentalJson["deferred sampling"].as( uf::renderer::settings::experimental::deferredSampling ); - uf::renderer::settings::experimental::culling = configRenderExperimentalJson["culling"].as( uf::renderer::settings::experimental::culling ); - uf::renderer::settings::experimental::bloom = configRenderExperimentalJson["bloom"].as( uf::renderer::settings::experimental::bloom ); + #endif + uf::renderer::settings::experimental::batchQueueSubmissions = configRenderExperimentalJson["batch queue submissions"].as( uf::renderer::settings::experimental::batchQueueSubmissions ); + + uf::renderer::settings::invariant::multithreadedRecording = configRenderInvariantJson["multithreaded recording"].as( uf::renderer::settings::invariant::multithreadedRecording ); + uf::renderer::settings::invariant::waitOnRenderEnd = configRenderInvariantJson["wait on render end"].as( uf::renderer::settings::invariant::waitOnRenderEnd ); + uf::renderer::settings::invariant::individualPipelines = configRenderInvariantJson["individual pipelines"].as( uf::renderer::settings::invariant::individualPipelines ); + uf::renderer::settings::invariant::deferredMode = configRenderInvariantJson["deferred mode"].as( uf::renderer::settings::invariant::deferredMode ); + uf::renderer::settings::invariant::deferredReconstructPosition = configRenderInvariantJson["deferred reconstruct position"].as( uf::renderer::settings::invariant::deferredReconstructPosition ); + uf::renderer::settings::invariant::deferredAliasOutputToSwapchain = configRenderInvariantJson["deferred alias output to swapchain"].as( uf::renderer::settings::invariant::deferredAliasOutputToSwapchain ); + uf::renderer::settings::invariant::deferredSampling = configRenderInvariantJson["deferred sampling"].as( uf::renderer::settings::invariant::deferredSampling ); + + uf::renderer::settings::pipelines::vsync = configRenderPipelinesJson["vsync"].as( uf::renderer::settings::pipelines::vsync ); + uf::renderer::settings::pipelines::hdr = configRenderPipelinesJson["hdr"].as( uf::renderer::settings::pipelines::hdr ); + uf::renderer::settings::pipelines::vxgi = configRenderPipelinesJson["vxgi"].as( uf::renderer::settings::pipelines::vxgi ); + uf::renderer::settings::pipelines::culling = configRenderPipelinesJson["culling"].as( uf::renderer::settings::pipelines::culling ); + uf::renderer::settings::pipelines::bloom = configRenderPipelinesJson["bloom"].as( uf::renderer::settings::pipelines::bloom ); #define JSON_TO_VKFORMAT( key ) if ( configRenderJson["formats"][#key].is() ) {\ uf::stl::string format = configRenderJson["formats"][#key].as();\ @@ -446,7 +471,6 @@ void EXT_API ext::initialize() { } #endif -#if UF_USE_VULKAN /* Initialize Vulkan */ { // setup render mode if ( ::json["engine"]["render modes"]["gui"].as(true) ) { @@ -460,10 +484,11 @@ void EXT_API ext::initialize() { if ( ::json["engine"]["render modes"]["stereo deferred"].as() ) { renderMode.metadata.eyes = 2; } - if ( uf::renderer::settings::experimental::culling ) { + if ( uf::renderer::settings::pipelines::culling ) { renderMode.metadata.pipelines.emplace_back("culling"); } } +#if UF_USE_VULKAN /* Callbacks for 2KHR stuffs */ { uf::hooks.addHook("vulkan:Instance.ExtensionsEnabled", []( const ext::json::Value& json ) { // UF_MSG_DEBUG("vulkan:Instance.ExtensionsEnabled: " << json); @@ -498,8 +523,8 @@ void EXT_API ext::initialize() { // UF_MSG_DEBUG("\tmaxMultiviewInstanceIndex = " << extProps.maxMultiviewInstanceIndex); }); } - } #endif + } #if UF_USE_OPENVR if ( ext::openvr::enabled ) { ext::openvr::initialize(); @@ -527,7 +552,7 @@ void EXT_API ext::initialize() { uf::renderer::initialize(); } - pod::Thread& threadMain = uf::thread::has("Main") ? uf::thread::get("Main") : uf::thread::create( "Main", false ); + pod::Thread& threadMain = uf::thread::get("Main"); #if UF_USE_DISCORD /* Discord */ if ( ::config.engine.ext.discord.enabled ) { ext::discord::initialize(); @@ -555,7 +580,8 @@ void EXT_API ext::initialize() { return 0; }; - if ( json["immediate"].as() ) function(); else uf::thread::add( uf::thread::get("Main"), function, true ); + if ( json["immediate"].as() ) function(); + else uf::thread::queue( uf::thread::get("Main"), function ); }); uf::hooks.addHook( "game:Scene.Cleanup", [&](ext::json::Value& json){ @@ -577,11 +603,11 @@ void EXT_API ext::initialize() { } /* - uf::thread::add( uf::thread::fetchWorker(), [&]() -> int { + uf::thread::add( uf::thread::fetchWorker(), [&]{ auto& scene = uf::scene::getCurrentScene(); auto& assetLoader = scene.getComponent(); assetLoader.processQueue(); - return 0;}, false ); + }); */ ext::ready = true; @@ -659,7 +685,7 @@ void EXT_API ext::tick() { } #endif /* Update vulkan */ { - uf::renderer::tick(); + // uf::renderer::tick(); } //UF_TIMER_TRACE("ticking renderer"); #if UF_USE_DISCORD @@ -671,7 +697,7 @@ void EXT_API ext::tick() { ++::times.frames; ++::times.total.frames; TIMER( ::config.engine.fps.every ) { - UF_MSG_DEBUG("System: " << (::config.engine.fps.every * 1000.0/::times.frames) << " ms/frame | Time: " << time << " | Frames: " << ::times.frames << " | FPS: " << ::times.frames / time); + UF_MSG_DEBUG("System: " << (time * 1000.0/::times.frames) << " ms/frame | Time: " << time << " | Frames: " << ::times.frames << " | FPS: " << ::times.frames / time); #if UF_ENV_DREAMCAST DC_STATS(); #endif @@ -699,6 +725,13 @@ void EXT_API ext::tick() { } timer.reset(); } + + if ( ::requestDedicatedRenderThread ) { + ::requestDedicatedRenderThread = false; + uf::renderer::settings::experimental::dedicatedThread = true; + uf::renderer::settings::experimental::rebuildOnTickBegin = true; + UF_MSG_DEBUG("Dedicated render requested"); + } #endif } void EXT_API ext::render() { @@ -713,6 +746,7 @@ void EXT_API ext::render() { } #endif /* Render scene */ { + uf::renderer::tick(); uf::renderer::render(); } #if UF_USE_OPENVR diff --git a/makefiles/default/arch b/makefiles/default/arch new file mode 100644 index 00000000..6ec5a6aa --- /dev/null +++ b/makefiles/default/arch @@ -0,0 +1 @@ +win64 \ No newline at end of file diff --git a/makefiles/default/cc b/makefiles/default/cc new file mode 100644 index 00000000..b08d5af5 --- /dev/null +++ b/makefiles/default/cc @@ -0,0 +1 @@ +gcc \ No newline at end of file diff --git a/makefiles/default/renderer b/makefiles/default/renderer new file mode 100644 index 00000000..53395cff --- /dev/null +++ b/makefiles/default/renderer @@ -0,0 +1 @@ +vulkan \ No newline at end of file diff --git a/makefiles/dreamcast.gcc.make b/makefiles/dreamcast.gcc.make index 19410736..d023b453 100644 --- a/makefiles/dreamcast.gcc.make +++ b/makefiles/dreamcast.gcc.make @@ -2,6 +2,7 @@ ARCH = dreamcast CDIR = CC = gcc CXX = $(KOS_CCPLUS) +RENDERER = opengl TARGET_EXTENSION = elf OPTIMIZATIONS = -Os -g -ffunction-sections -fdata-sections -Wl,--gc-sections -fstrict-aliasing -ffast-math -flto -fno-unroll-all-loops -fno-optimize-sibling-calls -fschedule-insns2 -fomit-frame-pointer -DUF_NO_EXCEPTIONS -fno-exceptions WARNINGS = -Wno-attributes -Wno-conversion-null diff --git a/makefiles/win64.clang.make b/makefiles/win64.clang.make index f6aa6c99..1bd4a23b 100644 --- a/makefiles/win64.clang.make +++ b/makefiles/win64.clang.make @@ -3,5 +3,5 @@ CDIR = CC = clang CXX = clang++ OPTIMIZATIONS = -O3 -fstrict-aliasing # -flto -WARNINGS = -g -Wall -Wno-pointer-arith -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder-ctor -Wno-ignored-attributes -Wno-c++11-narrowing -Wno-unknown-pragmas +WARNINGS = -g -Wall -Wno-pointer-arith -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder-ctor -Wno-ignored-attributes -Wno-c++11-narrowing -Wno-unknown-pragmas -Wno-nullability-completeness -Wno-defaulted-function-deleted -Wno-mismatched-tags FLAGS += -std=c++17 $(OPTIMIZATIONS) $(WARNINGS) -fcolor-diagnostics -fansi-escape-codes \ No newline at end of file diff --git a/makefiles/win64.gcc.make b/makefiles/win64.gcc.make index e99da8b4..28165b3d 100644 --- a/makefiles/win64.gcc.make +++ b/makefiles/win64.gcc.make @@ -2,6 +2,6 @@ ARCH = win64 CDIR = CC = gcc CXX = g++ -OPTIMIZATIONS = -O3 -g -fstrict-aliasing #-flto +OPTIMIZATIONS = -g -O3 -fstrict-aliasing #-flto WARNINGS = -Wall -Wno-unknown-pragmas -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation -FLAGS += -std=c++17 $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always \ No newline at end of file +FLAGS += -std=c++20 $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always \ No newline at end of file