revamped makefiles, overhauled memory pool allocator (instantiator works without memory pooling as a byproduct)
This commit is contained in:
parent
3965d3f719
commit
b523878912
510
Makefile
510
Makefile
@ -1,419 +1,96 @@
|
||||
ARCH = $(shell cat "./makefiles/default/arch")
|
||||
CC = $(shell cat "./makefiles/default/cc")
|
||||
RENDERER = $(shell cat "./makefiles/default/renderer")
|
||||
TARGET_NAME = program
|
||||
TARGET_EXTENSION = .exe
|
||||
DLIB_EXTENSION = .dll
|
||||
SLIB_EXTENSION = .a
|
||||
PREFIX = $(ARCH).$(CC)
|
||||
# Defaults
|
||||
ARCH = $(shell cat "./makefiles/default/arch")
|
||||
CC = $(shell cat "./makefiles/default/cc")
|
||||
RENDERER = $(shell cat "./makefiles/default/renderer")
|
||||
TARGET_NAME = program
|
||||
TARGET_EXTENSION = .exe
|
||||
DLIB_EXTENSION = .dll
|
||||
SLIB_EXTENSION = .a
|
||||
PREFIX = $(ARCH).$(CC).$(RENDERER)
|
||||
|
||||
include makefiles/$(PREFIX).make
|
||||
# Basic Paths
|
||||
7Z ?= /c/Program\ Files/7-Zip/7z.exe
|
||||
CXX := $(CDIR)$(CXX)
|
||||
BIN_DIR += ./bin
|
||||
|
||||
PREFIX = $(ARCH).$(CC).$(RENDERER)
|
||||
PREFIX_PATH = $(ARCH)/$(CC)/$(RENDERER)
|
||||
ENGINE_SRC_DIR += ./engine/src
|
||||
ENGINE_INC_DIR += ./engine/inc
|
||||
ENGINE_LIB_DIR += ./engine/lib
|
||||
DEP_SRC_DIR += ./dep/src
|
||||
EXT_SRC_DIR += ./ext
|
||||
CLIENT_SRC_DIR += ./client
|
||||
|
||||
.PHONY: $(PREFIX)
|
||||
@echo "Setting defaults: $(ARCH).$(CC).$(RENDERER)"
|
||||
# Base Flags
|
||||
OPTIMIZATIONS = -O3 -fstrict-aliasing -DUF_NO_EXCEPTIONS
|
||||
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++2b $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always -DUF_DEV_ENV
|
||||
|
||||
# Base Library Definitions
|
||||
LIB_NAME += uf
|
||||
EXT_LIB_NAME += ext
|
||||
PREFIX_PATH = $(ARCH)/$(CC)/$(RENDERER)
|
||||
INC_DIR += $(ENGINE_INC_DIR)
|
||||
LIB_DIR += $(ENGINE_LIB_DIR)
|
||||
|
||||
INCS += -I$(ENGINE_INC_DIR) -I./dep/include/
|
||||
LIBS += -L$(ENGINE_LIB_DIR) -L$(LIB_DIR)/$(PREFIX_PATH)/ -L$(LIB_DIR)/$(ARCH)/$(CC)/ -L$(LIB_DIR)/$(ARCH)/
|
||||
LINKS += $(UF_LIBS) $(EXT_LIBS) $(DEPS)
|
||||
|
||||
# DLL
|
||||
SRCS_DLL := $(shell find $(ENGINE_SRC_DIR) -name "*.cpp") $(shell find $(DEP_SRC_DIR) -name "*.cpp")
|
||||
OBJS_DLL += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_DLL))
|
||||
BASE_DLL += lib$(LIB_NAME)
|
||||
|
||||
IM_DLL += $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL)$(DLIB_EXTENSION)
|
||||
EX_DLL += $(BIN_DIR)/exe/lib/$(PREFIX_PATH)/$(BASE_DLL)$(DLIB_EXTENSION)
|
||||
|
||||
EXT_IM_DLL += $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL)$(DLIB_EXTENSION)
|
||||
EXT_EX_DLL += $(BIN_DIR)/exe/lib/$(PREFIX_PATH)/$(BASE_EXT_DLL)$(DLIB_EXTENSION)
|
||||
|
||||
SRCS_EXT_DLL := $(shell find $(EXT_SRC_DIR) -name "*.cpp")
|
||||
OBJS_EXT_DLL += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_EXT_DLL))
|
||||
BASE_EXT_DLL += lib$(EXT_LIB_NAME)
|
||||
|
||||
EXT_DEPS += -l$(LIB_NAME) $(DEPS)
|
||||
EXT_INC_DIR += $(INC_DIR)
|
||||
EXT_INCS += $(INCS)
|
||||
EXT_LIBS += $(LIBS)
|
||||
EXT_LINKS += $(UF_LIBS) $(EXT_LIBS) $(EXT_DEPS)
|
||||
|
||||
# Executable
|
||||
SRCS := $(shell find $(CLIENT_SRC_DIR) -name "*.cpp")
|
||||
OBJS += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS))
|
||||
TARGET += $(BIN_DIR)/exe/$(TARGET_NAME).$(PREFIX)$(TARGET_EXTENSION)
|
||||
|
||||
# Shaders
|
||||
SRCS_SHADERS := $(shell find bin/data/shaders/ -name "*.glsl")
|
||||
TARGET_SHADERS += $(patsubst %.glsl,%.spv,$(SRCS_SHADERS))
|
||||
|
||||
.DEFAULT_GOAL := $(PREFIX)
|
||||
|
||||
.PHONY: $(PREFIX) clean run run-debug clean-shaders backup
|
||||
.FORCE:
|
||||
|
||||
CXX := $(CDIR)$(CXX)
|
||||
BIN_DIR += ./bin
|
||||
|
||||
ENGINE_SRC_DIR += ./engine/src
|
||||
ENGINE_INC_DIR += ./engine/inc
|
||||
ENGINE_LIB_DIR += ./engine/lib
|
||||
DEP_SRC_DIR += ./dep/src
|
||||
|
||||
EXT_SRC_DIR += ./ext
|
||||
CLIENT_SRC_DIR += ./client
|
||||
|
||||
|
||||
UF_LIBS +=
|
||||
EXT_LIBS +=
|
||||
FLAGS +=
|
||||
LIB_NAME += uf
|
||||
EXT_LIB_NAME += ext
|
||||
|
||||
7Z += /c/Program\ Files/7-Zip/7z.exe
|
||||
include makefiles/platforms/$(ARCH).$(CC).mk
|
||||
|
||||
ifneq (,$(findstring win64,$(ARCH)))
|
||||
VULKAN_SDK_PATH = /c/VulkanSDK/1.4.321.1/
|
||||
GLSLC = $(VULKAN_SDK_PATH)/Bin/glslc
|
||||
SPV_OPTIMIZER = $(VULKAN_SDK_PATH)/Bin/spirv-opt
|
||||
SPV_LINTER = $(VULKAN_SDK_PATH)/Bin/spirv-lint
|
||||
else
|
||||
VULKAN_SDK_PATH = /
|
||||
GLSLC = glslc
|
||||
SPV_OPTIMIZER = spirv-opt
|
||||
SPV_LINTER = spirv-lint
|
||||
endif
|
||||
|
||||
|
||||
# Base Engine's DLL
|
||||
INC_DIR += $(ENGINE_INC_DIR)
|
||||
LIB_DIR += $(ENGINE_LIB_DIR)
|
||||
|
||||
INCS += -I$(ENGINE_INC_DIR) -I./dep/include/
|
||||
LIBS += -L$(ENGINE_LIB_DIR) -L$(LIB_DIR)/$(PREFIX_PATH)/ -L$(LIB_DIR)/$(ARCH)/$(CC)/ -L$(LIB_DIR)/$(ARCH)/
|
||||
|
||||
LINKS += $(UF_LIBS) $(EXT_LIBS) $(DEPS)
|
||||
DEPS +=
|
||||
FLAGS += -DUF_DEV_ENV
|
||||
|
||||
ifneq (,$(findstring win64,$(ARCH)))
|
||||
ifneq (,$(findstring -DUF_DEV_ENV,$(FLAGS)))
|
||||
REQ_DEPS += meshoptimizer toml xatlas curl ffx:sdk dc:texconv # vall_e cpptrace # openvr # ncurses draco discord bullet ultralight-ux
|
||||
FLAGS += -march=native -g # -flto # -g
|
||||
endif
|
||||
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit r:eactphysics simd ctti gltf imgui fmt freetype openal ogg wav
|
||||
FLAGS += -DUF_ENV_WINDOWS -DUF_ENV_WIN64 -DWIN32_LEAN_AND_MEAN
|
||||
DEPS += -lgdi32 -ldwmapi
|
||||
LINKS += #-Wl,-subsystem,windows
|
||||
INCS := -I./dep/master/include $(INCS)
|
||||
include makefiles/platforms/win64.mk
|
||||
else ifneq (,$(findstring linux,$(ARCH)))
|
||||
ifneq (,$(findstring -DUF_DEV_ENV,$(FLAGS)))
|
||||
REQ_DEPS += toml xatlas curl dc:texconv # meshoptimizer ffx:fsr cpptrace vall_e # ncurses openvr draco discord bullet ultralight-ux
|
||||
FLAGS += -march=native -g # -flto # -g
|
||||
endif
|
||||
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit r:eactphysics simd ctti gltf imgui fmt freetype openal ogg wav
|
||||
FLAGS += -DUF_ENV_LINUX -fPIC
|
||||
DEPS += -pthread -ldl -lX11 -lXrandr
|
||||
INCS := -I./dep/master/include $(INCS)
|
||||
include makefiles/platforms/linux.mk
|
||||
else ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
FLAGS += -DUF_ENV_DREAMCAST # -DUF_LEAN_AND_MEAN # this apparently crashes
|
||||
REQ_DEPS += opengl gldc json:nlohmann zlib lua r:eactphysics simd ctti fmt freetype openal aldc ogg wav png # imgui
|
||||
INCS := -I./dep/dreamcast/include $(INCS)
|
||||
include makefiles/platforms/dreamcast.mk
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring ffx:sdk,$(REQ_DEPS)))
|
||||
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_FFX_SDK=3
|
||||
#INCS += -I./dep/include/ffx_fsr2/
|
||||
#DEPS += -lffx_fsr3_x64drel -lffx_fsr2_x64drel -lffx_fsr3upscaler_x64drel -lffx_frameinterpolation_x64drel -lffx_opticalflow_x64drel -lffx_backend_vk_x64drel -lamd_fidelityfx_vkdrel
|
||||
DEPS += -lffx_fsr3_x64 -lffx_fsr2_x64 -lffx_fsr3upscaler_x64 -lffx_frameinterpolation_x64 -lffx_opticalflow_x64 -lffx_backend_vk_x64 -lamd_fidelityfx_vk
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_VULKAN
|
||||
DEPS += -lspirv-cross-core -lspirv-cross-cpp #-lVulkanMemoryAllocator
|
||||
INCS += -I$(VULKAN_SDK_PATH)/include -I./dep/include/spirv_cross/
|
||||
LIBS += -L$(VULKAN_SDK_PATH)/Lib
|
||||
|
||||
ifneq (,$(findstring linux,$(ARCH)))
|
||||
DEPS += -lvulkan
|
||||
FLAGS += -DVK_USE_PLATFORM_XLIB_KHR # VK_USE_PLATFORM_XCB_KHR
|
||||
else
|
||||
DEPS += -lvulkan-1
|
||||
FLAGS += -DVK_USE_PLATFORM_WIN32_KHR
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(findstring opengl,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_OPENGL -DUF_USE_OPENGL_FIXED_FUNCTION
|
||||
include makefiles/dependencies.mk
|
||||
|
||||
ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
ifneq (,$(findstring gldc,$(REQ_DEPS)))
|
||||
DEPS += -lGL # kos-ports version saves it as libGL instead of libGLdc
|
||||
FLAGS += -DUF_USE_OPENGL_GLDC
|
||||
else
|
||||
DEPS += -lGL
|
||||
endif
|
||||
else
|
||||
# software rendering version through GLdc
|
||||
ifneq (,$(findstring gldc,$(REQ_DEPS)))
|
||||
DEPS += -lGLdc -lSDL2
|
||||
FLAGS += -DUF_USE_OPENGL_GLDC
|
||||
# OpenGL through GLEW
|
||||
else
|
||||
FLAGS += -DUF_USE_GLEW
|
||||
ifneq (,$(findstring linux,$(ARCH)))
|
||||
DEPS += -lGLU -lglut -lGLEW
|
||||
else
|
||||
DEPS += -lglew32 -lopengl32 -lglu32
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
# Build Rules
|
||||
|
||||
endif
|
||||
ifneq (,$(findstring fmt,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_FMT
|
||||
ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
# dreamcast uses a header only version because reasons
|
||||
else
|
||||
DEPS += -lfmt
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(findstring ffx:fsr,$(REQ_DEPS)))
|
||||
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_FFX_FSR
|
||||
#INCS += -I./dep/include/ffx_fsr2/
|
||||
DEPS += -lffx_fsr2_api_ -lffx_fsr2_api_vk_
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(findstring imgui,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_IMGUI
|
||||
INCS += -I./dep/include/imgui/
|
||||
INCS += -I./dep/include/imgui/backends
|
||||
endif
|
||||
ifneq (,$(findstring cpptrace,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_CPPTRACE
|
||||
DEPS += -lcpptrace
|
||||
endif
|
||||
ifneq (,$(findstring json,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_JSON
|
||||
DEPS +=
|
||||
ifneq (,$(findstring nlohmann,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_JSON_USE_NLOHMANN
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(findstring gltf,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_GLTF
|
||||
INCS += -I./dep/include/stb/ # saves having to edit the file
|
||||
INCS += -I./dep/include/nlohmann/ # saves having to edit the file
|
||||
endif
|
||||
ifneq (,$(findstring dc:texconv,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_DC_TEXCONV
|
||||
endif
|
||||
ifneq (,$(findstring openal,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_OPENAL -DUF_USE_ALUT
|
||||
ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
ifneq (,$(findstring aldc,$(REQ_DEPS)))
|
||||
DEPS += -lAL -lpthread # kos-ports version saves it as libAL instead of libALdc
|
||||
FLAGS += -DUF_USE_OPENAL_ALDC -DUF_USE_ALUT
|
||||
else
|
||||
DEPS += -lAL
|
||||
endif
|
||||
else
|
||||
DEPS += -lopenal -lalut
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(findstring ogg,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_VORBIS
|
||||
ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
FLAGS += -DUF_USE_TREMOR
|
||||
DEPS += -ltremor
|
||||
else
|
||||
DEPS += -lvorbis -lvorbisfile -logg
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(findstring wav,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_WAV
|
||||
endif
|
||||
ifneq (,$(findstring zlib,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_ZLIB
|
||||
DEPS += -lz
|
||||
endif
|
||||
ifneq (,$(findstring freetype,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_FREETYPE
|
||||
DEPS += -lfreetype -lbz2
|
||||
endif
|
||||
ifneq (,$(findstring curl,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_CURL
|
||||
DEPS += -lcurl
|
||||
endif
|
||||
ifneq (,$(findstring openvr,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_OPENVR -DUSE_OPENVR_MINGW
|
||||
DEPS += -lopenvr_api
|
||||
endif
|
||||
ifneq (,$(findstring lua,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_LUA
|
||||
ifneq (,$(findstring luajit,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_LUAJIT
|
||||
DEPS += -lluajit-5.1
|
||||
|
||||
# sol directly includes <luajit.h>
|
||||
ifneq (,$(findstring linux,$(ARCH)))
|
||||
INCS += -I/usr/include/luajit-2.1
|
||||
else
|
||||
ifneq (,$(findstring clang,$(CC)))
|
||||
INCS += -I/clang64/include/luajit-2.1
|
||||
else
|
||||
INCS += -I/mingw64/include/luajit-2.1
|
||||
endif
|
||||
endif
|
||||
else
|
||||
ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
DEPS += -llua
|
||||
INCS += -I/opt/dreamcast/kos-ports/include/lua
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(findstring reactphysics,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_REACTPHYSICS
|
||||
DEPS += -lreactphysics3d
|
||||
endif
|
||||
ifneq (,$(findstring simd,$(REQ_DEPS)))
|
||||
ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
FLAGS += -DUF_ENV_DREAMCAST_SIMD
|
||||
else
|
||||
FLAGS += -DUF_USE_SIMD -DUF_ALIGN_FOR_SIMD -DUF_MATRIX_ALIGNED #-DUF_VECTOR_ALIGNED #-march=native
|
||||
endif
|
||||
endif
|
||||
ifneq (,$(findstring meshoptimizer,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_MESHOPT
|
||||
DEPS += -lmeshoptimizer
|
||||
endif
|
||||
ifneq (,$(findstring xatlas,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_XATLAS
|
||||
endif
|
||||
ifneq (,$(findstring ctti,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_CTTI -fno-rtti
|
||||
else
|
||||
FLAGS += -DUF_RTTI -rtti
|
||||
endif
|
||||
ifneq (,$(findstring toml,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_TOML
|
||||
endif
|
||||
ifneq (,$(findstring vall_e,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_VALL_E
|
||||
INCS += -I./dep/include/vall_e.cpp/
|
||||
DEPS += -lvall_e
|
||||
endif
|
||||
ifneq (,$(findstring draco,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_DRACO
|
||||
DEPS += -ldraco
|
||||
endif
|
||||
ifneq (,$(findstring ultralight-ux,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_ULTRALIGHT_UX
|
||||
DEPS += -lUltralight -lUltralightCore -lWebCore -lAppCore
|
||||
endif
|
||||
ifneq (,$(findstring discord,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_DISCORD
|
||||
DEPS += -ldiscord_game_sdk
|
||||
endif
|
||||
ifneq (,$(findstring ncurses,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_NCURSES
|
||||
DEPS += -lncursesw
|
||||
endif
|
||||
ifneq (,$(findstring png,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_PNG
|
||||
DEPS += -lpng
|
||||
endif
|
||||
ifneq (,$(findstring lz4,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_LZ4
|
||||
DEPS += -llz4
|
||||
endif
|
||||
ifneq (,$(findstring xz,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_XZ -DUF_USE_LZMA
|
||||
DEPS += -lxz -llzma
|
||||
endif
|
||||
|
||||
SRCS_DLL := $(shell find $(ENGINE_SRC_DIR) -name "*.cpp") $(shell find $(DEP_SRC_DIR) -name "*.cpp")
|
||||
OBJS_DLL += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_DLL))
|
||||
BASE_DLL += lib$(LIB_NAME)
|
||||
IM_DLL += $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL)$(DLIB_EXTENSION)
|
||||
EX_DLL += $(BIN_DIR)/exe/lib/$(PREFIX_PATH)/$(BASE_DLL)$(DLIB_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)
|
||||
|
||||
EXT_LIB_DIR += $(ENGINE_LIB_DIR)/$(ARCH)
|
||||
EXT_INCS += $(INCS)
|
||||
EXT_LIBS += $(LIBS)
|
||||
|
||||
#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)
|
||||
SRCS_EXT_DLL := $(shell find $(EXT_SRC_DIR) -name "*.cpp")
|
||||
OBJS_EXT_DLL += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_EXT_DLL))
|
||||
BASE_EXT_DLL += lib$(EXT_LIB_NAME)
|
||||
EXT_IM_DLL += $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL)$(DLIB_EXTENSION)
|
||||
EXT_EX_DLL += $(BIN_DIR)/exe/lib/$(PREFIX_PATH)/$(BASE_EXT_DLL)$(DLIB_EXTENSION)
|
||||
# Client EXE
|
||||
#SRCS += $(wildcard $(CLIENT_SRC_DIR)/*.cpp) $(wildcard $(CLIENT_SRC_DIR)/*/*.cpp)
|
||||
SRCS := $(shell find $(CLIENT_SRC_DIR) -name "*.cpp")
|
||||
OBJS += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS))
|
||||
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)
|
||||
SRCS_SHADERS := $(shell find bin/data/shaders/ -name "*.glsl")
|
||||
TARGET_SHADERS += $(patsubst %.glsl,%.spv,$(SRCS_SHADERS))
|
||||
|
||||
ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
#$(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)
|
||||
SRCS_DLL = $(shell find $(ENGINE_SRC_DIR) -name "*.cpp") $(shell find $(DEP_SRC_DIR) -name "*.cpp")
|
||||
OBJS_DLL = $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_DLL))
|
||||
OBJS = $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_DLL)) $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_EXT_DLL)) $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS))
|
||||
|
||||
DEPS += -lkallisti -lc -lm -lgcc -lstdc++ # -l$(LIB_NAME) -l$(EXT_LIB_NAME)
|
||||
|
||||
INCS += -I$(KOS_PORTS)/include
|
||||
LIBS += -I$(KOS_PORTS)/lib
|
||||
|
||||
%.$(PREFIX).o: %.cpp
|
||||
$(CXX) $(FLAGS) $(INCS) -c $< -o $@
|
||||
|
||||
$(EX_DLL): FLAGS += -DUF_EXPORTS
|
||||
$(EX_DLL): $(OBJS_DLL)
|
||||
$(KOS_AR) cru $@ $^
|
||||
$(KOS_RANLIB) $@
|
||||
cp $@ $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL)
|
||||
|
||||
$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS
|
||||
$(EXT_EX_DLL): $(OBJS_EXT_DLL)
|
||||
$(KOS_AR) cru $@ $^
|
||||
$(KOS_RANLIB) $@
|
||||
cp $@ $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL)
|
||||
|
||||
./bin/dreamcast/romdisk.img:
|
||||
$(KOS_GENROMFS) -f ./bin/dreamcast/romdisk.img -d ./bin/dreamcast/romdisk/ -v
|
||||
|
||||
./bin/dreamcast/romdisk.o: ./bin/dreamcast/romdisk.img
|
||||
$(KOS_BASE)/utils/bin2o/bin2o ./bin/dreamcast/romdisk.img romdisk ./bin/dreamcast/romdisk.o
|
||||
|
||||
$(TARGET): $(OBJS) #./bin/dreamcast/romdisk.o
|
||||
$(CXX) $(FLAGS) $(INCS) -D_arch_dreamcast -D_arch_sub_pristine -Wall -fno-builtin -ml -Wl,-Ttext=0x8c010000 -T/opt/dreamcast/kos/utils/ldscripts/shlelf.xc -nodefaultlibs $(KOS_LIB_PATHS) $(LIBS) -o $(TARGET) $(OBJS) -Wl,--start-group $(DEPS) -Wl,--end-group
|
||||
cp $(TARGET) $(TARGET).unstripped
|
||||
$(KOS_STRIP) --strip-unneeded $(TARGET)
|
||||
|
||||
./bin/dreamcast/$(TARGET_NAME).cdi: $(TARGET)
|
||||
cd ./bin/dreamcast/; ./elf2cdi.sh $(TARGET_NAME)
|
||||
|
||||
cdi:
|
||||
cd ./bin/dreamcast/; ./elf2cdi.sh $(TARGET_NAME)
|
||||
|
||||
else
|
||||
$(PREFIX): $(EX_DLL) $(EXT_EX_DLL) $(TARGET) $(TARGET_SHADERS)
|
||||
|
||||
%.$(PREFIX).o: %.cpp
|
||||
$(CXX) $(FLAGS) $(INCS) -c $< -o $@
|
||||
|
||||
ifneq (,$(findstring linux,$(ARCH)))
|
||||
#$(EX_DLL): FLAGS += -DUF_EXPORTS -DEXT_EXPORTS
|
||||
$(EX_DLL): FLAGS += -DUF_EXPORTS
|
||||
$(EX_DLL): $(OBJS_DLL)
|
||||
$(CXX) $(FLAGS) -shared -Wl,-soname,$(BASE_DLL)$(DLIB_EXTENSION) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS) -o $(EX_DLL)
|
||||
cp $(EX_DLL) $(IM_DLL)
|
||||
@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
|
||||
$(EXT_EX_DLL): $(OBJS_EXT_DLL)
|
||||
$(CXX) $(FLAGS) -shared -Wl,-soname,$(BASE_EXT_DLL)$(DLIB_EXTENSION) $(OBJS_EXT_DLL) $(EXT_LIBS) $(EXT_INCS) $(EXT_LINKS) -o $(EXT_EX_DLL)
|
||||
cp $(EXT_EX_DLL) $(EXT_IM_DLL)
|
||||
|
||||
else
|
||||
|
||||
#$(EX_DLL): FLAGS += -DUF_EXPORTS -DEXT_EXPORTS
|
||||
$(EX_DLL): FLAGS += -DUF_EXPORTS
|
||||
$(EX_DLL): $(OBJS_DLL)
|
||||
$(CXX) $(FLAGS) -shared -o $(EX_DLL) -Wl,--out-implib=$(IM_DLL)$(SLIB_EXTENSION) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS)
|
||||
@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
|
||||
$(EXT_EX_DLL): $(OBJS_EXT_DLL)
|
||||
$(CXX) $(FLAGS) -shared -o $(EXT_EX_DLL) -Wl,--out-implib=$(EXT_IM_DLL)$(SLIB_EXTENSION) $(OBJS_EXT_DLL) $(EXT_LIBS) $(EXT_INCS) $(EXT_LINKS)
|
||||
|
||||
endif
|
||||
|
||||
ifneq ($(ARCH),dreamcast)
|
||||
$(TARGET): $(OBJS)
|
||||
$(CXX) $(FLAGS) $(OBJS) $(LIBS) $(INCS) $(LINKS) -l$(LIB_NAME) -l$(EXT_LIB_NAME) -o $(TARGET)
|
||||
endif
|
||||
@ -434,55 +111,20 @@ clean:
|
||||
@-rm -f $(OBJS_EXT_DLL)
|
||||
@-rm -f $(OBJS)
|
||||
|
||||
#@-rm $(shell find $(ENGINE_SRC_DIR) -name "*.$(PREFIX).o") $(shell find $(EXT_SRC_DIR) -name "*.$(PREFIX).o") $(shell find $(DEP_SRC_DIR) -name "*.$(PREFIX).o")
|
||||
|
||||
ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
@-rm ./bin/dreamcast/build/*
|
||||
@-rm ./bin/dreamcast/romdisk.*
|
||||
@-rm ./bin/dreamcast/$(TARGET_NAME).*
|
||||
endif
|
||||
clean-shaders:
|
||||
@-rm -f $(TARGET_SHADERS)
|
||||
|
||||
run:
|
||||
ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
$(KOS_EMU) ./bin/dreamcast/$(TARGET_NAME).cdi
|
||||
else
|
||||
@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
|
||||
|
||||
run-debug:
|
||||
ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
$(KOS_EMU_DEBUG) ./bin/dreamcast/$(TARGET_NAME).cdi
|
||||
else
|
||||
@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)"
|
||||
./debug.sh
|
||||
endif
|
||||
|
||||
clean-zips:
|
||||
@-find ./bin/data/ -name "*.gz" -type f -delete
|
||||
|
||||
clean-uf:
|
||||
@-rm $(EX_DLL)
|
||||
@-rm -f $(OBJS_DLL)
|
||||
|
||||
clean-exf:
|
||||
@-rm $(EXT_EX_DLL)
|
||||
@-rm -f $(OBJS_EXT_DLL)
|
||||
|
||||
clean-exe:
|
||||
-rm $(EX_DLL)
|
||||
-rm $(EXT_EX_DLL)
|
||||
-rm $(TARGET)
|
||||
-rm $(TARGET_SHADERS)
|
||||
|
||||
clean-shaders:
|
||||
-rm $(TARGET_SHADERS)
|
||||
|
||||
backup:
|
||||
@-rm $(shell find $(ENGINE_SRC_DIR) -name "*.o") $(shell find $(EXT_SRC_DIR) -name "*.o") $(shell find $(DEP_SRC_DIR) -name "*.o")
|
||||
|
||||
@ -85,8 +85,8 @@ int main(int argc, char** argv){
|
||||
signal(SIGSEGV, ::handlers::segv);
|
||||
|
||||
client::initialize();
|
||||
ext::initialize();
|
||||
uf::initialize();
|
||||
ext::initialize();
|
||||
|
||||
// For Multithreaded initialization
|
||||
while ( !client::ready || !uf::ready ) {
|
||||
|
||||
@ -47,6 +47,7 @@ namespace uf {
|
||||
extern UF_API pod::NamedTypes<pod::Instantiator>* objects;
|
||||
// extern UF_API pod::NamedTypes<pod::Behavior>* behaviors;
|
||||
extern UF_API uf::stl::unordered_map<uf::stl::string, pod::Behavior>* behaviors;
|
||||
extern UF_API uf::stl::vector<uf::Entity*> queue;
|
||||
|
||||
uf::Entity* UF_API alloc( size_t );
|
||||
template<typename T> T* alloc();
|
||||
@ -66,6 +67,8 @@ namespace uf {
|
||||
template<typename T> T& instantiate();
|
||||
template<typename T> T* _instantiate();
|
||||
|
||||
void UF_API queueDeletion( uf::Entity& );
|
||||
|
||||
void UF_API bind( const uf::stl::string&, uf::Entity& );
|
||||
template<typename T> void bind( uf::Entity& );
|
||||
|
||||
|
||||
@ -6,12 +6,15 @@
|
||||
#include <uf/utils/memory/string.h>
|
||||
#include <mutex>
|
||||
|
||||
#define UF_MEMORYPOOL_MUTEX 1
|
||||
#define UF_MEMORYPOOL_INVALID_MALLOC 1
|
||||
#define UF_MEMORYPOOL_INVALID_FREE 1
|
||||
|
||||
#define UF_MEMORYPOOL_CACHED_ALLOCATIONS 0
|
||||
#define UF_MEMORYPOOL_STORE_ORPHANS 0
|
||||
|
||||
#define UF_MAX_BUCKETS 4096 // E.g., 16, 32, 64, 128, 256, 512, 1024, 2048 bytes
|
||||
|
||||
namespace pod {
|
||||
struct UF_API Userdata;
|
||||
|
||||
@ -20,22 +23,52 @@ namespace pod {
|
||||
uintptr_t pointer = 0;
|
||||
};
|
||||
|
||||
struct UF_API MemoryPool {
|
||||
typedef std::vector<pod::Allocation, uf::Mallocator<pod::Allocation>> allocations_t;
|
||||
struct MemoryPool {
|
||||
// in order of complexity
|
||||
enum Strategy {
|
||||
LINEAR,
|
||||
POOL,
|
||||
SEGREGATED,
|
||||
BUDDY
|
||||
};
|
||||
|
||||
void* memory = nullptr;
|
||||
size_t size = 0;
|
||||
void* memory = 0;
|
||||
size_t used = 0;
|
||||
|
||||
Strategy strategy = Strategy::BUDDY;
|
||||
union State {
|
||||
// linear
|
||||
struct { size_t offset; } linear;
|
||||
|
||||
// pool
|
||||
struct { void* freeListHead; size_t fixedChunkSize; } pool;
|
||||
|
||||
// segregated
|
||||
struct {
|
||||
void* freeListHeads[UF_MAX_BUCKETS];
|
||||
size_t offset; // To carve new memory when a bucket is empty
|
||||
size_t minChunkSize; // Base size, e.g., 16 bytes
|
||||
} segregated;
|
||||
|
||||
// buddy
|
||||
struct {
|
||||
void* freeLists[32]; // Max 32 levels for powers of two up to 4GB
|
||||
uint8_t* splitBlockBitset; // Tracks if a block was split
|
||||
size_t maxLevel;
|
||||
size_t minBlockSize;
|
||||
} buddy;
|
||||
} state;
|
||||
|
||||
typedef std::vector<pod::Allocation, uf::Mallocator<pod::Allocation>> allocations_t;
|
||||
#if UF_MEMORYPOOL_MUTEX
|
||||
std::mutex mutex;
|
||||
allocations_t allocations;
|
||||
|
||||
#if UF_MEMORYPOOL_CACHED_ALLOCATIONS
|
||||
allocations_t cachedFreeAllocations;
|
||||
#endif
|
||||
#if UF_MEMORYPOOL_STORE_ORPHANS
|
||||
allocations_t orphaned;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace uf {
|
||||
@ -46,7 +79,7 @@ namespace uf {
|
||||
size_t UF_API size( const pod::MemoryPool& );
|
||||
size_t UF_API allocated( const pod::MemoryPool& );
|
||||
uf::stl::string UF_API stats( const pod::MemoryPool& );
|
||||
void UF_API initialize( pod::MemoryPool&, size_t );
|
||||
void UF_API initialize( pod::MemoryPool&, size_t, pod::MemoryPool::Strategy = pod::MemoryPool::Strategy::BUDDY, size_t = 0 );
|
||||
void UF_API destroy( pod::MemoryPool& );
|
||||
|
||||
// pod::Allocation UF_API allocate( pod::MemoryPool&, void*, size_t, size_t alignment = uf::memoryPool::alignment );
|
||||
@ -79,7 +112,7 @@ namespace uf {
|
||||
inline size_t size() const;
|
||||
inline size_t allocated() const;
|
||||
inline uf::stl::string stats() const;
|
||||
inline void initialize( size_t size );
|
||||
inline void initialize( size_t size, pod::MemoryPool::Strategy = pod::MemoryPool::Strategy::BUDDY, size_t = 0 );
|
||||
inline void destroy();
|
||||
|
||||
// inline pod::Allocation allocate( void* data, size_t size/*, size_t alignment = uf::memoryPool::alignment*/ );
|
||||
@ -89,7 +122,7 @@ namespace uf {
|
||||
inline void* alloc( size_t size/*, size_t alignment = uf::memoryPool::alignment*/ );
|
||||
inline pod::Allocation& fetch( void* data, size_t size = 0 );
|
||||
inline bool exists( void* data, size_t size = 0 );
|
||||
inline bool free( void* data, size_t size = 0 );
|
||||
inline bool free( void* data, size_t size );
|
||||
|
||||
inline const pod::MemoryPool::allocations_t& allocations() const;
|
||||
inline pod::MemoryPool& data();
|
||||
|
||||
@ -27,13 +27,23 @@ bool uf::memoryPool::exists( pod::MemoryPool& pool, const T& data ) {
|
||||
}
|
||||
template<typename T>
|
||||
bool uf::memoryPool::free( pod::MemoryPool& pool, const T& data ) {
|
||||
return std::is_pointer<T>::value ? uf::memoryPool::free( pool, (void*) data ) : uf::memoryPool::free( pool, (void*) &data, sizeof(data) );
|
||||
#if __cplusplus >= 201703L
|
||||
if constexpr (std::is_pointer_v<T>) {
|
||||
return uf::memoryPool::free( pool, (void*) data, sizeof(std::remove_pointer_t<T>) );
|
||||
} else {
|
||||
return uf::memoryPool::free( pool, (void*) &data, sizeof(T) );
|
||||
}
|
||||
#else
|
||||
return std::is_pointer<T>::value
|
||||
? uf::memoryPool::free( pool, (void*) data, sizeof(typename std::remove_pointer<T>::type) )
|
||||
: uf::memoryPool::free( pool, (void*) &data, sizeof(T) );
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t uf::MemoryPool::size() const { return uf::memoryPool::size( m_pod ); }
|
||||
size_t uf::MemoryPool::allocated() const { return uf::memoryPool::allocated( m_pod ); }
|
||||
uf::stl::string uf::MemoryPool::stats() const { return uf::memoryPool::stats( m_pod ); }
|
||||
void uf::MemoryPool::initialize( size_t size ) { return uf::memoryPool::initialize( m_pod, size ); }
|
||||
void uf::MemoryPool::initialize( size_t size, pod::MemoryPool::Strategy strategy, size_t chunkSize ) { return uf::memoryPool::initialize( m_pod, size, strategy, chunkSize ); }
|
||||
void uf::MemoryPool::destroy() { return uf::memoryPool::destroy( m_pod ); }
|
||||
|
||||
//pod::Allocation uf::MemoryPool::allocate( void* data, size_t size/*, size_t alignment*/ ) { return uf::memoryPool::allocate( m_pod, data, size/*, alignment*/ ); }
|
||||
|
||||
@ -425,7 +425,7 @@ void UF_API uf::initialize() {
|
||||
{
|
||||
size_t size = deduceSize( configMemoryPoolJson["pools"]["entity"] );
|
||||
UF_MSG_DEBUG("Requesting {} bytes for entity memory pool: {}", (int) size, (void*) &uf::Entity::memoryPool);
|
||||
uf::Entity::memoryPool.initialize( size );
|
||||
uf::Entity::memoryPool.initialize( size, pod::MemoryPool::Strategy::POOL, sizeof(uf::Entity) );
|
||||
}
|
||||
}
|
||||
uf::allocator::override = configMemoryPoolJson["override"].as( uf::allocator::override );
|
||||
|
||||
@ -4,12 +4,18 @@
|
||||
#include <uf/engine/scene/scene.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace {
|
||||
std::mutex queueMutex;
|
||||
}
|
||||
|
||||
pod::NamedTypes<pod::Instantiator>* uf::instantiator::objects = NULL;
|
||||
//pod::NamedTypes<pod::Behavior>* uf::instantiator::behaviors = NULL;
|
||||
uf::stl::unordered_map<uf::stl::string, pod::Behavior>* uf::instantiator::behaviors = NULL;
|
||||
uf::stl::vector<uf::Entity*> uf::instantiator::queue;
|
||||
|
||||
uf::Entity* uf::instantiator::reuse( size_t size ) {
|
||||
uf::Entity* laxed = NULL;
|
||||
/*
|
||||
auto& allocations = uf::Entity::memoryPool.allocations();
|
||||
for ( auto& allocation : allocations ) {
|
||||
uf::Entity* e = (uf::Entity*) (allocation.pointer);
|
||||
@ -31,14 +37,16 @@ uf::Entity* uf::instantiator::reuse( size_t size ) {
|
||||
if ( allocation.size == size ) return e;
|
||||
if ( allocation.size > size ) laxed = e;
|
||||
}
|
||||
*/
|
||||
return laxed;
|
||||
}
|
||||
size_t uf::instantiator::collect( uint8_t level ) {
|
||||
/*
|
||||
uf::stl::vector<uf::Entity*> queued;
|
||||
size_t collected = 0;
|
||||
auto& allocations = uf::Entity::memoryPool.allocations();
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
|
||||
uf::stl::vector<uf::Entity*> queued;
|
||||
for ( auto& allocation : allocations ) {
|
||||
uf::Entity* e = (uf::Entity*) (allocation.pointer);
|
||||
// no scenes
|
||||
@ -58,6 +66,12 @@ size_t uf::instantiator::collect( uint8_t level ) {
|
||||
// UF_MSG_DEBUG("Freeing: {}", uf::string::toString(e->as<uf::Object>()));
|
||||
queued.emplace_back( (uf::Entity*) allocation.pointer );
|
||||
}
|
||||
*/
|
||||
// mutex
|
||||
::queueMutex.lock();
|
||||
uf::stl::vector<uf::Entity*> queued = std::move( uf::instantiator::queue );
|
||||
::queueMutex.unlock();
|
||||
|
||||
for ( auto& p : queued ) {
|
||||
if ( p->hasComponent<uf::SceneBehavior::Metadata>() ) continue;
|
||||
// UF_MSG_DEBUG("Destroying: {}", uf::string::toString(*p));
|
||||
@ -68,6 +82,7 @@ size_t uf::instantiator::collect( uint8_t level ) {
|
||||
// UF_MSG_DEBUG("Destroying scene: {}", uf::string::toString(*p));
|
||||
uf::instantiator::free( p );
|
||||
}
|
||||
|
||||
return queued.size();
|
||||
}
|
||||
|
||||
@ -148,6 +163,12 @@ uf::Entity& uf::instantiator::instantiate( const uf::stl::string& name ) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
void UF_API uf::instantiator::queueDeletion( uf::Entity& entity ) {
|
||||
::queueMutex.lock();
|
||||
uf::instantiator::queue.emplace_back(&entity);
|
||||
::queueMutex.unlock();
|
||||
}
|
||||
|
||||
void uf::instantiator::bind( const uf::stl::string& name, uf::Entity& entity ) {
|
||||
// was actually a behavior name, single bind
|
||||
if ( !uf::instantiator::objects->has( name, false ) ) {
|
||||
|
||||
@ -41,7 +41,10 @@ void uf::Object::queueDeletion() {
|
||||
|
||||
if ( this->hasParent() ) this->getParent().removeChild(*this);
|
||||
auto& metadata = this->getComponent<uf::ObjectBehavior::Metadata>();
|
||||
|
||||
// mark for destruction
|
||||
metadata.system.markedForDeletion = true;
|
||||
uf::instantiator::queueDeletion( *this );
|
||||
}
|
||||
|
||||
uf::Hooks::return_t uf::Object::callHook( const uf::stl::string& name ) {
|
||||
|
||||
@ -252,6 +252,8 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
UF_ASSERT( !bounds.empty() );
|
||||
|
||||
// recursively build BVH from indices
|
||||
if ( uf::physics::impl::settings.useBvhSahMeshes ) ::buildBVHNode_SAH( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
else ::buildBVHNode( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
|
||||
@ -146,7 +146,11 @@ void uf::physics::impl::step( pod::World& world, float dt ) {
|
||||
|
||||
// bodies with meshes already reorient the normal to the triangle's center
|
||||
// do not do it for meshes because it'll reorient to the mesh's origin
|
||||
if ( a.collider.type != pod::ShapeType::MESH && b.collider.type != pod::ShapeType::MESH ) {
|
||||
// do not do it for planes
|
||||
bool shouldReorient = true;
|
||||
if ( a.collider.type == pod::ShapeType::MESH || b.collider.type == pod::ShapeType::MESH ) shouldReorient = false;
|
||||
if ( a.collider.type == pod::ShapeType::PLANE || b.collider.type == pod::ShapeType::PLANE ) shouldReorient = false;
|
||||
if ( shouldReorient ) {
|
||||
for ( auto& c : manifold.points ) c.normal = ::orientNormalToAB( a, b, c.normal );
|
||||
}
|
||||
// retrieve accumulated impulses
|
||||
|
||||
@ -32,7 +32,7 @@ namespace {
|
||||
b.velocity += impulse * b.inverseMass;
|
||||
//b.angularVelocity += (uf::vector::cross(rB, impulse)) * b.inverseInertiaTensor;
|
||||
pod::Matrix3f invIb = computeWorldInverseInertia( b );
|
||||
a.angularVelocity += uf::matrix::multiply( invIb, uf::vector::cross(rB, impulse) );
|
||||
b.angularVelocity += uf::matrix::multiply( invIb, uf::vector::cross(rB, impulse) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ namespace {
|
||||
//0, 1, 2, 3, 4, 5
|
||||
0, 2, 1, 3, 5, 4
|
||||
});
|
||||
mesh.updateDescriptor();
|
||||
|
||||
return mesh;
|
||||
}
|
||||
@ -75,7 +76,7 @@ TEST(RaySphere_Hit, {
|
||||
body.transform->position = {0,0,0};
|
||||
body.bounds = ::computeAABB( body );
|
||||
|
||||
::buildBroadphaseBVH( world.bvh, world.bodies );
|
||||
::buildBroadphaseBVH( world.dynamicBvh, world.bodies );
|
||||
|
||||
pod::Ray ray{ {0,0,-5}, uf::vector::normalize(pod::Vector3f{0,0,1}) };
|
||||
pod::RayQuery hit = uf::physics::impl::rayCast(ray, world, 100.0f);
|
||||
@ -183,7 +184,7 @@ TEST(RayAabb_Miss, {
|
||||
box.transform->position = {0,0,0};
|
||||
box.bounds = ::computeAABB( box );
|
||||
|
||||
::buildBroadphaseBVH( world.bvh, world.bodies );
|
||||
::buildBroadphaseBVH( world.dynamicBvh, world.bodies );
|
||||
|
||||
pod::Ray ray{{5,5,5}, uf::vector::normalize(pod::Vector3f{1,0,0})};
|
||||
auto hit = uf::physics::impl::rayCast(ray, world, 100.0f);
|
||||
@ -320,7 +321,7 @@ TEST(RaySphere_OriginInside, {
|
||||
body.transform->position = {0,0,0};
|
||||
body.bounds = ::computeAABB( body );
|
||||
|
||||
::buildBroadphaseBVH( world.bvh, world.bodies );
|
||||
::buildBroadphaseBVH( world.dynamicBvh, world.bodies );
|
||||
|
||||
pod::Ray ray{ {0,0,0}, {1,0,0} }; // starts inside
|
||||
auto q = uf::physics::impl::rayCast(ray, world, 100.0f);
|
||||
@ -857,7 +858,7 @@ TEST(RayMesh_Hit, {
|
||||
auto& bodyA = uf::physics::impl::create(world, objMesh, mesh, 0.0f);
|
||||
bodyA.transform->position = {0,0,0};
|
||||
|
||||
::buildBroadphaseBVH( world.bvh, world.bodies );
|
||||
::buildBroadphaseBVH( world.dynamicBvh, world.bodies );
|
||||
|
||||
pod::Ray ray{ {0,1,0}, {0,-1,0} }; // from above, pointing down
|
||||
pod::RayQuery hit = uf::physics::impl::rayCast(ray, world, 100.0f);
|
||||
@ -874,7 +875,7 @@ TEST(RayMesh_Miss, {
|
||||
auto& bodyA = uf::physics::impl::create(world, objMesh, mesh, 0.0f);
|
||||
bodyA.transform->position = {0,0,0};
|
||||
|
||||
::buildBroadphaseBVH( world.bvh, world.bodies );
|
||||
::buildBroadphaseBVH( world.dynamicBvh, world.bodies );
|
||||
|
||||
pod::Ray ray{ {0,2,0}, {1,0,0} }; // parallel, goes sideways
|
||||
pod::RayQuery hit = uf::physics::impl::rayCast(ray, world, 100.0f);
|
||||
|
||||
@ -10,63 +10,124 @@
|
||||
#include <uf/utils/thread/perthread.h>
|
||||
#include <uf/utils/io/iostream.h>
|
||||
|
||||
#define UF_MEMORYPOOL_MUTEX 1
|
||||
#define UF_MEMORYPOOL_FETCH_STL_FIND 1
|
||||
#define UF_MEMORYPOOL_LAZY 0
|
||||
#define UF_MEMORYPOOL_TEST 0
|
||||
|
||||
#define UF_MEMORYPOOL_CACHED_ALLOCATIONS 0
|
||||
#define UF_MEMORYPOOL_STORE_ORPHANS 0
|
||||
#define UF_MEMORYPOOL_INVALID_FREE 0
|
||||
namespace {
|
||||
inline size_t getBucketIndex( size_t size, size_t currentSize, size_t levels = UF_MAX_BUCKETS - 1 ) {
|
||||
size_t index = 0;
|
||||
while ( currentSize < size && index < levels ) {
|
||||
currentSize <<= 1;
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
inline size_t getTargetLevel( size_t size, size_t& currentSize, size_t levels = UF_MAX_BUCKETS - 1 ) {
|
||||
size_t index = 0;
|
||||
while ( currentSize < size && index < levels ) {
|
||||
currentSize <<= 1;
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
#define DEBUG_PRINT 0
|
||||
#if DEBUG_PRINT
|
||||
#define UF_MSG_CONDITIONAL_PRINT(...) UF_MSG_DEBUG(__VA_ARGS__)
|
||||
#else
|
||||
#define UF_MSG_CONDITIONAL_PRINT(...)
|
||||
#endif
|
||||
inline void* getBuddy(void* block, size_t blockSize, void* poolStart) {
|
||||
uintptr_t offset = (uintptr_t)block - (uintptr_t) poolStart; // offset from start of the pool
|
||||
uintptr_t buddyOffset = offset ^ blockSize; // XOR the offset with the block size to find the buddy's offset
|
||||
return (void*)((uintptr_t)poolStart + buddyOffset);
|
||||
}
|
||||
|
||||
inline size_t getTreeNodeIndex(size_t offset, size_t level, size_t maxLevel, size_t minChunkSize) {
|
||||
size_t indexInLevel = offset / (minChunkSize << level);
|
||||
size_t firstIndexOfLevel = (1 << (maxLevel - level)) - 1;
|
||||
return firstIndexOfLevel + indexInLevel;
|
||||
}
|
||||
|
||||
inline void setBit(uint8_t* bitset, size_t index) {
|
||||
bitset[index / 8] |= (1 << (index % 8));
|
||||
}
|
||||
inline void clearBit(uint8_t* bitset, size_t index) {
|
||||
bitset[index / 8] &= ~(1 << (index % 8));
|
||||
}
|
||||
inline bool getBit(uint8_t* bitset, size_t index) {
|
||||
return (bitset[index / 8] & (1 << (index % 8))) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool uf::memoryPool::subPool = true;
|
||||
uint8_t uf::memoryPool::alignment = 64;
|
||||
uf::MemoryPool uf::memoryPool::global;
|
||||
size_t uf::memoryPool::size( const pod::MemoryPool& pool ) {
|
||||
return pool.size;
|
||||
}
|
||||
size_t uf::memoryPool::allocated( const pod::MemoryPool& pool ) {
|
||||
size_t allocated = 0;
|
||||
for ( auto& allocation : pool.allocations ) allocated += allocation.size;
|
||||
return allocated;
|
||||
}
|
||||
uf::stl::string uf::memoryPool::stats( const pod::MemoryPool& pool ) {
|
||||
uf::Serializer metadata;
|
||||
|
||||
size_t size = uf::memoryPool::size( pool );
|
||||
size_t allocated = uf::memoryPool::allocated( pool );
|
||||
|
||||
uf::stl::stringstream ss; ss << std::hex << (void*) pool.memory;
|
||||
|
||||
metadata["size"] = size;
|
||||
metadata["used"] = allocated;
|
||||
metadata["free"] = size - allocated;
|
||||
metadata["objects"] = pool.allocations.size();
|
||||
metadata["pool"] = ss.str();
|
||||
|
||||
return metadata;
|
||||
}
|
||||
void uf::memoryPool::initialize( pod::MemoryPool& pool, size_t size ) {
|
||||
void uf::memoryPool::initialize( pod::MemoryPool& pool, size_t size, pod::MemoryPool::Strategy strategy, size_t chunkSize ) {
|
||||
if ( size <= 0 ) return;
|
||||
if ( uf::memoryPool::size( pool ) > 0 ) uf::memoryPool::destroy( pool );
|
||||
|
||||
pool.allocations.reserve(64);
|
||||
|
||||
if ( uf::memoryPool::subPool && uf::memoryPool::global.size() > 0 && &pool != &uf::memoryPool::global.data() ) {
|
||||
pool.memory = uf::memoryPool::global.alloc( size );
|
||||
} else {
|
||||
pool.memory = uf::allocator::malloc_m( size );
|
||||
}
|
||||
UF_ASSERT( pool.memory );
|
||||
memset( pool.memory, 0, size );
|
||||
|
||||
pool.size = size;
|
||||
pool.strategy = strategy;
|
||||
pool.memory = uf::allocator::malloc_m(size);
|
||||
UF_ASSERT( pool.memory );
|
||||
|
||||
switch ( pool.strategy ) {
|
||||
case pod::MemoryPool::Strategy::LINEAR: {
|
||||
pool.state.linear.offset = 0;
|
||||
break;
|
||||
}
|
||||
case pod::MemoryPool::Strategy::POOL: {
|
||||
UF_ASSERT(chunkSize > 0 && chunkSize >= sizeof(void*));
|
||||
|
||||
pool.state.pool.fixedChunkSize = chunkSize;
|
||||
pool.state.pool.freeListHead = pool.memory;
|
||||
|
||||
size_t numChunks = size / chunkSize;
|
||||
uint8_t* ptr = static_cast<uint8_t*>(pool.memory);
|
||||
for (size_t i = 0; i < numChunks - 1; ++i) {
|
||||
void** currentChunk = reinterpret_cast<void**>(ptr + (i * chunkSize));
|
||||
*currentChunk = ptr + ((i + 1) * chunkSize);
|
||||
}
|
||||
void** lastChunk = reinterpret_cast<void**>(ptr + ((numChunks - 1) * chunkSize));
|
||||
*lastChunk = nullptr;
|
||||
break;
|
||||
}
|
||||
case pod::MemoryPool::Strategy::SEGREGATED: {
|
||||
UF_ASSERT(chunkSize >= sizeof(void*));
|
||||
|
||||
pool.state.segregated.minChunkSize = chunkSize;
|
||||
pool.state.segregated.offset = 0;
|
||||
for (int i = 0; i < UF_MAX_BUCKETS; ++i) {
|
||||
pool.state.segregated.freeListHeads[i] = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case pod::MemoryPool::Strategy::BUDDY: {
|
||||
// to-do: pick a better fallback
|
||||
if ( !chunkSize ) chunkSize = 128;
|
||||
|
||||
UF_ASSERT(chunkSize >= sizeof(void*));
|
||||
UF_ASSERT((size & (size - 1)) == 0); // is power of 2
|
||||
|
||||
pool.state.buddy.minBlockSize = chunkSize;
|
||||
for (int i = 0; i < 32; ++i) pool.state.buddy.freeLists[i] = nullptr;
|
||||
|
||||
// calculate max level
|
||||
size_t s = size;
|
||||
size_t maxLevel = 0;
|
||||
while ( s > chunkSize ) { s >>= 1; maxLevel++; }
|
||||
pool.state.buddy.maxLevel = maxLevel;
|
||||
|
||||
pool.state.buddy.freeLists[maxLevel] = pool.memory; // set highest level as one free block
|
||||
|
||||
// allocate a small bitset to track splits
|
||||
// to-do: make it at the end of the allocation instead
|
||||
size_t totalNodes = (1 << (maxLevel + 1)) - 1;
|
||||
size_t bitsetSize = (totalNodes + 7) / 8; // round up to nearest byte
|
||||
pool.state.buddy.splitBlockBitset = (uint8_t*) uf::allocator::malloc_m(bitsetSize);
|
||||
memset(pool.state.buddy.splitBlockBitset, 0, bitsetSize);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UF_EXCEPTION("invalid strategy: {}", pool.strategy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void uf::memoryPool::destroy( pod::MemoryPool& pool ) {
|
||||
if ( uf::memoryPool::size( pool ) <= 0 ) goto CLEAR;
|
||||
@ -75,262 +136,295 @@ void uf::memoryPool::destroy( pod::MemoryPool& pool ) {
|
||||
} else {
|
||||
uf::allocator::free_m(pool.memory);
|
||||
}
|
||||
|
||||
// per-pool destruction
|
||||
switch ( pool.strategy ) {
|
||||
case pod::MemoryPool::Strategy::BUDDY: {
|
||||
uf::allocator::free_m(pool.state.buddy.splitBlockBitset);
|
||||
pool.state.buddy.splitBlockBitset = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CLEAR:
|
||||
pool.size = 0;
|
||||
pool.used = 0;
|
||||
pool.memory = NULL;
|
||||
}
|
||||
|
||||
pod::Allocation uf::memoryPool::allocate( pod::MemoryPool& pool, size_t size, size_t alignment ) {
|
||||
// alignment = MIN( alignment, uf::memoryPool::alignment );
|
||||
// alignment = uf::memoryPool::alignment;
|
||||
pod::Allocation alloc;
|
||||
#if UF_MEMORYPOOL_MUTEX
|
||||
pool.mutex.lock();
|
||||
std::lock_guard<std::mutex> lock(pool.mutex);
|
||||
#endif
|
||||
// find next available allocation
|
||||
pod::Allocation allocation;
|
||||
|
||||
uintptr_t pointer = (uintptr_t) pool.memory;
|
||||
// realign pointer
|
||||
if ( 0 < alignment ) {
|
||||
uintptr_t a = uf::alignment( (void*) pointer, alignment );
|
||||
pointer += a == 0 ? 0 : alignment - a;
|
||||
}
|
||||
switch ( pool.strategy ) {
|
||||
case pod::MemoryPool::Strategy::LINEAR: {
|
||||
// get next free space
|
||||
uintptr_t currentPtr = (uintptr_t) pool.memory + pool.state.linear.offset;
|
||||
|
||||
size_t len = uf::memoryPool::size( pool );
|
||||
size_t padding = 0;
|
||||
// pool not initialized
|
||||
if ( len <= 0 ) {
|
||||
UF_MSG_CONDITIONAL_PRINT("cannot malloc, pool not initialized: {} bytes", size);
|
||||
goto MANUAL_MALLOC;
|
||||
}
|
||||
|
||||
#if UF_MEMORYPOOL_CACHED_ALLOCATIONS
|
||||
// an optimization by quickly reusing freed allocations seemed like a good idea
|
||||
// but still have to iterate through allocation information
|
||||
// to keep allocation information in order
|
||||
|
||||
// check our cache of first
|
||||
if ( !pool.cachedFreeAllocations.empty() ) {
|
||||
auto it = pool.cachedFreeAllocations.begin();
|
||||
// check if any recently freed allocation is big enough for our new allocation
|
||||
for ( ; it != pool.cachedFreeAllocations.end(); ++it ) {
|
||||
// is aligned
|
||||
if ( 0 < alignment && !uf::aligned( (void*) it->pointer, alignment ) ) continue;
|
||||
// sized adequately
|
||||
if ( it->size < size ) break;
|
||||
}
|
||||
// found a suitable allocation, use it
|
||||
if ( it != pool.cachedFreeAllocations.end() ) {
|
||||
pointer = it->pointer;
|
||||
// find where to insert in our allocation table
|
||||
auto next = pool.allocations.begin();
|
||||
while ( next != pool.allocations.end() ) {
|
||||
if ( pointer + size + padding < next->pointer ) break;
|
||||
++next;
|
||||
// realign
|
||||
size_t padding = 0;
|
||||
if ( alignment > 0 ) {
|
||||
uintptr_t a = uf::alignment((void*) currentPtr, alignment);
|
||||
padding = a == 0 ? 0 : alignment - a;
|
||||
}
|
||||
// check if it was actually valid
|
||||
if ( next != pool.allocations.end() ) {
|
||||
// remove from cache
|
||||
pool.cachedFreeAllocations.erase(it);
|
||||
|
||||
// initialize allocation info
|
||||
void* p = (void*) pointer;
|
||||
allocation.size = size;
|
||||
allocation.pointer = pointer;
|
||||
|
||||
// security
|
||||
// if ( data ) memcpy( p, data, size );
|
||||
// else memset( p, 0, size );
|
||||
memset( p, 0, size );
|
||||
// oom
|
||||
if ( pool.state.linear.offset + padding + size > pool.size ) {
|
||||
goto MANUAL_MALLOC;
|
||||
}
|
||||
|
||||
// register as allocated
|
||||
pool.allocations.insert(next, allocation);
|
||||
// allocate
|
||||
alloc.pointer = currentPtr + padding;
|
||||
alloc.size = size;
|
||||
|
||||
// move offset forward
|
||||
pool.state.linear.offset += padding + size;
|
||||
goto RETURN;
|
||||
}
|
||||
case pod::MemoryPool::Strategy::POOL: {
|
||||
// oom
|
||||
if ( size > pool.state.pool.fixedChunkSize || pool.state.pool.freeListHead == nullptr ) {
|
||||
goto MANUAL_MALLOC;
|
||||
}
|
||||
|
||||
// allocate
|
||||
alloc.pointer = (uintptr_t) pool.state.pool.freeListHead;
|
||||
alloc.size = pool.state.pool.fixedChunkSize;
|
||||
|
||||
// move head to next free spot
|
||||
pool.state.pool.freeListHead = *reinterpret_cast<void**>(pool.state.pool.freeListHead); // ???
|
||||
goto RETURN;
|
||||
}
|
||||
case pod::MemoryPool::Strategy::SEGREGATED: {
|
||||
// find bucket level
|
||||
size_t bucketIdx = getBucketIndex(size, pool.state.segregated.minChunkSize);
|
||||
size_t bucketSize = pool.state.segregated.minChunkSize << bucketIdx;
|
||||
|
||||
// search within the free list first
|
||||
if ( pool.state.segregated.freeListHeads[bucketIdx] != nullptr ) {
|
||||
alloc.pointer = (uintptr_t)pool.state.segregated.freeListHeads[bucketIdx];
|
||||
alloc.size = bucketSize;
|
||||
pool.state.segregated.freeListHeads[bucketIdx] = *reinterpret_cast<void**>(alloc.pointer);
|
||||
goto RETURN;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
{
|
||||
// find any availble spots in-between existing allocations
|
||||
auto next = pool.allocations.begin();
|
||||
// no allocations;
|
||||
if ( pool.allocations.empty() ) {
|
||||
// beginning is big enough to fit
|
||||
} else if ( pointer + size < next->pointer ) {
|
||||
} else {
|
||||
for ( auto it = next; it != pool.allocations.end(); ++it ) {
|
||||
// ignore invalid indexes
|
||||
if ( pool.size == 0 ) continue;
|
||||
// point to end of allocation we're looking at
|
||||
pointer = it->pointer + it->size + padding;
|
||||
// realign our index if requested
|
||||
if ( 0 < alignment ) {
|
||||
uintptr_t a = uf::alignment( (void*) pointer, alignment );
|
||||
pointer += a == 0 ? 0 : alignment - a;
|
||||
}
|
||||
// hit the end of our allocations, break
|
||||
if ( ++next == pool.allocations.end() ) break;
|
||||
// target index is behind next allocated space, use it
|
||||
if ( pointer + size < next->pointer ) break;
|
||||
|
||||
// oom
|
||||
if (pool.state.segregated.offset + bucketSize > pool.size) {
|
||||
goto MANUAL_MALLOC;
|
||||
}
|
||||
}
|
||||
// no allocation found, OOM
|
||||
if ( (uintptr_t) pool.memory + len <= pointer + size + padding ) {
|
||||
UF_MSG_ERROR("MemoryPool: {}: out of memory", (void*) &pool);
|
||||
UF_MSG_ERROR("Trying to request {} bytes of memory", size);
|
||||
UF_MSG_ERROR("Stats: {}", uf::memoryPool::stats( pool ));
|
||||
goto MANUAL_MALLOC;
|
||||
}
|
||||
|
||||
// initialize allocation info
|
||||
void* p = (void*) pointer;
|
||||
allocation.size = size;
|
||||
allocation.pointer = pointer;
|
||||
|
||||
// security
|
||||
// if ( data ) memcpy( p, data, size );
|
||||
// else memset( p, 0, size );
|
||||
memset( p, 0, size );
|
||||
// allocate
|
||||
alloc.pointer = (uintptr_t) pool.memory + pool.state.segregated.offset;
|
||||
alloc.size = bucketSize;
|
||||
|
||||
// move offset to next free spot
|
||||
pool.state.segregated.offset += bucketSize;
|
||||
goto RETURN;
|
||||
}
|
||||
case pod::MemoryPool::Strategy::BUDDY: {
|
||||
// realign
|
||||
size_t requestedSize = size;
|
||||
if ( alignment > 0 && size < alignment ) requestedSize = alignment;
|
||||
|
||||
// overrides if we're overloading global new/delete
|
||||
// register as allocated
|
||||
pool.allocations.insert(next, allocation);
|
||||
// find target level
|
||||
size_t currentSize = pool.state.buddy.minBlockSize;
|
||||
size_t targetLevel = getTargetLevel(requestedSize, currentSize, pool.state.buddy.maxLevel);
|
||||
|
||||
// find a free block at target level or higher
|
||||
size_t allocLevel = targetLevel;
|
||||
while ( allocLevel <= pool.state.buddy.maxLevel && pool.state.buddy.freeLists[allocLevel] == nullptr ) {
|
||||
allocLevel++;
|
||||
}
|
||||
|
||||
// oom
|
||||
if ( allocLevel > pool.state.buddy.maxLevel ) {
|
||||
goto MANUAL_MALLOC;
|
||||
}
|
||||
|
||||
// pop the block from the higher level
|
||||
void* block = pool.state.buddy.freeLists[allocLevel];
|
||||
pool.state.buddy.freeLists[allocLevel] = *reinterpret_cast<void**>(block);
|
||||
|
||||
// split downwards to the target level
|
||||
while (allocLevel > targetLevel) {
|
||||
// mark the current block as split before dropping down
|
||||
size_t offset = (uintptr_t) block - (uintptr_t) pool.memory;
|
||||
size_t nodeIndex = getTreeNodeIndex( offset, allocLevel, pool.state.buddy.maxLevel, pool.state.buddy.minBlockSize );
|
||||
setBit(pool.state.buddy.splitBlockBitset, nodeIndex);
|
||||
|
||||
allocLevel--;
|
||||
size_t halfSize = pool.state.buddy.minBlockSize << allocLevel;
|
||||
|
||||
void* buddy = (void*) ((uintptr_t) block + halfSize); // right half
|
||||
|
||||
// push buddy to the free list of this lower level
|
||||
*reinterpret_cast<void**>(buddy) = pool.state.buddy.freeLists[allocLevel];
|
||||
pool.state.buddy.freeLists[allocLevel] = buddy;
|
||||
}
|
||||
|
||||
// allocate
|
||||
alloc.pointer = (uintptr_t) block;
|
||||
alloc.size = currentSize;
|
||||
goto RETURN;
|
||||
}
|
||||
default: {
|
||||
UF_EXCEPTION("invalid strategy: {}", pool.strategy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
goto RETURN;
|
||||
MANUAL_MALLOC:
|
||||
#if UF_MEMORYPOOL_INVALID_MALLOC
|
||||
allocation.size = 0;
|
||||
allocation.pointer = (uintptr_t) uf::allocator::malloc_m(size);
|
||||
alloc.size = 0; // orphaned
|
||||
alloc.pointer = (uintptr_t) uf::allocator::malloc_m(size);
|
||||
UF_MSG_DEBUG("allocating orphan: {} bytes at {}", size, (void*) alloc.pointer);
|
||||
|
||||
#if UF_MEMORYPOOL_STORE_ORPHANS
|
||||
pool.orphaned.emplace_back(allocation);
|
||||
pool.orphaned.emplace_back( alloc );
|
||||
#endif
|
||||
#else
|
||||
UF_EXCEPTION("invalid malloc");
|
||||
UF_EXCEPTION("cannot malloc: {}", size );
|
||||
#endif
|
||||
|
||||
RETURN:
|
||||
pool.used += alloc.size;
|
||||
UF_ASSERT(alloc.pointer);
|
||||
return alloc;
|
||||
}
|
||||
|
||||
bool uf::memoryPool::free( pod::MemoryPool& pool, void* pointer, size_t size ) {
|
||||
if (!pointer) return false;
|
||||
#if UF_MEMORYPOOL_MUTEX
|
||||
pool.mutex.unlock();
|
||||
std::lock_guard<std::mutex> lock(pool.mutex);
|
||||
#endif
|
||||
// UF_MSG_CONDITIONAL_PRINT((uintptr_t) allocation.pointer - (uintptr_t) pool.memory << " -> " << (uintptr_t) allocation.pointer + allocation.size - (uintptr_t) pool.memory - 1 );
|
||||
UF_ASSERT(allocation.pointer);
|
||||
return allocation;
|
||||
bool oob = !exists( pool, pointer, size );
|
||||
if ( oob ) goto MANUAL_FREE;
|
||||
|
||||
switch (pool.strategy) {
|
||||
case pod::MemoryPool::Strategy::LINEAR: {
|
||||
UF_EXCEPTION("cannot free individual allocation");
|
||||
return false;
|
||||
}
|
||||
|
||||
case pod::MemoryPool::Strategy::POOL: {
|
||||
void** chunk = reinterpret_cast<void**>(pointer);
|
||||
*chunk = pool.state.pool.freeListHead; // point freed chunk to current head
|
||||
pool.state.pool.freeListHead = pointer; // freed chunk is now the new head
|
||||
goto RETURN;
|
||||
}
|
||||
case pod::MemoryPool::Strategy::SEGREGATED: {
|
||||
UF_ASSERT(size > 0);
|
||||
size_t bucketIdx = getBucketIndex(size, pool.state.segregated.minChunkSize);
|
||||
|
||||
void** chunk = reinterpret_cast<void**>(pointer);
|
||||
*chunk = pool.state.segregated.freeListHeads[bucketIdx]; // point freed chunk to current head
|
||||
pool.state.segregated.freeListHeads[bucketIdx] = pointer; // freed chunk is now the new head
|
||||
goto RETURN;
|
||||
}
|
||||
case pod::MemoryPool::Strategy::BUDDY: {
|
||||
UF_ASSERT(size > 0);
|
||||
void* block = pointer;
|
||||
|
||||
// attempt to merge with buddies
|
||||
size_t currentSize = pool.state.buddy.minBlockSize;
|
||||
size_t level = getTargetLevel(size, currentSize, pool.state.buddy.maxLevel);
|
||||
while (level < pool.state.buddy.maxLevel) {
|
||||
void* buddy = getBuddy(block, currentSize, pool.memory);
|
||||
|
||||
// search for buddy in the current level's free list
|
||||
void** current = &pool.state.buddy.freeLists[level];
|
||||
bool buddyIsFree = false;
|
||||
|
||||
while ( *current != nullptr ) {
|
||||
// buddy is free, remove from free list
|
||||
if ( *current == buddy ) {
|
||||
*current = *reinterpret_cast<void**>(buddy);
|
||||
buddyIsFree = true;
|
||||
break;
|
||||
}
|
||||
current = reinterpret_cast<void**>(*current);
|
||||
}
|
||||
|
||||
// buddy is allocated or split, stop merging
|
||||
if ( !buddyIsFree ) break;
|
||||
|
||||
// merge; new block pointer is the minimum of the two
|
||||
block = (block < buddy) ? block : buddy;
|
||||
currentSize <<= 1;
|
||||
level++;
|
||||
}
|
||||
|
||||
// push final block onto the appropriate free list
|
||||
*reinterpret_cast<void**>(block) = pool.state.buddy.freeLists[level];
|
||||
pool.state.buddy.freeLists[level] = block;
|
||||
goto RETURN;
|
||||
}
|
||||
default: {
|
||||
UF_EXCEPTION("invalid strategy: {}", pool.strategy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
MANUAL_FREE:
|
||||
#if UF_MEMORYPOOL_STORE_ORPHANS
|
||||
if ( oob ) {
|
||||
auto it = pool.orphaned.begin();
|
||||
for ( ; it != pool.orphaned.end(); ++it ) {
|
||||
if ( (uintptr_t) pointer == it->pointer && ((size > 0 && it->size == size) || (size == 0)) ) break;
|
||||
}
|
||||
|
||||
if ( it != pool.orphaned.end() ) {
|
||||
UF_MSG_DEBUG("manually freeing orphan {}", pointer);
|
||||
uf::allocator::free_m( pointer );
|
||||
pool.orphaned.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UF_MEMORYPOOL_INVALID_FREE
|
||||
UF_MSG_DEBUG("manually freeing {}", pointer);
|
||||
uf::allocator::free_m(pointer);
|
||||
return true;
|
||||
#else
|
||||
UF_EXCEPTION("cannot free: {}", pointer);
|
||||
return false;
|
||||
#endif
|
||||
|
||||
RETURN:
|
||||
pool.used -= size;
|
||||
return true;
|
||||
}
|
||||
size_t uf::memoryPool::size( const pod::MemoryPool& pool ) {
|
||||
return pool.size;
|
||||
}
|
||||
void* uf::memoryPool::alloc( pod::MemoryPool& pool, size_t size, size_t alignment ) {
|
||||
auto allocation = uf::memoryPool::allocate( pool, size, alignment );
|
||||
return (void*) allocation.pointer;
|
||||
}
|
||||
|
||||
pod::Allocation& uf::memoryPool::fetch( pod::MemoryPool& pool, void* pointer, size_t size ) {
|
||||
static pod::Allocation missing;
|
||||
#if UF_MEMORYPOOL_FETCH_STL_FIND
|
||||
auto it = std::find_if( pool.allocations.begin(), pool.allocations.end(), [pointer, size]( const pod::Allocation& a ){
|
||||
return (uintptr_t) pointer == a.pointer && ((size > 0 && a.size == size) || (size == 0));
|
||||
});
|
||||
return it != pool.allocations.end() ? *it : missing;
|
||||
#else
|
||||
for ( auto& allocation : pool.allocations ) {
|
||||
if ( (uintptr_t) pointer == allocation.pointer && ((size > 0 && allocation.size == size) || (size == 0)) ) return allocation;
|
||||
}
|
||||
return missing;
|
||||
#endif
|
||||
}
|
||||
bool uf::memoryPool::exists( pod::MemoryPool& pool, void* pointer, size_t size ) {
|
||||
// bound check
|
||||
#if UF_MEMORYPOOL_LAZY
|
||||
// if pointer lies before the start of the pool, or if it lies after the end of the pool
|
||||
return pool.memory <= pointer && pointer < (void*) ((uintptr_t) pool.memory + pool.size);
|
||||
#else
|
||||
if ( !(pool.memory <= pointer && pointer < (void*) ((uintptr_t) pool.memory + pool.size)) ) return false;
|
||||
auto& allocation = uf::memoryPool::fetch( pool, pointer, size );
|
||||
return allocation.pointer == (uintptr_t) pointer && ((size > 0 && allocation.size == size) || (size == 0));
|
||||
#endif
|
||||
}
|
||||
bool uf::memoryPool::free( pod::MemoryPool& pool, void* pointer, size_t size ) {
|
||||
// skip freeing, we're already a deallocated pool
|
||||
// this comes up because of how backasswards C++ static initialization/destruction order is
|
||||
if ( !pool.memory ) return false;
|
||||
// passed a NULL, for some reason
|
||||
if ( !pointer ) return false;
|
||||
#if UF_MEMORYPOOL_MUTEX
|
||||
pool.mutex.lock();
|
||||
#endif
|
||||
bool oob = pool.size <= 0 && !(pool.memory <= pointer && pointer < (void*) ((uintptr_t) pool.memory + pool.size));
|
||||
#if UF_MEMORYPOOL_INVALID_MALLOC && UF_MEMORYPOOL_STORE_ORPHANS
|
||||
// if pointer is out of bounds
|
||||
if ( oob ) {
|
||||
// check if our pointer was an orphaned one
|
||||
#if UF_MEMORYPOOL_FETCH_STL_FIND
|
||||
auto it = std::find_if( pool.orphaned.begin(), pool.orphaned.end(), [pointer, size]( const pod::Allocation& a ){
|
||||
return (uintptr_t) pointer == a.pointer && ((size > 0 && a.size == size) || (size == 0));
|
||||
});
|
||||
#else
|
||||
auto it = pool.orphaned.begin();
|
||||
for ( ; it != pool.orphaned.end(); ++it ) if ( pointer == it->pointer && ((size > 0 && it->size == size) || (size == 0)) ) break;
|
||||
#endif
|
||||
// orphaned pointer, just free it
|
||||
if ( it != pool.orphaned.end() ) {
|
||||
uf::allocator::free_m( pointer );
|
||||
pool.orphaned.erase(it);
|
||||
}
|
||||
#if UF_MEMORYPOOL_MUTEX
|
||||
pool.mutex.unlock();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
// fail if uninitialized or pointer is outside of our pool
|
||||
if ( oob ) {
|
||||
// UF_MSG_CONDITIONAL_PRINT("cannot free: " << pointer << " | " << (pool.size <= 0) << " " << (pointer < pool.memory) << " " << (pointer >= (void*) ((uintptr_t) pool.memory + pool.size)));
|
||||
goto MANUAL_FREE;
|
||||
}
|
||||
{
|
||||
// pointer arithmatic
|
||||
auto it = pool.allocations.begin();
|
||||
pod::Allocation allocation{};
|
||||
// find our allocation in the allocation pool
|
||||
for ( ; it != pool.allocations.end(); ++it ) {
|
||||
if ( it->pointer != (uintptr_t) pointer ) continue;
|
||||
allocation = *it;
|
||||
break;
|
||||
}
|
||||
// pointer isn't actually allocated
|
||||
if ( allocation.pointer != (uintptr_t) pointer ) {
|
||||
UF_MSG_ERROR("cannot free, allocation not found: {}", pointer);
|
||||
goto MANUAL_FREE;
|
||||
}
|
||||
// size validation mismatch, do not free
|
||||
if (0 < size && allocation.size != size) {
|
||||
UF_MSG_ERROR("cannot free, mismatched sized: {} ({} != {})", pointer, size, allocation.size);
|
||||
goto MANUAL_FREE;
|
||||
}
|
||||
// UF_MSG_CONDITIONAL_PRINT(" " << (uintptr_t) allocation.pointer - (uintptr_t) pool.memory << " -> " << (uintptr_t) allocation.pointer + allocation.size - (uintptr_t) pool.memory - 1 );
|
||||
// security
|
||||
memset( pointer, 0, size );
|
||||
|
||||
// remove from our allocation table...
|
||||
pool.allocations.erase(it);
|
||||
#if UF_MEMORYPOOL_CACHED_ALLOCATIONS
|
||||
// ...but add it to our freed allocation cache
|
||||
pool.cachedFreeAllocations.push_back(allocation);
|
||||
#endif
|
||||
#if UF_MEMORYPOOL_MUTEX
|
||||
pool.mutex.unlock();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
MANUAL_FREE:
|
||||
#if UF_MEMORYPOOL_MUTEX
|
||||
pool.mutex.unlock();
|
||||
#endif
|
||||
#if UF_MEMORYPOOL_INVALID_FREE
|
||||
uf::allocator::free_m(pointer);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t uf::memoryPool::allocated( const pod::MemoryPool& pool ) {
|
||||
return pool.used;
|
||||
}
|
||||
uf::stl::string uf::memoryPool::stats( const pod::MemoryPool& pool ) {
|
||||
uf::Serializer metadata;
|
||||
metadata["size"] = pool.size;
|
||||
metadata["used"] = pool.used;
|
||||
metadata["free"] = pool.size - pool.used;
|
||||
metadata["strategy"] = (int) pool.strategy;
|
||||
|
||||
uf::stl::stringstream ss; ss << std::hex << (void*) pool.memory;
|
||||
metadata["pool"] = ss.str();
|
||||
return metadata;
|
||||
}
|
||||
pod::Allocation& uf::memoryPool::fetch( pod::MemoryPool& pool, void* pointer, size_t size ) {
|
||||
UF_EXCEPTION("unimplemented");
|
||||
}
|
||||
const pod::MemoryPool::allocations_t& uf::memoryPool::allocations( const pod::MemoryPool& pool ) {
|
||||
return pool.allocations;
|
||||
UF_EXCEPTION("unimplemented")
|
||||
}
|
||||
//
|
||||
uf::MemoryPool::MemoryPool( size_t size ) {
|
||||
@ -338,4 +432,8 @@ uf::MemoryPool::MemoryPool( size_t size ) {
|
||||
}
|
||||
uf::MemoryPool::~MemoryPool( ) {
|
||||
this->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
#if UF_MEMORYPOOL_TEST
|
||||
#include "tests.inl"
|
||||
#endif
|
||||
82
engine/src/utils/memory/tests.inl
Normal file
82
engine/src/utils/memory/tests.inl
Normal file
@ -0,0 +1,82 @@
|
||||
#include <uf/utils/tests/tests.h>
|
||||
|
||||
TEST(MemoryPool_LinearStrategy, {
|
||||
pod::MemoryPool pool;
|
||||
uf::memoryPool::initialize(pool, 1024, pod::MemoryPool::Strategy::LINEAR, 0);
|
||||
|
||||
auto alloc1 = uf::memoryPool::allocate(pool, 100, 0);
|
||||
EXPECT_TRUE(alloc1.pointer != 0);
|
||||
EXPECT_EQ(alloc1.size, 100);
|
||||
|
||||
auto alloc2 = uf::memoryPool::allocate(pool, 200, 0);
|
||||
EXPECT_TRUE(alloc2.pointer != 0);
|
||||
EXPECT_EQ(alloc2.size, 200);
|
||||
EXPECT_EQ(alloc2.pointer, alloc1.pointer + 100);
|
||||
|
||||
auto oom_alloc = uf::memoryPool::allocate(pool, 800, 0);
|
||||
|
||||
EXPECT_TRUE(oom_alloc.size == 0);
|
||||
EXPECT_TRUE(oom_alloc.pointer != 0);
|
||||
|
||||
uf::memoryPool::destroy(pool);
|
||||
})
|
||||
|
||||
TEST(MemoryPool_PoolStrategy, {
|
||||
pod::MemoryPool pool;
|
||||
uf::memoryPool::initialize(pool, 1024, pod::MemoryPool::Strategy::POOL, 64);
|
||||
|
||||
auto alloc1 = uf::memoryPool::allocate(pool, 64, 0);
|
||||
EXPECT_TRUE(alloc1.pointer != 0);
|
||||
EXPECT_EQ(alloc1.size, 64);
|
||||
|
||||
auto alloc2 = uf::memoryPool::allocate(pool, 64, 0);
|
||||
EXPECT_TRUE(alloc2.pointer != 0);
|
||||
|
||||
bool freed = uf::memoryPool::free(pool, (void*)alloc1.pointer, 64);
|
||||
EXPECT_TRUE(freed);
|
||||
|
||||
auto alloc3 = uf::memoryPool::allocate(pool, 64, 0);
|
||||
EXPECT_EQ(alloc3.pointer, alloc1.pointer);
|
||||
|
||||
uf::memoryPool::destroy(pool);
|
||||
})
|
||||
|
||||
TEST(MemoryPool_SegregatedStrategy, {
|
||||
pod::MemoryPool pool;
|
||||
uf::memoryPool::initialize(pool, 1024, pod::MemoryPool::Strategy::SEGREGATED, 16);
|
||||
|
||||
auto alloc1 = uf::memoryPool::allocate(pool, 20, 0);
|
||||
EXPECT_EQ(alloc1.size, 32);
|
||||
|
||||
auto alloc2 = uf::memoryPool::allocate(pool, 60, 0);
|
||||
EXPECT_EQ(alloc2.size, 64);
|
||||
|
||||
EXPECT_TRUE(uf::memoryPool::free(pool, (void*)alloc1.pointer, 32));
|
||||
|
||||
auto alloc3 = uf::memoryPool::allocate(pool, 30, 0);
|
||||
EXPECT_EQ(alloc3.size, 32);
|
||||
EXPECT_EQ(alloc3.pointer, alloc1.pointer);
|
||||
|
||||
uf::memoryPool::destroy(pool);
|
||||
})
|
||||
|
||||
TEST(MemoryPool_BuddyStrategy, {
|
||||
pod::MemoryPool pool;
|
||||
uf::memoryPool::initialize(pool, 1024, pod::MemoryPool::Strategy::BUDDY, 64);
|
||||
|
||||
auto alloc1 = uf::memoryPool::allocate(pool, 100, 0);
|
||||
EXPECT_EQ(alloc1.size, 128);
|
||||
|
||||
auto alloc2 = uf::memoryPool::allocate(pool, 128, 0);
|
||||
EXPECT_EQ(alloc2.size, 128);
|
||||
|
||||
EXPECT_TRUE(uf::memoryPool::free(pool, (void*)alloc1.pointer, 128));
|
||||
EXPECT_TRUE(uf::memoryPool::free(pool, (void*)alloc2.pointer, 128));
|
||||
|
||||
|
||||
auto alloc3 = uf::memoryPool::allocate(pool, 256, 0);
|
||||
EXPECT_EQ(alloc3.size, 256);
|
||||
EXPECT_EQ(alloc3.pointer, alloc1.pointer);
|
||||
|
||||
uf::memoryPool::destroy(pool);
|
||||
})
|
||||
@ -127,13 +127,13 @@ void uf::thread::batchWorkers_Async( const uf::stl::vector<pod::Thread::function
|
||||
*/
|
||||
/*
|
||||
void uf::thread::add( pod::Thread& thread, bool queued, const pod::Thread::function_t& function ) {
|
||||
if ( thread.mutex != NULL ) thread.mutex->lock();
|
||||
std::unique_lock<std::mutex> lock(*thread.mutex);
|
||||
queue ? thread.queue.push( function ) : thread.container.push_back( function );
|
||||
if ( thread.mutex != NULL ) thread.mutex->unlock();
|
||||
}
|
||||
*/
|
||||
void uf::thread::add( pod::Thread& thread, const pod::Thread::function_t& function ) {
|
||||
if ( thread.mutex != NULL ) thread.mutex->lock();
|
||||
std::unique_lock<std::mutex> lock(*thread.mutex);
|
||||
thread.container.emplace_back( function );
|
||||
if ( thread.mutex != NULL ) thread.mutex->unlock();
|
||||
}
|
||||
@ -145,7 +145,7 @@ void uf::thread::queue( const pod::Thread::function_t& function ) {
|
||||
return uf::thread::queue( uf::thread::fetchWorker(), function );
|
||||
}
|
||||
void uf::thread::queue( pod::Thread& thread, const pod::Thread::function_t& function ) {
|
||||
if ( thread.mutex != NULL ) thread.mutex->lock();
|
||||
std::unique_lock<std::mutex> lock(*thread.mutex);
|
||||
thread.queue.emplace( function );
|
||||
thread.conditions.queued.notify_one();
|
||||
thread.pending.fetch_add(1);
|
||||
@ -233,6 +233,7 @@ void uf::thread::terminate() {
|
||||
}
|
||||
}
|
||||
pod::Thread& uf::thread::create( const uf::stl::string& name, bool start, bool locks ) {
|
||||
locks = true; // test
|
||||
if ( name == uf::thread::mainThreadName ) start = false;
|
||||
|
||||
pod::Thread* pointer = NULL;
|
||||
|
||||
177
makefiles/dependencies.mk
Normal file
177
makefiles/dependencies.mk
Normal file
@ -0,0 +1,177 @@
|
||||
ifneq (,$(findstring ffx:sdk,$(REQ_DEPS)))
|
||||
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_FFX_SDK=3
|
||||
DEPS := -lffx_fsr3_x64 -lffx_fsr2_x64 -lffx_fsr3upscaler_x64 -lffx_frameinterpolation_x64 -lffx_opticalflow_x64 -lffx_backend_vk_x64 -lamd_fidelityfx_vk $(DEPS)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_VULKAN
|
||||
DEPS += -lspirv-cross-core -lspirv-cross-cpp
|
||||
INCS += -I$(VULKAN_SDK_PATH)/include -I./dep/include/spirv_cross/
|
||||
LIBS += -L$(VULKAN_SDK_PATH)/Lib
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring opengl,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_OPENGL -DUF_USE_OPENGL_FIXED_FUNCTION
|
||||
ifeq (,$(findstring gldc,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_GLEW
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring fmt,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_FMT
|
||||
ifeq (,$(findstring dreamcast,$(ARCH)))
|
||||
DEPS += -lfmt
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring ffx:fsr,$(REQ_DEPS)))
|
||||
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_FFX_FSR
|
||||
DEPS += -lffx_fsr2_api_ -lffx_fsr2_api_vk_
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring imgui,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_IMGUI
|
||||
INCS += -I./dep/include/imgui/ -I./dep/include/imgui/backends
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring cpptrace,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_CPPTRACE
|
||||
DEPS += -lcpptrace
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring json,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_JSON
|
||||
ifneq (,$(findstring nlohmann,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_JSON_USE_NLOHMANN
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring gltf,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_GLTF
|
||||
INCS += -I./dep/include/stb/ -I./dep/include/nlohmann/
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring dc:texconv,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_DC_TEXCONV
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring openal,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_OPENAL -DUF_USE_ALUT
|
||||
ifeq (,$(findstring dreamcast,$(ARCH)))
|
||||
DEPS += -lopenal -lalut
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring ogg,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_VORBIS
|
||||
ifeq (,$(findstring dreamcast,$(ARCH)))
|
||||
DEPS += -lvorbis -lvorbisfile -logg
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring wav,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_WAV
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring zlib,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_ZLIB
|
||||
DEPS += -lz
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring freetype,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_FREETYPE
|
||||
DEPS += -lfreetype -lbz2
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring curl,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_CURL
|
||||
DEPS += -lcurl
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring openvr,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_OPENVR -DUSE_OPENVR_MINGW
|
||||
DEPS += -lopenvr_api
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring lua,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_LUA
|
||||
ifneq (,$(findstring luajit,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_LUAJIT
|
||||
DEPS += -lluajit-5.1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring reactphysics,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_REACTPHYSICS
|
||||
DEPS += -lreactphysics3d
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring simd,$(REQ_DEPS)))
|
||||
ifeq (,$(findstring dreamcast,$(ARCH)))
|
||||
FLAGS += -DUF_USE_SIMD -DUF_ALIGN_FOR_SIMD -DUF_MATRIX_ALIGNED
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring meshoptimizer,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_MESHOPT
|
||||
DEPS += -lmeshoptimizer
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring xatlas,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_XATLAS
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring ctti,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_CTTI -fno-rtti
|
||||
else
|
||||
FLAGS += -DUF_RTTI -rtti
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring toml,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_TOML
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring vall_e,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_VALL_E
|
||||
INCS += -I./dep/include/vall_e.cpp/
|
||||
DEPS += -lvall_e
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring draco,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_DRACO
|
||||
DEPS += -ldraco
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring ultralight-ux,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_ULTRALIGHT_UX
|
||||
DEPS += -lUltralight -lUltralightCore -lWebCore -lAppCore
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring discord,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_DISCORD
|
||||
DEPS += -ldiscord_game_sdk
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring ncurses,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_NCURSES
|
||||
DEPS += -lncursesw
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring png,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_PNG
|
||||
DEPS += -lpng
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring lz4,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_LZ4
|
||||
DEPS += -llz4
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring xz,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_XZ -DUF_USE_LZMA
|
||||
DEPS += -lxz -llzma
|
||||
endif
|
||||
@ -10,5 +10,5 @@ FLAGS += $(KOS_CPPFLAGS) -m4-single -std=c++2b $(OPTIMIZATIONS) $(WARNINGS)
|
||||
TARGET_EXTENSION = .elf
|
||||
|
||||
# KOS
|
||||
INCS += $(KOS_INC_PATHS) -I/opt/dreamcast/sh-elf/sh-elf/include
|
||||
LIBS += $(KOS_LIB_PATHS) -L/opt/dreamcast/sh-elf/sh-elf/lib
|
||||
INCS := $(KOS_INC_PATHS) -I/opt/dreamcast/sh-elf/sh-elf/include $(INCS)
|
||||
LIBS := $(KOS_LIB_PATHS) -L/opt/dreamcast/sh-elf/sh-elf/lib $(LIBS)
|
||||
77
makefiles/platforms/dreamcast.mk
Normal file
77
makefiles/platforms/dreamcast.mk
Normal file
@ -0,0 +1,77 @@
|
||||
FLAGS += -DUF_ENV_DREAMCAST
|
||||
REQ_DEPS += opengl gldc json:nlohmann zlib lua r:eactphysics simd ctti fmt freetype openal aldc ogg wav png
|
||||
|
||||
INCS := -I./dep/dreamcast/include $(INCS)
|
||||
|
||||
# Dependency Overrides
|
||||
ifneq (,$(findstring gldc,$(REQ_DEPS)))
|
||||
DEPS += -lGL
|
||||
FLAGS += -DUF_USE_OPENGL_GLDC
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring aldc,$(REQ_DEPS)))
|
||||
DEPS += -lAL -lpthread
|
||||
FLAGS += -DUF_USE_OPENAL_ALDC -DUF_USE_ALUT
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring ogg,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_USE_TREMOR
|
||||
DEPS += -ltremor
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring lua,$(REQ_DEPS)))
|
||||
DEPS += -llua
|
||||
INCS += -I/opt/dreamcast/kos-ports/include/lua
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring simd,$(REQ_DEPS)))
|
||||
FLAGS += -DUF_ENV_DREAMCAST_SIMD
|
||||
endif
|
||||
|
||||
DEPS += -lkallisti -lc -lm -lgcc -lstdc++
|
||||
|
||||
SRCS_DLL = $(shell find $(ENGINE_SRC_DIR) -name "*.cpp") $(shell find $(DEP_SRC_DIR) -name "*.cpp")
|
||||
OBJS_DLL = $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_DLL))
|
||||
OBJS = $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_DLL)) $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_EXT_DLL)) $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS))
|
||||
|
||||
$(PREFIX): $(TARGET) ./bin/dreamcast/$(TARGET_NAME).cdi
|
||||
|
||||
$(EX_DLL): FLAGS += -DUF_EXPORTS
|
||||
$(EX_DLL): $(OBJS_DLL)
|
||||
$(KOS_AR) cru $@ $^
|
||||
$(KOS_RANLIB) $@
|
||||
cp $@ $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL)
|
||||
|
||||
$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS
|
||||
$(EXT_EX_DLL): $(OBJS_EXT_DLL)
|
||||
$(KOS_AR) cru $@ $^
|
||||
$(KOS_RANLIB) $@
|
||||
cp $@ $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL)
|
||||
|
||||
./bin/dreamcast/romdisk.img:
|
||||
$(KOS_GENROMFS) -f ./bin/dreamcast/romdisk.img -d ./bin/dreamcast/romdisk/ -v
|
||||
|
||||
./bin/dreamcast/romdisk.o: ./bin/dreamcast/romdisk.img
|
||||
$(KOS_BASE)/utils/bin2o/bin2o ./bin/dreamcast/romdisk.img romdisk ./bin/dreamcast/romdisk.o
|
||||
|
||||
$(TARGET): $(OBJS) #./bin/dreamcast/romdisk.o
|
||||
$(CXX) $(FLAGS) $(INCS) -D_arch_dreamcast -D_arch_sub_pristine -Wall -fno-builtin -ml -Wl,-Ttext=0x8c010000 -T/opt/dreamcast/kos/utils/ldscripts/shlelf.xc -nodefaultlibs $(KOS_LIB_PATHS) $(LIBS) -o $(TARGET) $(OBJS) -Wl,--start-group $(DEPS) -Wl,--end-group
|
||||
cp $(TARGET) $(TARGET).unstripped
|
||||
$(KOS_STRIP) --strip-unneeded $(TARGET)
|
||||
|
||||
./bin/dreamcast/$(TARGET_NAME).cdi: $(TARGET)
|
||||
cd ./bin/dreamcast/; ./elf2cdi.sh $(TARGET_NAME)
|
||||
|
||||
cdi:
|
||||
cd ./bin/dreamcast/; ./elf2cdi.sh $(TARGET_NAME)
|
||||
|
||||
run-dreamcast:
|
||||
$(KOS_EMU) ./bin/dreamcast/$(TARGET_NAME).cdi
|
||||
|
||||
run-debug-dreamcast:
|
||||
$(KOS_EMU_DEBUG) ./bin/dreamcast/$(TARGET_NAME).cdi
|
||||
|
||||
clean-dreamcast:
|
||||
@-rm ./bin/dreamcast/build/*
|
||||
@-rm ./bin/dreamcast/romdisk.*
|
||||
@-rm ./bin/dreamcast/$(TARGET_NAME).*
|
||||
45
makefiles/platforms/linux.mk
Normal file
45
makefiles/platforms/linux.mk
Normal file
@ -0,0 +1,45 @@
|
||||
ifneq (,$(findstring -DUF_DEV_ENV,$(FLAGS)))
|
||||
REQ_DEPS += toml xatlas curl dc:texconv # meshoptimizer ffx:fsr cpptrace vall_e # ncurses openvr draco discord bullet ultralight-ux
|
||||
FLAGS += -march=native -g # -flto # -g
|
||||
endif
|
||||
|
||||
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit r:eactphysics simd ctti gltf imgui fmt freetype openal ogg wav
|
||||
FLAGS += -DUF_ENV_LINUX -fPIC
|
||||
DEPS += -pthread -ldl -lX11 -lXrandr
|
||||
INCS := -I./dep/master/include $(INCS)
|
||||
|
||||
# Vulkan Paths
|
||||
VULKAN_SDK_PATH ?= /
|
||||
GLSLC ?= glslc
|
||||
SPV_OPTIMIZER ?= spirv-opt
|
||||
SPV_LINTER ?= spirv-lint
|
||||
|
||||
# Dependency Overrides
|
||||
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
|
||||
DEPS += -lvulkan
|
||||
FLAGS += -DVK_USE_PLATFORM_XLIB_KHR
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring opengl,$(REQ_DEPS)))
|
||||
ifeq (,$(findstring gldc,$(REQ_DEPS)))
|
||||
DEPS += -lGLU -lglut -lGLEW
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring luajit,$(REQ_DEPS)))
|
||||
INCS += -I/usr/include/luajit-2.1
|
||||
endif
|
||||
|
||||
# Target Compilation Overrides
|
||||
$(EX_DLL): FLAGS += -DUF_EXPORTS
|
||||
$(EX_DLL): $(OBJS_DLL)
|
||||
$(CXX) $(FLAGS) -shared -Wl,-soname,$(BASE_DLL)$(DLIB_EXTENSION) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS) -o $(EX_DLL)
|
||||
cp $(EX_DLL) $(IM_DLL)
|
||||
@echo -n $(ARCH) > "./bin/exe/default/arch"
|
||||
@echo -n $(CC) > "./bin/exe/default/cc"
|
||||
@echo -n $(RENDERER) > "./bin/exe/default/renderer"
|
||||
|
||||
$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS
|
||||
$(EXT_EX_DLL): $(OBJS_EXT_DLL)
|
||||
$(CXX) $(FLAGS) -shared -Wl,-soname,$(BASE_EXT_DLL)$(DLIB_EXTENSION) $(OBJS_EXT_DLL) $(EXT_LIBS) $(EXT_INCS) $(EXT_LINKS) -o $(EXT_EX_DLL)
|
||||
cp $(EXT_EX_DLL) $(EXT_IM_DLL)
|
||||
48
makefiles/platforms/win64.mk
Normal file
48
makefiles/platforms/win64.mk
Normal file
@ -0,0 +1,48 @@
|
||||
ifneq (,$(findstring -DUF_DEV_ENV,$(FLAGS)))
|
||||
REQ_DEPS += meshoptimizer toml xatlas curl ffx:sdk dc:texconv # vall_e cpptrace # openvr # ncurses draco discord bullet ultralight-ux
|
||||
FLAGS += -march=native -g # -flto # -g
|
||||
endif
|
||||
|
||||
REQ_DEPS += $(RENDERER) json:nlohmann zlib luajit r:eactphysics simd ctti gltf imgui fmt freetype openal ogg wav
|
||||
FLAGS += -DUF_ENV_WINDOWS -DUF_ENV_WIN64 -DWIN32_LEAN_AND_MEAN
|
||||
DEPS += -lgdi32 -ldwmapi
|
||||
LINKS += #-Wl,-subsystem,windows
|
||||
INCS := -I./dep/master/include $(INCS)
|
||||
|
||||
# Vulkan Paths
|
||||
VULKAN_SDK_PATH ?= /c/VulkanSDK/1.4.321.1/
|
||||
GLSLC ?= $(VULKAN_SDK_PATH)/Bin/glslc
|
||||
SPV_OPTIMIZER ?= $(VULKAN_SDK_PATH)/Bin/spirv-opt
|
||||
SPV_LINTER ?= $(VULKAN_SDK_PATH)/Bin/spirv-lint
|
||||
|
||||
# Dependency Overrides
|
||||
ifneq (,$(findstring vulkan,$(REQ_DEPS)))
|
||||
DEPS += -lvulkan-1
|
||||
FLAGS += -DVK_USE_PLATFORM_WIN32_KHR
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring opengl,$(REQ_DEPS)))
|
||||
ifeq (,$(findstring gldc,$(REQ_DEPS)))
|
||||
DEPS += -lglew32 -lopengl32 -lglu32
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring luajit,$(REQ_DEPS)))
|
||||
ifneq (,$(findstring clang,$(CC)))
|
||||
INCS += -I/clang64/include/luajit-2.1
|
||||
else
|
||||
INCS += -I/mingw64/include/luajit-2.1
|
||||
endif
|
||||
endif
|
||||
|
||||
# Target Compilation Overrides
|
||||
$(EX_DLL): FLAGS += -DUF_EXPORTS
|
||||
$(EX_DLL): $(OBJS_DLL)
|
||||
$(CXX) $(FLAGS) -shared -o $(EX_DLL) -Wl,--out-implib=$(IM_DLL)$(SLIB_EXTENSION) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS)
|
||||
@echo -n $(ARCH) > "./bin/exe/default/arch"
|
||||
@echo -n $(CC) > "./bin/exe/default/cc"
|
||||
@echo -n $(RENDERER) > "./bin/exe/default/renderer"
|
||||
|
||||
$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS
|
||||
$(EXT_EX_DLL): $(OBJS_EXT_DLL)
|
||||
$(CXX) $(FLAGS) -shared -o $(EXT_EX_DLL) -Wl,--out-implib=$(EXT_IM_DLL)$(SLIB_EXTENSION) $(OBJS_EXT_DLL) $(EXT_LIBS) $(EXT_INCS) $(EXT_LINKS)
|
||||
Loading…
Reference in New Issue
Block a user