Commit for 2022.06.12 17-21-07.7z
This commit is contained in:
parent
a9f5a56366
commit
e38c08ff85
99
Makefile
99
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 .
|
||||
@ -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 ],
|
||||
|
||||
@ -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 ],
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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" }
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
"scaling": "relative",
|
||||
"world": true,
|
||||
"cull mode": "none",
|
||||
"color": [ 1, 0, 1, 1 ],
|
||||
"text settings": {
|
||||
"scale": 8,
|
||||
"font": "Coolvetica.ttf",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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<bool>() ) {
|
||||
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 }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,8 +6,10 @@
|
||||
#include <uf/utils/window/payloads.h>
|
||||
|
||||
#include <uf/utils/memory/pool.h>
|
||||
#include <filesystem>
|
||||
#include <uf/spec/renderer/universal.h>
|
||||
|
||||
|
||||
#include <filesystem>
|
||||
#include <signal.h>
|
||||
|
||||
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<long long> 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());
|
||||
|
||||
10
debug.sh
10
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
|
||||
|
||||
|
||||
@ -52,7 +52,7 @@ namespace uf {
|
||||
typedef uf::stl::vector<pod::Behavior> container_t;
|
||||
// typedef uf::stl::vector<pod::Behavior::Header> 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<value_t> 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& );
|
||||
|
||||
@ -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<uf::stl::string, uf::Entity*> cache;
|
||||
#endif
|
||||
|
||||
pod::Thread::Tasks tasks;
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -52,7 +52,7 @@ namespace ext {
|
||||
template<typename T> T& encode( const ext::json::Value& json, T& output, const ext::json::EncodingSettings& settings = {} );
|
||||
template<typename T> 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;
|
||||
|
||||
@ -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<RenderMode*> renderModes;
|
||||
extern UF_API uf::stl::vector<uf::Scene*> scenes;
|
||||
extern UF_API uf::ThreadUnique<RenderMode*> 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<RenderMode*> UF_API getRenderModes( const uf::stl::string&, bool = true );
|
||||
uf::stl::vector<RenderMode*> UF_API getRenderModes( const uf::stl::vector<uf::stl::string>&, 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();
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <uf/ext/opengl/rendermode.h>
|
||||
#include <uf/ext/opengl/graphic.h>
|
||||
|
||||
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<ext::opengl::Graphic*> 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 );
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@ namespace ext {
|
||||
virtual void createCommandBuffers( const uf::stl::vector<ext::opengl::Graphic*>& graphics );
|
||||
virtual void initialize( Device& device );
|
||||
virtual void tick();
|
||||
virtual void render();
|
||||
virtual void destroy();
|
||||
};
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<int32_t, callback_t> 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<ext::vulkan::Graphic*> 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();
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <uf/ext/vulkan/rendermode.h>
|
||||
#include <uf/ext/vulkan/graphic.h>
|
||||
|
||||
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<ext::vulkan::Graphic*> 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 );
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,8 @@ namespace ext {
|
||||
virtual void createCommandBuffers( const uf::stl::vector<ext::vulkan::Graphic*>& graphics );
|
||||
virtual void initialize( Device& device );
|
||||
virtual void tick();
|
||||
virtual VkSubmitInfo queue();
|
||||
virtual void render();
|
||||
virtual void destroy();
|
||||
};
|
||||
}
|
||||
|
||||
@ -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<uf::stl::string> 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<RenderMode*> renderModes;
|
||||
extern UF_API uf::stl::unordered_map<uf::stl::string, RenderMode*> renderModesMap;
|
||||
extern UF_API uf::stl::vector<uf::Scene*> scenes;
|
||||
extern UF_API uf::ThreadUnique<RenderMode*> 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<RenderMode*> UF_API getRenderModes( const uf::stl::string&, bool = true );
|
||||
uf::stl::vector<RenderMode*> UF_API getRenderModes( const uf::stl::vector<uf::stl::string>&, 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();
|
||||
|
||||
@ -79,13 +79,13 @@
|
||||
#define UF_TIMER_TRACE_INIT() uf::Timer<long long> 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;\
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#include <uf/ext/opengl/graphic.h>
|
||||
#include <uf/ext/opengl/rendermodes/rendertarget.h>
|
||||
#include <uf/ext/opengl/rendermodes/deferred.h>
|
||||
#include <uf/ext/opengl/rendermodes/compute.h>
|
||||
#include <uf/ext/opengl/rendertarget.h>
|
||||
|
||||
namespace spec {
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#include <uf/ext/vulkan/graphic.h>
|
||||
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
|
||||
#include <uf/ext/vulkan/rendermodes/deferred.h>
|
||||
#include <uf/ext/vulkan/rendermodes/compute.h>
|
||||
#include <uf/ext/vulkan/rendertarget.h>
|
||||
|
||||
namespace spec {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <uf/ext/json/json.h>
|
||||
#include <uf/utils/serialize/serializer.h>
|
||||
#include <uf/utils/math/angle.h>
|
||||
|
||||
namespace pod {
|
||||
|
||||
@ -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::stl::string> UF_API match( const uf::stl::string& str, const uf::stl::string& r );
|
||||
inline uf::stl::vector<uf::stl::string> UF_API matches( const uf::stl::string& str, const uf::stl::string& r ) { return uf::string::match( str, r ); }
|
||||
inline uf::stl::vector<uf::stl::string> 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 );
|
||||
|
||||
|
||||
@ -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<id_t, type_t> container_t;
|
||||
typedef uf::stl::unordered_map<id_t, mutex_type_t> 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<std::mutex> guard( id_t id = std::this_thread::get_id() );
|
||||
|
||||
container_t& container();
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,3 +1,12 @@
|
||||
template<typename T>
|
||||
uf::ThreadUnique<T>::~ThreadUnique() {
|
||||
for ( auto& pair : m_mutex_container ) {
|
||||
if ( !pair.second ) continue;
|
||||
delete pair.second;
|
||||
pair.second = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool uf::ThreadUnique<T>::has( id_t id ) const {
|
||||
return m_container.count(id) > 0;
|
||||
@ -7,6 +16,21 @@ T& uf::ThreadUnique<T>::get( id_t id ) {
|
||||
return m_container[id];
|
||||
}
|
||||
template<typename T>
|
||||
void uf::ThreadUnique<T>::lock( id_t id ) {
|
||||
if ( m_mutex_container.count(id) == 0 ) m_mutex_container[id] = new std::mutex;
|
||||
m_mutex_container[id]->lock();
|
||||
}
|
||||
template<typename T>
|
||||
void uf::ThreadUnique<T>::unlock( id_t id ) {
|
||||
if ( m_mutex_container.count(id) == 0 ) m_mutex_container[id] = new std::mutex;
|
||||
m_mutex_container[id]->unlock();
|
||||
}
|
||||
template<typename T>
|
||||
std::lock_guard<std::mutex> uf::ThreadUnique<T>::guard( id_t id ) {
|
||||
if ( m_mutex_container.count(id) == 0 ) m_mutex_container[id] = new std::mutex;
|
||||
return std::lock_guard<std::mutex>(*m_mutex_container[id]);
|
||||
}
|
||||
template<typename T>
|
||||
typename uf::ThreadUnique<T>::container_t& uf::ThreadUnique<T>::container() {
|
||||
return m_container;
|
||||
}
|
||||
@ -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<long long> 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<void()>& = 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<pod::Thread::function_t>&, bool = true, const uf::stl::string& name = "Aux" );
|
||||
void UF_API batchWorkers_Async( const uf::stl::vector<pod::Thread::function_t>&, 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<pod::Thread*> 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<int()> function_t;
|
||||
typedef std::queue<uf::Thread::function_t> queue_t;
|
||||
typedef uf::stl::vector<uf::Thread::function_t> 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<void()>& = 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<uf::stl::string, uf::Thread*> 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& );
|
||||
};
|
||||
}
|
||||
*/
|
||||
}
|
||||
@ -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<std::queue<Job>>());
|
||||
while ( !jobs.empty() ) {
|
||||
@ -69,102 +69,6 @@ void uf::Asset::processQueue() {
|
||||
}
|
||||
mutex.unlock();
|
||||
});
|
||||
|
||||
#if 0
|
||||
auto& jobs = this->getComponent<std::queue<Job>>();
|
||||
mutex.lock();
|
||||
uf::stl::vector<std::function<void()>> 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<std::queue<Job>>();
|
||||
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<std::queue<Job>>());
|
||||
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<std::queue<Job>>());
|
||||
uf::stl::vector<std::function<void()>> 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();
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <uf/utils/serialize/serializer.h>
|
||||
#include <uf/utils/thread/thread.h>
|
||||
|
||||
#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);
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include <uf/engine/instantiator/instantiator.h>
|
||||
|
||||
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();
|
||||
|
||||
@ -306,9 +306,13 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize
|
||||
graph.name = filename; //serializer["name"].as<uf::stl::string>();
|
||||
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 ) {
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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<size_t, uf::stl::string> 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<pod::SceneTextures>();
|
||||
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>("");
|
||||
uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as<uf::stl::string>("/graph/base.frag.spv"); {
|
||||
std::pair<bool, uf::stl::string> 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<uf::stl::string>("/graph/base.vert.spv");
|
||||
uf::stl::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as<uf::stl::string>("/graph/voxelize.geom.spv");
|
||||
uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as<uf::stl::string>("/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<bool>();
|
||||
#endif
|
||||
|
||||
uf::Serializer metadataLight;
|
||||
metadataLight["radius"][0] = 0.001;
|
||||
metadataLight["radius"][1] = l.range; // l.range <= 0.001f ? graph.metadata["lights"]["range cap"].as<float>() : 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<bool>()) && graph.metadata["flags"]["RENDER"].as<bool>() ) {
|
||||
uf::instantiator::bind("RenderBehavior", entity);
|
||||
// uf::instantiator::bind("RenderBehavior", entity);
|
||||
|
||||
auto& graphic = entity.getComponent<uf::Graphic>();
|
||||
graphic.initialize();
|
||||
@ -948,7 +943,7 @@ void uf::graph::initialize( pod::Graph& graph ) {
|
||||
initializeShaders( graph, entity->as<uf::Object>() );
|
||||
|
||||
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<uf::Object>() ) );
|
||||
*/
|
||||
@ -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<uf::Camera>();
|
||||
|
||||
#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() {
|
||||
|
||||
@ -184,6 +184,10 @@ void uf::ObjectBehavior::tick( uf::Object& self ) {
|
||||
auto& audio = this->getComponent<uf::MappedSoundEmitter>();
|
||||
audio.update();
|
||||
}
|
||||
if ( this->hasComponent<pod::Graph>() ) {
|
||||
auto& graph = this->getComponent<pod::Graph>();
|
||||
uf::graph::update( graph );
|
||||
}
|
||||
|
||||
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
|
||||
#if UF_ENTITY_METADATA_USE_JSON
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
#include <uf/utils/string/hash.h>
|
||||
|
||||
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<uf::Serializer>();
|
||||
@ -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<pod::Graph>() ) {
|
||||
auto& graph = this->getComponent<pod::Graph>();
|
||||
uf::graph::update( graph );
|
||||
}
|
||||
#if 0
|
||||
/* Update animations */ if ( this->hasComponent<pod::Graph>() ) {
|
||||
auto& graph = this->getComponent<pod::Graph>();
|
||||
// if ( graph.metadata["flags"]["SKINNED"].as<bool>() ) uf::graph::update( graph );
|
||||
|
||||
@ -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 ) {
|
||||
|
||||
@ -17,14 +17,15 @@ namespace {
|
||||
uf::SceneBehavior::Metadata metadata;
|
||||
}
|
||||
#endif
|
||||
|
||||
uf::Entity& uf::Scene::getController() {
|
||||
#if !UF_SCENE_GLOBAL_GRAPH
|
||||
auto& metadata = this->getComponent<uf::SceneBehavior::Metadata>();
|
||||
#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<uf::Scene*>(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::Entity*>& 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<uf::ObjectBehavior::Metadata>() ) return;
|
||||
auto& eMetadata = entity->getComponent<uf::ObjectBehavior::Metadata>();
|
||||
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<uf::SceneBehavior::Metadata>();
|
||||
#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;
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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<size_t, uf::stl::vector<CommandBuffer::InfoDraw>> 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<decltype(subpass)>{}(subpass);
|
||||
if ( settings::experimental::individualPipelines )
|
||||
if ( settings::invariant::individualPipelines )
|
||||
hash += std::hash<decltype(renderMode)>{}(renderMode);
|
||||
|
||||
hash += std::hash<decltype(renderTarget)>{}(renderTarget);
|
||||
|
||||
@ -27,21 +27,27 @@ uf::stl::vector<uf::stl::string> 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::RenderMode*> ext::opengl::currentRenderMode;
|
||||
|
||||
|
||||
uf::stl::vector<uf::Scene*> ext::opengl::scenes;
|
||||
ext::opengl::RenderMode* ext::opengl::currentRenderMode = NULL;
|
||||
uf::stl::vector<ext::opengl::RenderMode*> 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<uf::Serializer>();
|
||||
|
||||
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
|
||||
|
||||
@ -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<uf::Serializer>();
|
||||
|
||||
@ -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 ) {
|
||||
|
||||
@ -41,12 +41,12 @@ void ext::opengl::BaseRenderMode::createCommandBuffers( const uf::stl::vector<ex
|
||||
}
|
||||
commands.record(clearCommandInfo);
|
||||
#endif
|
||||
|
||||
CommandBuffer::InfoViewport viewportCommandInfo = {};
|
||||
viewportCommandInfo.type = enums::Command::VIEWPORT;
|
||||
viewportCommandInfo.corner = pod::Vector2ui{0, 0};
|
||||
viewportCommandInfo.size = pod::Vector2ui{width, height};
|
||||
commands.record(viewportCommandInfo);
|
||||
|
||||
for ( auto graphic : graphics ) {
|
||||
if ( graphic->descriptor.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();
|
||||
}
|
||||
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
#if UF_USE_OPENGL
|
||||
|
||||
#include <uf/ext/opengl/opengl.h>
|
||||
#include <uf/ext/opengl/rendermodes/compute.h>
|
||||
#include <uf/ext/opengl/rendermodes/deferred.h>
|
||||
#include <uf/ext/opengl/rendermodes/rendertarget.h>
|
||||
#include <uf/ext/opengl/initializers.h>
|
||||
#include <uf/ext/openvr/openvr.h>
|
||||
#include <uf/utils/window/window.h>
|
||||
#include <uf/utils/graphic/graphic.h>
|
||||
#include <uf/ext/opengl/graphic.h>
|
||||
#include <uf/engine/scene/scene.h>
|
||||
#include <uf/utils/camera/camera.h>
|
||||
#include <uf/utils/math/transform.h>
|
||||
|
||||
#include <uf/ext/opengl/graphic.h>
|
||||
|
||||
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::Graphic*> 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
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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<int>::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<VkPhysicalDevice> 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<int, VkPhysicalDevice> 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;
|
||||
}
|
||||
|
||||
@ -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<ext::vulkan::enums::Image::viewType_t> 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::Shader*> ext::vulkan::Pipeline::getShaders( uf::stl::vector<ext::vulkan::Shader>& shaders ) {
|
||||
uf::stl::unordered_map<uf::stl::string, ext::vulkan::Shader*> map;
|
||||
@ -1103,7 +1115,7 @@ ext::vulkan::GraphicDescriptor::hash_t ext::vulkan::GraphicDescriptor::hash() co
|
||||
size_t hash{};
|
||||
|
||||
hash += std::hash<decltype(subpass)>{}(subpass);
|
||||
if ( settings::experimental::individualPipelines )
|
||||
if ( settings::invariant::individualPipelines )
|
||||
hash += std::hash<decltype(renderMode)>{}(renderMode);
|
||||
|
||||
hash += std::hash<decltype(renderTarget)>{}(renderTarget);
|
||||
|
||||
@ -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<ext::vulkan::Graphic*>& graphics ) {
|
||||
|
||||
}
|
||||
@ -239,6 +255,7 @@ void ext::vulkan::RenderMode::bindPipelines() {
|
||||
this->bindPipelines( graphics );
|
||||
}
|
||||
void ext::vulkan::RenderMode::bindPipelines( const uf::stl::vector<ext::vulkan::Graphic*>& 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::vector<ext::vulkan::
|
||||
}
|
||||
}
|
||||
}
|
||||
//unlockMutex();
|
||||
}
|
||||
VkSubmitInfo ext::vulkan::RenderMode::queue() {
|
||||
if ( !metadata.limiter.execute ) return {};
|
||||
|
||||
void ext::vulkan::RenderMode::render() {
|
||||
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.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 ) {
|
||||
}
|
||||
|
||||
@ -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 ) {
|
||||
|
||||
@ -1,260 +0,0 @@
|
||||
#if UF_USE_VULKAN
|
||||
|
||||
#include <uf/ext/vulkan/vulkan.h>
|
||||
#include <uf/ext/vulkan/rendermodes/compute.h>
|
||||
#include <uf/ext/vulkan/rendermodes/deferred.h>
|
||||
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
|
||||
#include <uf/ext/vulkan/initializers.h>
|
||||
#include <uf/ext/openvr/openvr.h>
|
||||
#include <uf/utils/window/window.h>
|
||||
#include <uf/utils/graphic/graphic.h>
|
||||
#include <uf/ext/vulkan/graphic.h>
|
||||
#include <uf/engine/scene/scene.h>
|
||||
#include <uf/utils/camera/camera.h>
|
||||
#include <uf/utils/math/transform.h>
|
||||
|
||||
#include <uf/ext/vulkan/graphic.h>
|
||||
|
||||
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::Graphic*> 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<uf::Serializer>();
|
||||
|
||||
auto& shader = compute.material.shaders.front();
|
||||
|
||||
struct SpecializationConstant {
|
||||
uint32_t maxLights = 16;
|
||||
uint32_t eyes = 2;
|
||||
};
|
||||
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
|
||||
specializationConstants.maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as<size_t>();
|
||||
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<pod::Vertex_2F2F, uint16_t>();
|
||||
mesh.insertVertices<pod::Vertex_2F2F>({
|
||||
{ {-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<uint16_t>({
|
||||
0, 1, 2, 2, 3, 0
|
||||
});
|
||||
/*
|
||||
uf::Mesh<pod::Vertex_2F2F, uint16_t> 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
|
||||
@ -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<bool, uf::stl::string> 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<uf::Serializer>();
|
||||
|
||||
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;
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include <uf/utils/graphic/graphic.h>
|
||||
#include <uf/ext/vulkan/graphic.h>
|
||||
#include <uf/engine/graph/graph.h>
|
||||
#include <uf/utils/camera/camera.h>
|
||||
|
||||
const uf::stl::string ext::vulkan::RenderTargetRenderMode::getTarget() const {
|
||||
// auto& metadata = *const_cast<uf::Serializer*>(&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<bool, uf::stl::string> 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 };
|
||||
|
||||
@ -44,7 +44,7 @@ void ext::vulkan::Swapchain::initialize( Device& device ) {
|
||||
uf::stl::vector<VkPresentModeKHR> 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;
|
||||
|
||||
@ -13,12 +13,17 @@
|
||||
#include <fstream>
|
||||
#include <atomic>
|
||||
|
||||
namespace {
|
||||
uf::stl::vector<VkFence> 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<uf::stl::string> ext::vulkan::settings::validationFilters;
|
||||
uf::stl::vector<uf::stl::string> ext::vulkan::settings::requestedDeviceFeatures;
|
||||
@ -27,21 +32,28 @@ uf::stl::vector<uf::stl::string> 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::RenderMode*> ext::vulkan::currentRenderMode;
|
||||
|
||||
uf::stl::vector<uf::Scene*> ext::vulkan::scenes;
|
||||
ext::vulkan::RenderMode* ext::vulkan::currentRenderMode = NULL;
|
||||
uf::stl::vector<ext::vulkan::RenderMode*> 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<uf::Graphic>() ) continue;
|
||||
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
|
||||
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<uf::Graphic>() ) continue;
|
||||
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
|
||||
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<uf::Graphic>() ) continue;
|
||||
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
|
||||
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<RenderMode*> auxRenderModes; auxRenderModes.reserve( renderModes.size() );
|
||||
uf::stl::vector<RenderMode*> 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<VkSubmitInfo> 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();
|
||||
|
||||
@ -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 ) {
|
||||
|
||||
@ -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<std::future<void>> 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<pod::Thread*> 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::vector<pod::Thread::functio
|
||||
for ( auto& function : functions ) {
|
||||
auto& worker = uf::thread::fetchWorker( name );
|
||||
workers.emplace_back(&worker);
|
||||
uf::thread::add( worker, function, true );
|
||||
uf::thread::queue( worker, function );
|
||||
}
|
||||
if ( wait ) for ( auto& worker : workers ) uf::thread::wait( *worker );
|
||||
}
|
||||
@ -82,14 +122,34 @@ void UF_API uf::thread::batchWorkers_Async( const uf::stl::vector<pod::Thread::f
|
||||
if ( wait ) for ( auto& future : futures ) future.wait();
|
||||
return;
|
||||
}
|
||||
void UF_API uf::thread::add( pod::Thread& thread, const pod::Thread::function_t& function, bool temporary ) {
|
||||
*/
|
||||
/*
|
||||
void UF_API uf::thread::add( pod::Thread& thread, bool queued, const pod::Thread::function_t& function ) {
|
||||
if ( thread.mutex != NULL ) thread.mutex->lock();
|
||||
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<std::mutex> 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");
|
||||
}
|
||||
|
||||
@ -54,7 +54,6 @@ void ext::BakingBehavior::initialize( uf::Object& self ) {
|
||||
metadata.cull = metadataJson["baking"]["cull"].as<bool>();
|
||||
|
||||
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
|
||||
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;
|
||||
|
||||
|
||||
@ -1,525 +0,0 @@
|
||||
#include <uf/config.h>
|
||||
#if UF_USE_OPENVR
|
||||
#include "behavior.h"
|
||||
|
||||
#include <uf/utils/hook/hook.h>
|
||||
#include <uf/utils/time/time.h>
|
||||
#include <uf/utils/serialize/serializer.h>
|
||||
#include <uf/utils/userdata/userdata.h>
|
||||
#include <uf/utils/window/window.h>
|
||||
#include <uf/utils/camera/camera.h>
|
||||
#include <uf/utils/audio/audio.h>
|
||||
#include <uf/ext/openvr/openvr.h>
|
||||
#include <uf/utils/math/physics.h>
|
||||
#include <uf/utils/mesh/mesh.h>
|
||||
#include <uf/utils/graphic/graphic.h>
|
||||
#include <uf/utils/math/transform.h>
|
||||
#include <uf/utils/math/collision.h>
|
||||
#include <uf/utils/thread/thread.h>
|
||||
#include <uf/utils/renderer/renderer.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
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<uf::Serializer>();
|
||||
{
|
||||
::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<uf::stl::string>()) ) 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>();
|
||||
uf::stl::string side = "";
|
||||
if ( name == metadata["hands"]["left"]["controller"]["model"].as<uf::stl::string>() ) {
|
||||
side = "left";
|
||||
} else if ( name == metadata["hands"]["right"]["controller"]["model"].as<uf::stl::string>() ) {
|
||||
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<uf::Graphic>() = 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<float>() > 0 ) {
|
||||
// line.addAlias<uf::LineMesh, uf::Mesh>();
|
||||
|
||||
pod::Transform<>& transform = line.getComponent<pod::Transform<>>();
|
||||
transform.orientation = uf::quaternion::axisAngle(
|
||||
{
|
||||
metadata["hands"][side]["pointer"]["orientation"]["axis"][0].as<float>(),
|
||||
metadata["hands"][side]["pointer"]["orientation"]["axis"][1].as<float>(),
|
||||
metadata["hands"][side]["pointer"]["orientation"]["axis"][2].as<float>()
|
||||
},
|
||||
metadata["hands"][side]["pointer"]["orientation"]["angle"].as<float>() * 3.14159f / 180.0f
|
||||
);
|
||||
transform.position = {
|
||||
metadata["hands"][side]["pointer"]["offset"][0].as<float>(),
|
||||
metadata["hands"][side]["pointer"]["offset"][1].as<float>(),
|
||||
metadata["hands"][side]["pointer"]["offset"][2].as<float>()
|
||||
};
|
||||
|
||||
auto& mesh = line.getComponent<uf::LineMesh>();
|
||||
auto& graphic = line.getComponent<uf::Graphic>();
|
||||
|
||||
mesh.vertices = {
|
||||
{ {0.0f, 0.0f, 0.0f} },
|
||||
{ {0.0f, 0.0f, metadata["hands"][side]["pointer"]["length"].as<float>()} },
|
||||
};
|
||||
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<float>();
|
||||
|
||||
line.initialize();
|
||||
}
|
||||
if ( metadata["hands"][side]["light"]["should"].as<bool>() ){
|
||||
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<uf::Serializer>();
|
||||
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<uf::Serializer>();
|
||||
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<uf::Object*> 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<pod::Transform<>>();
|
||||
auto& collider = hand.getComponent<uf::Collider>();
|
||||
|
||||
// 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<uf::Camera>();
|
||||
auto& controllerTransform = controller.getComponent<pod::Transform<>>();
|
||||
auto& controllerCameraTransform = controllerCamera.getTransform();
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
|
||||
pod::Matrix4f playerModel = uf::matrix::identity(); {
|
||||
auto& controller = this->getParent();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
pod::Matrix4f translation = uf::matrix::translate( uf::matrix::identity(), camera.getTransform().position + controller.getComponent<pod::Transform<>>().position );
|
||||
pod::Matrix4f rotation = uf::quaternion::matrix( controller.getComponent<pod::Transform<>>().orientation );
|
||||
playerModel = translation * rotation;
|
||||
}
|
||||
|
||||
{
|
||||
pod::Transform<>& transform = ::hands.left->getComponent<pod::Transform<>>();
|
||||
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<uf::Collider>();
|
||||
for ( auto* box : collider.getContainer() ) {
|
||||
box->getTransform().position = transform.position + controllerTransform.position + controllerCameraTransform.position;
|
||||
}
|
||||
}
|
||||
{
|
||||
pod::Transform<>& transform = ::hands.right->getComponent<pod::Transform<>>();
|
||||
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<uf::Collider>();
|
||||
for ( auto* box : collider.getContainer() ) {
|
||||
box->getTransform().position = transform.position + controllerTransform.position + controllerCameraTransform.position;
|
||||
}
|
||||
}
|
||||
{
|
||||
pod::Transform<>& transform = ::lines.left->getComponent<pod::Transform<>>();
|
||||
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<pod::Transform<>>();
|
||||
lightTransform.position = controllerCameraTransform.position + controller.getComponent<pod::Transform<>>().position + transform.position;
|
||||
|
||||
auto& lightCamera = light.getComponent<uf::Camera>();
|
||||
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<pod::Transform<>>();
|
||||
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<pod::Transform<>>();
|
||||
lightTransform.position = controllerCameraTransform.position + controllerTransform.position + transform.position;
|
||||
|
||||
auto& lightCamera = light.getComponent<uf::Camera>();
|
||||
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<uf::Graphic>() ) {
|
||||
auto& graphic = ::hands.left->getComponent<uf::Graphic>();
|
||||
auto& transform = ::hands.left->getComponent<pod::Transform<>>();
|
||||
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<UniformDescriptor>();
|
||||
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<uf::Graphic>() ) {
|
||||
auto& graphic = ::hands.right->getComponent<uf::Graphic>();
|
||||
auto& transform = ::hands.right->getComponent<pod::Transform<>>();
|
||||
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<UniformDescriptor>();
|
||||
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<uf::Graphic>() ) {
|
||||
auto& graphic = ::lines.left->getComponent<uf::Graphic>();
|
||||
auto& transform = ::lines.left->getComponent<pod::Transform<>>();
|
||||
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<UniformDescriptor>();
|
||||
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<uf::Graphic>() ) {
|
||||
auto& graphic = ::lines.right->getComponent<uf::Graphic>();
|
||||
auto& transform = ::lines.right->getComponent<pod::Transform<>>();
|
||||
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<UniformDescriptor>();
|
||||
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<uf::Object*> 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<pod::Transform<>>();
|
||||
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<uf::Serializer>();
|
||||
if ( ext::json::isArray( cMetadata["overlay"]["position"] ) )
|
||||
gtransform.position = {
|
||||
cMetadata["overlay"]["position"][0].as<float>(),
|
||||
cMetadata["overlay"]["position"][1].as<float>(),
|
||||
cMetadata["overlay"]["position"][2].as<float>(),
|
||||
};
|
||||
if ( ext::json::isArray( cMetadata["overlay"]["scale"] ) )
|
||||
gtransform.scale = {
|
||||
cMetadata["overlay"]["scale"][0].as<float>(),
|
||||
cMetadata["overlay"]["scale"][1].as<float>(),
|
||||
cMetadata["overlay"]["scale"][2].as<float>(),
|
||||
};
|
||||
if ( ext::json::isArray( cMetadata["overlay"]["orientation"] ) )
|
||||
gtransform.orientation = {
|
||||
cMetadata["overlay"]["orientation"][0].as<float>(),
|
||||
cMetadata["overlay"]["orientation"][1].as<float>(),
|
||||
cMetadata["overlay"]["orientation"][2].as<float>(),
|
||||
cMetadata["overlay"]["orientation"][3].as<float>(),
|
||||
};
|
||||
|
||||
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<float>( uf::matrix::inverse( uf::matrix::scale( uf::matrix::identity(), gtransform.scale ) ), uf::vector::subtract( plane.center, hit ) );
|
||||
{
|
||||
auto& metadata = this->getComponent<uf::Serializer>();
|
||||
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<uf::Serializer>();
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
|
||||
if ( ::hands.left && ::hands.left->hasComponent<uf::Graphic>() ) {
|
||||
auto& graphic = ::hands.left->getComponent<uf::Graphic>();
|
||||
auto& transform = ::hands.left->getComponent<pod::Transform<>>();
|
||||
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<pod::Camera::Viewports>();
|
||||
uniforms = camera.data().viewport;
|
||||
shader.updateUniform("Camera", uniform);
|
||||
}
|
||||
}
|
||||
if ( ::hands.right && ::hands.right->hasComponent<uf::Graphic>() ) {
|
||||
auto& graphic = ::hands.right->getComponent<uf::Graphic>();
|
||||
auto& transform = ::hands.right->getComponent<pod::Transform<>>();
|
||||
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<pod::Camera::Viewports>();
|
||||
uniforms = camera.data().viewport;
|
||||
shader.updateUniform("Camera", uniform);
|
||||
}
|
||||
}
|
||||
if ( ::lines.left && ::lines.left->hasComponent<uf::Graphic>() ) {
|
||||
auto& graphic = ::lines.left->getComponent<uf::Graphic>();
|
||||
auto& transform = ::lines.left->getComponent<pod::Transform<>>();
|
||||
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<pod::Camera::Viewports>();
|
||||
uniforms = camera.data().viewport;
|
||||
shader.updateUniform("Camera", uniform);
|
||||
}
|
||||
}
|
||||
if ( ::lines.right && ::lines.right->hasComponent<uf::Graphic>() ) {
|
||||
auto& graphic = ::lines.right->getComponent<uf::Graphic>();
|
||||
auto& transform = ::lines.right->getComponent<pod::Transform<>>();
|
||||
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<pod::Camera::Viewports>();
|
||||
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
|
||||
@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <uf/config.h>
|
||||
#include <uf/ext/ext.h>
|
||||
#include <uf/engine/entity/entity.h>
|
||||
#include <uf/engine/scene/scene.h>
|
||||
|
||||
namespace ext {
|
||||
namespace PlayerHandBehavior {
|
||||
UF_BEHAVIOR_DEFINE_TYPE();
|
||||
EXT_BEHAVIOR_DEFINE_TRAITS();
|
||||
EXT_BEHAVIOR_DEFINE_FUNCTIONS();
|
||||
UF_BEHAVIOR_DEFINE_METADATA(
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -65,7 +65,7 @@ void ext::LightBehavior::initialize( uf::Object& self ) {
|
||||
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
|
||||
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<uf::renderer::RenderTargetRenderMode>() ) {
|
||||
|
||||
auto& renderMode = this->getComponent<uf::renderer::RenderTargetRenderMode>();
|
||||
// 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<uf::Camera>();
|
||||
// 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
|
||||
|
||||
@ -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) );
|
||||
}
|
||||
|
||||
@ -35,9 +35,11 @@ namespace ext {
|
||||
pod::Vector3f max = {NAN, NAN, NAN};
|
||||
} limit;
|
||||
pod::Vector3t<bool> invert;
|
||||
pod::Vector2f queued;
|
||||
} camera;
|
||||
struct {
|
||||
pod::Vector2f sensitivity;
|
||||
pod::Vector2f sensitivity = {1,1};
|
||||
pod::Vector2f smoothing = {10,10};
|
||||
} mouse;
|
||||
struct {
|
||||
struct {
|
||||
|
||||
@ -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<uf::renderer::RenderTargetRenderMode>();
|
||||
if ( hasRT ) {
|
||||
auto& renderMode = entity->getComponent<uf::renderer::RenderTargetRenderMode>();
|
||||
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<pod::Transform<>>() );
|
||||
@ -468,7 +477,10 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
|
||||
auto& lightMetadata = entity->getComponent<ext::LightBehavior::Metadata>();
|
||||
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);
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -33,6 +33,8 @@
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
|
||||
#define EXT_COLOR_FLOATS 1
|
||||
|
||||
namespace {
|
||||
#if UF_USE_FREETYPE
|
||||
struct {
|
||||
@ -40,7 +42,6 @@ namespace {
|
||||
uf::stl::unordered_map<uf::stl::string, uf::stl::unordered_map<uf::stl::string, uf::Glyph>> 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<uf::renderer::AttributeDescriptor> 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<pod::GlyphBox> ext::Gui::generateGlyphs( const uf::stl::string& _string ) {
|
||||
uf::stl::vector<pod::GlyphBox> 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<ext::Gui::mesh_t>();
|
||||
auto& transform = this->getComponent<pod::Transform<>>();
|
||||
uf::stl::vector<pod::Vertex_3F2F3F> 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<uf::stl::vector<::GuiMesh>>();
|
||||
#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<size_t> 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<bool>() ) {
|
||||
|
||||
// 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<bool>() ) 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<bool>() ) 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>() ) {
|
||||
uf::stl::string mode = metadataJson["scaling"].as<uf::stl::string>();
|
||||
@ -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<uf::stl::string>() ) {
|
||||
graphic.initialize( metadataJson["layer"].as<uf::stl::string>() );
|
||||
} else if ( !ext::json::isNull( metadataJson["gui layer"] ) && !metadataJson["gui layer"].as<bool>() ) {
|
||||
@ -385,11 +425,13 @@ void ext::Gui::load( const uf::Image& image ) {
|
||||
} else {
|
||||
graphic.initialize( ::defaultRenderMode );
|
||||
}
|
||||
#endif
|
||||
// graphic.initialize();
|
||||
|
||||
auto& mesh = this->getComponent<uf::Mesh>();
|
||||
mesh.bind<pod::Vertex_3F2F3F>();
|
||||
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<pod::Transform<>>();
|
||||
transform.scale.x = scale;
|
||||
transform.scale.y = scale;
|
||||
|
||||
uf::stl::vector<pod::Vertex_3F2F3F> vertices;
|
||||
#if 0
|
||||
uf::stl::vector<::GuiMesh> vertices;
|
||||
#else
|
||||
auto& vertices = this->getComponent<uf::stl::vector<::GuiMesh>>();
|
||||
#endif
|
||||
uf::stl::vector<size_t> 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<pod::Vertex_3F2F3F>();
|
||||
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<uf::Graphic>();
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
auto& transform = this->getComponent<pod::Transform<>>();
|
||||
auto transform = this->getComponent<pod::Transform<>>();
|
||||
if ( !graphic.initialized ) return;
|
||||
|
||||
bool isGlyph = this->hasComponent<ext::GuiBehavior::GlyphMetadata>();
|
||||
#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<uf::Graphic>() ) return;
|
||||
if ( ext::opengl::currentRenderMode->getName() != "Gui" ) return;
|
||||
|
||||
auto& metadata = this->getComponent<ext::GuiBehavior::Metadata>();
|
||||
auto& metadataJson = this->getComponent<uf::Serializer>();
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& graphic = this->getComponent<uf::Graphic>();
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
auto& transform = this->getComponent<pod::Transform<>>();
|
||||
if ( !graphic.initialized ) return;
|
||||
auto& shader = graphic.material.getShader("vertex");
|
||||
auto& mesh = this->getComponent<uf::Mesh>();
|
||||
|
||||
bool isGlyph = this->hasComponent<ext::GuiBehavior::GlyphMetadata>();
|
||||
|
||||
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<uf::Camera>();
|
||||
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 );
|
||||
|
||||
82
ext/main.cpp
82
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<uf::stl::string>() == "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<size_t>();
|
||||
UF_MSG_DEBUG("Using async worker threads");
|
||||
} else if ( configEngineThreadJson["workers"].as<uf::stl::string>() == "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<size_t>();
|
||||
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<uf::stl::string>() == "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<uf::stl::string>() );
|
||||
}
|
||||
@ -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<uf::stl::string>() );
|
||||
}
|
||||
/*
|
||||
"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>() ) {\
|
||||
uf::stl::string format = configRenderJson["formats"][#key].as<uf::stl::string>();\
|
||||
@ -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<bool>(true) ) {
|
||||
@ -460,10 +484,11 @@ void EXT_API ext::initialize() {
|
||||
if ( ::json["engine"]["render modes"]["stereo deferred"].as<bool>() ) {
|
||||
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<bool>() ) function(); else uf::thread::add( uf::thread::get("Main"), function, true );
|
||||
if ( json["immediate"].as<bool>() ) 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<uf::Asset>();
|
||||
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
|
||||
|
||||
1
makefiles/default/arch
Normal file
1
makefiles/default/arch
Normal file
@ -0,0 +1 @@
|
||||
win64
|
||||
1
makefiles/default/cc
Normal file
1
makefiles/default/cc
Normal file
@ -0,0 +1 @@
|
||||
gcc
|
||||
1
makefiles/default/renderer
Normal file
1
makefiles/default/renderer
Normal file
@ -0,0 +1 @@
|
||||
vulkan
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
FLAGS += -std=c++20 $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always
|
||||
Loading…
Reference in New Issue
Block a user