From 2bc78e7f0a56e0ac696841be5899f44246b449f4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 6 Jul 2019 14:42:53 +0900 Subject: [PATCH 001/435] Start work on a Vulkan-based renderer Doesn't do much other than create an instance and enumerate some stuff, but the build system is working. --- config.d/ac_config_files.m4 | 1 + config.d/build_control.m4 | 10 +- config.d/vulkan.m4 | 24 ++ configure.ac | 1 + include/QF/Vulkan/cvars.h | 7 + include/QF/Vulkan/funclist.h | 55 +++ include/QF/Vulkan/funcs.h | 9 + include/QF/Vulkan/init.h | 65 +++ include/QF/Vulkan/qf_draw.h | 37 ++ include/QF/Vulkan/qf_vid.h | 36 ++ libs/video/renderer/Makefile.am | 10 +- libs/video/renderer/vid_render_vulkan.c | 193 +++++++++ libs/video/renderer/vulkan/Makefile.am | 26 ++ libs/video/renderer/vulkan/init.c | 390 ++++++++++++++++++ libs/video/renderer/vulkan/namehack.h | 137 ++++++ libs/video/renderer/vulkan/vulkan_draw.c | 189 +++++++++ libs/video/renderer/vulkan/vulkan_funcs.c | 6 + .../video/renderer/vulkan/vulkan_vid_common.c | 129 ++++++ 18 files changed, 1319 insertions(+), 6 deletions(-) create mode 100644 config.d/vulkan.m4 create mode 100644 include/QF/Vulkan/cvars.h create mode 100644 include/QF/Vulkan/funclist.h create mode 100644 include/QF/Vulkan/funcs.h create mode 100644 include/QF/Vulkan/init.h create mode 100644 include/QF/Vulkan/qf_draw.h create mode 100644 include/QF/Vulkan/qf_vid.h create mode 100644 libs/video/renderer/vid_render_vulkan.c create mode 100644 libs/video/renderer/vulkan/Makefile.am create mode 100644 libs/video/renderer/vulkan/init.c create mode 100644 libs/video/renderer/vulkan/namehack.h create mode 100644 libs/video/renderer/vulkan/vulkan_draw.c create mode 100644 libs/video/renderer/vulkan/vulkan_funcs.c create mode 100644 libs/video/renderer/vulkan/vulkan_vid_common.c diff --git a/config.d/ac_config_files.m4 b/config.d/ac_config_files.m4 index 587a515d9..499c93099 100644 --- a/config.d/ac_config_files.m4 +++ b/config.d/ac_config_files.m4 @@ -32,6 +32,7 @@ libs/video/renderer/glsl/Makefile libs/video/renderer/sw/Makefile libs/video/renderer/sw32/Makefile + libs/video/renderer/vulkan/Makefile libs/video/targets/Makefile hw/Makefile diff --git a/config.d/build_control.m4 b/config.d/build_control.m4 index abc60cd75..94a7415af 100644 --- a/config.d/build_control.m4 +++ b/config.d/build_control.m4 @@ -71,7 +71,7 @@ if test "x$HAVE_X" = xyes; then NQ_DESKTOP_DATA="$NQ_DESKTOP_DATA quakeforge-nq-x11.desktop" CL_TARGETS="$CL_TARGETS X11" VID_TARGETS="$VID_TARGETS libQFx11.la" - QF_NEED(vid_render, [sw sw32 gl glsl]) + QF_NEED(vid_render, [sw sw32 gl glsl vulkan]) QF_NEED(models, [sw gl glsl]) QF_NEED(alias, [sw gl glsl]) QF_NEED(brush, [sw gl glsl]) @@ -95,7 +95,7 @@ if test "x$HAVE_SDL" = xyes; then NQ_DESKTOP_DATA="$NQ_DESKTOP_DATA quakeforge-nq-sdl.desktop" CL_TARGETS="$CL_TARGETS SDL" VID_TARGETS="$VID_TARGETS libQFsdl.la" - QF_NEED(vid_render, [sw sw32 gl glsl]) + QF_NEED(vid_render, [sw sw32 gl glsl vulkan]) QF_NEED(models, [sw gl glsl]) QF_NEED(alias, [sw gl glsl]) QF_NEED(brush, [sw gl glsl]) @@ -258,7 +258,7 @@ QF_SUBST(progs_gz) QF_PROCESS_NEED_DIRS(top, [libs hw nq qtv qw tools ruamoko]) QF_PROCESS_NEED_LIBS(swrend, [asm]) -QF_PROCESS_NEED_DIRS(vid_render, [gl glsl sw sw32]) +QF_PROCESS_NEED_DIRS(vid_render, [gl glsl sw sw32 vulkan]) QF_PROCESS_NEED_LIBS(models, [gl glsl sw]) QF_PROCESS_NEED_LIBS(alias, [gl glsl sw]) QF_PROCESS_NEED_LIBS(brush, [gl glsl sw]) @@ -308,7 +308,7 @@ if test "x$static_plugins" = xauto; then fi fi if test "x$static_plugins" = xyes; then - QF_PROCESS_NEED_STATIC_PLUGINS(vid_render, [sw sw32 glsl gl]) + QF_PROCESS_NEED_STATIC_PLUGINS(vid_render, [sw sw32 glsl gl vulkan]) QF_PROCESS_NEED_STATIC_PLUGINS(console, [server], [\$(top_builddir)/libs/console], [server]) QF_PROCESS_NEED_STATIC_PLUGINS(console, [client], [\$(top_builddir)/libs/console], [client]) @@ -323,7 +323,7 @@ if test "x$static_plugins" = xyes; then CDTYPE="$CDTYPE (static)" fi else - QF_PROCESS_NEED_PLUGINS(vid_render, [sw sw32 glsl gl]) + QF_PROCESS_NEED_PLUGINS(vid_render, [sw sw32 glsl gl vulkan]) QF_PROCESS_NEED_PLUGINS(console, [server], [server]) QF_PROCESS_NEED_PLUGINS(console, [client], [client]) QF_PROCESS_NEED_PLUGINS(snd_output, [sdl mme sgi sun win dx oss alsa]) diff --git a/config.d/vulkan.m4 b/config.d/vulkan.m4 new file mode 100644 index 000000000..c82900f58 --- /dev/null +++ b/config.d/vulkan.m4 @@ -0,0 +1,24 @@ +dnl Check for vulkan support +AC_ARG_ENABLE(vulkan, +[ --disable-vulkan do not use Vulkan], + HAVE_VULKAN=$enable_vulkan, HAVE_VULKAN=auto) +if test "x$HAVE_VULKAN" != xno; then + save_CPPFLAGS="$CPPFLAGS" + AS_IF([test x"$VULKAN_SDK" != x], [ + CPPFLAGS="$CPPFLAGS -I$VULKAN_SDK/include" + LDFLAGS="$LDFLAGS -L$VULKAN_SDK/lib" + glslangvalidator="$VULKAN_SDK/bin/glslangValidator" + ], [glslangvalidator="glslangValidator"]) + AC_CHECK_HEADER( + [vulkan/vulkan.h], + dnl Make sure the library "works" + [AC_CHECK_LIB([vulkan], [vkCreateInstance], + [AC_DEFINE([HAVE_VULKAN], [1], [Define if yhou have the Vulkan libs]) + VULKAN_LIBS=-lvulkan], + [AC_MSG_RESULT(no)]) + ], + [AC_MSG_RESULT(no)] + ) + CPPFLAGS="$save_CPPFLAGS" +fi +AC_SUBST(VULKAN_LIBS) diff --git a/configure.ac b/configure.ac index ea203472c..aaf6492ea 100644 --- a/configure.ac +++ b/configure.ac @@ -64,6 +64,7 @@ m4_include(config.d/mgl.m4) m4_include(config.d/fbdev.m4) m4_include(config.d/svga.m4) m4_include(config.d/x11.m4) +m4_include(config.d/vulkan.m4) m4_include(config.d/sdl.m4) m4_include(config.d/curses.m4) diff --git a/include/QF/Vulkan/cvars.h b/include/QF/Vulkan/cvars.h new file mode 100644 index 000000000..9f318b8f0 --- /dev/null +++ b/include/QF/Vulkan/cvars.h @@ -0,0 +1,7 @@ +#ifndef __QF_Vulkan_cvars_h +#define __QF_Vulkan_cvars_h + +extern struct cvar_s *vulkan_library_name; +extern struct cvar_s *vulkan_use_validation; + +#endif//__QF_Vulkan_cvars_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h new file mode 100644 index 000000000..1ab96300c --- /dev/null +++ b/include/QF/Vulkan/funclist.h @@ -0,0 +1,55 @@ +#ifndef EXPORTED_VULKAN_FUNCTION +#define EXPORTED_VULKAN_FUNCTION(function) +#endif + +EXPORTED_VULKAN_FUNCTION (vkGetInstanceProcAddr) + +#undef EXPORTED_VULKAN_FUNCTION + +#ifndef GLOBAL_LEVEL_VULKAN_FUNCTION +#define GLOBAL_LEVEL_VULKAN_FUNCTION(function) +#endif + +GLOBAL_LEVEL_VULKAN_FUNCTION (vkEnumerateInstanceVersion) +GLOBAL_LEVEL_VULKAN_FUNCTION (vkEnumerateInstanceExtensionProperties) +GLOBAL_LEVEL_VULKAN_FUNCTION (vkEnumerateInstanceLayerProperties) +GLOBAL_LEVEL_VULKAN_FUNCTION (vkCreateInstance) + +#undef GLOBAL_LEVEL_VULKAN_FUNCTION + +#ifndef INSTANCE_LEVEL_VULKAN_FUNCTION +#define INSTANCE_LEVEL_VULKAN_FUNCTION(function) +#endif + +INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumeratePhysicalDevices) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceProperties) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceFeatures) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkCreateDevice) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetDeviceProcAddr) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceLayerProperties) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceExtensionProperties) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceMemoryProperties) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceQueueFamilyProperties) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkDestroyInstance) + +#undef INSTANCE_LEVEL_VULKAN_FUNCTION + +#ifndef INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION +#define INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION(function) +#endif + +INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION (vkCreateDebugUtilsMessengerEXT) + +#undef INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION + +#ifndef DEVICE_LEVEL_VULKAN_FUNCTION +#define DEVICE_LEVEL_VULKAN_FUNCTION(function) +#endif + +#undef DEVICE_LEVEL_VULKAN_FUNCTION + +#ifndef DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION +#define DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION(function) +#endif + +#undef DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION diff --git a/include/QF/Vulkan/funcs.h b/include/QF/Vulkan/funcs.h new file mode 100644 index 000000000..975f5485b --- /dev/null +++ b/include/QF/Vulkan/funcs.h @@ -0,0 +1,9 @@ +#ifndef __QF_Vulkan_funcs_h +#define __QF_Vulkan_funcs_h + +#define EXPORTED_VULKAN_FUNCTION(fname) extern PFN_##fname fname; +#define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) extern PFN_##fname fname; + +#include "QF/Vulkan/funclist.h" + +#endif//__QF_Vulkan_funcs_h diff --git a/include/QF/Vulkan/init.h b/include/QF/Vulkan/init.h new file mode 100644 index 000000000..b12dcd42e --- /dev/null +++ b/include/QF/Vulkan/init.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2019 Bill Currie + + Author: Bill Currie + Date: 2019/6/29 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_init_h +#define __QF_Vulkan_init_h + +#include + +#include "QF/qtypes.h" +#include "QF/Vulkan/funcs.h" + +typedef struct { + VkPhysicalDevice device; + VkPhysicalDeviceProperties properties; + uint32_t numLayers; + VkLayerProperties *layers; + uint32_t numExtensions; + VkExtensionProperties *extensions; + VkPhysicalDeviceFeatures features; + VkPhysicalDeviceMemoryProperties memory; + uint32_t numQueueFamilies; + VkQueueFamilyProperties *queueFamilies; +} VulkanPhysDevice_t; + +typedef struct { + VkInstance instance; + VkDebugUtilsMessengerEXT debug_callback; + uint32_t numDevices; + VulkanPhysDevice_t *devices; + + #define INSTANCE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; + #define INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) PFN_##name name; + #include "QF/Vulkan/funclist.h" +} VulkanInstance_t; + +void Vulkan_Init_Cvars (void); +VulkanInstance_t *Vulkan_CreateInstance (const char *appName, + uint32_t appVersion, + const char **layers, + const char **extensions); +void Vulkan_DestroyInstance (VulkanInstance_t *instance); + +#endif // __QF_Vulkan_init_h diff --git a/include/QF/Vulkan/qf_draw.h b/include/QF/Vulkan/qf_draw.h new file mode 100644 index 000000000..e4716f7ed --- /dev/null +++ b/include/QF/Vulkan/qf_draw.h @@ -0,0 +1,37 @@ +/* + qf_draw.h + + vulkan specific draw function + + Copyright (C) 1996-1997 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __gl_draw_h +#define __gl_draw_h + +void Vulkan_Set2D (void); +void Vulkan_Set2DScaled (void); +void Vulkan_End2D (void); +void Vulkan_DrawReset (void); +void Vulkan_FlushText (void); + +#endif//__gl_draw_h diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h new file mode 100644 index 000000000..d032a075a --- /dev/null +++ b/include/QF/Vulkan/qf_vid.h @@ -0,0 +1,36 @@ +/* + Vulkan/qf_vid.h + + vulkan vid stuff from the renderer. + + Copyright (C) 1996-1997 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_Vulkan_vid_h +#define __QF_Vulkan_vid_h + +#include "QF/Vulkan/cvars.h" + +void Vulkan_Init_Common (void); +void Vulkan_Shutdown_Common (void); + +#endif // __QF_Vulkan_vid_h diff --git a/libs/video/renderer/Makefile.am b/libs/video/renderer/Makefile.am index 2c234fe33..f7a0fa0cd 100644 --- a/libs/video/renderer/Makefile.am +++ b/libs/video/renderer/Makefile.am @@ -16,7 +16,8 @@ noinst_LTLIBRARIES= libQFrenderer.la @vid_render_static_plugins@ EXTRA_LTLIBRARIES= \ vid_render_sw.la vid_render_sw32.la \ - vid_render_gl.la vid_render_glsl.la + vid_render_gl.la vid_render_glsl.la \ + vid_render_vulkan.la common_sources= \ crosshair.c noisetextures.c r_alias.c r_bsp.c r_cvar.c r_dyn_textures.c \ @@ -63,3 +64,10 @@ vid_render_sw32_la_LDFLAGS= $(plugin_ldflags) vid_render_sw32_la_LIBADD= $(sw32_libs) vid_render_sw32_la_DEPENDENCIES=$(sw32_libs) vid_render_sw32_la_SOURCES= $(common_sources) vid_render_sw32.c + +vulkan_libs= \ + vulkan/libvulkan.la +vid_render_vulkan_la_LDFLAGS= $(plugin_ldflags) +vid_render_vulkan_la_LIBADD= $(vulkan_libs) +vid_render_vulkan_la_DEPENDENCIES=$(vulkan_libs) +vid_render_vulkan_la_SOURCES= $(common_sources) vid_render_vulkan.c diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c new file mode 100644 index 000000000..820d58fa6 --- /dev/null +++ b/libs/video/renderer/vid_render_vulkan.c @@ -0,0 +1,193 @@ +/* + vid_render_vulkan.c + + Vulkan version of the renderer + + Copyright (C) 2019 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define NH_DEFINE +#include "vulkan/namehack.h" + +#include "QF/plugin/general.h" +#include "QF/plugin/vid_render.h" + +#include "QF/Vulkan/qf_vid.h" + +#include "mod_internal.h" +#include "r_internal.h" + +#include "vulkan/namehack.h" + +static vid_model_funcs_t model_funcs = { +/* vulkan_Mod_LoadExternalTextures, + vulkan_Mod_LoadLighting, + vulkan_Mod_SubdivideSurface, + vulkan_Mod_ProcessTexture, + + Mod_LoadIQM, + Mod_LoadAliasModel, + Mod_LoadSpriteModel, + + vulkan_Mod_MakeAliasModelDisplayLists, + vulkan_Mod_LoadSkin, + vulkan_Mod_FinalizeAliasModel, + vulkan_Mod_LoadExternalSkins, + vulkan_Mod_IQMFinish, + 0, + vulkan_Mod_SpriteLoadTexture, + + Skin_SetColormap, + Skin_SetSkin, + vulkan_Skin_SetupSkin, + Skin_SetTranslation, + vulkan_Skin_ProcessTranslation, + vulkan_Skin_InitTranslations,*/ +}; + +vid_render_funcs_t vulkan_vid_render_funcs = { + vulkan_Draw_Init, + vulkan_Draw_Character, + vulkan_Draw_String, + vulkan_Draw_nString, + vulkan_Draw_AltString, + vulkan_Draw_ConsoleBackground, + vulkan_Draw_Crosshair, + vulkan_Draw_CrosshairAt, + vulkan_Draw_TileClear, + vulkan_Draw_Fill, + vulkan_Draw_TextBox, + vulkan_Draw_FadeScreen, + vulkan_Draw_BlendScreen, + vulkan_Draw_CachePic, + vulkan_Draw_UncachePic, + vulkan_Draw_MakePic, + vulkan_Draw_DestroyPic, + vulkan_Draw_PicFromWad, + vulkan_Draw_Pic, + vulkan_Draw_Picf, + vulkan_Draw_SubPic, + +/* vulkan_SCR_UpdateScreen, + SCR_DrawRam, + SCR_DrawTurtle, + SCR_DrawPause, + vulkan_SCR_CaptureBGR, + vulkan_SCR_ScreenShot, + SCR_DrawStringToSnap, + + vulkan_Fog_Update, + vulkan_Fog_ParseWorldspawn, + + vulkan_R_Init, + vulkan_R_ClearState, + vulkan_R_LoadSkys, + vulkan_R_NewMap, + R_AddEfrags, + R_RemoveEfrags, + R_EnqueueEntity, + vulkan_R_LineGraph, + R_AllocDlight, + R_AllocEntity, + vulkan_R_RenderView, + R_DecayLights, + vulkan_R_ViewChanged, + vulkan_R_ClearParticles, + vulkan_R_InitParticles, + vulkan_SCR_ScreenShot_f, + vulkan_r_easter_eggs_f, + vulkan_r_particles_style_f, + 0, + &model_funcs*/ +}; + +static void +set_palette (const byte *palette) +{ + //FIXME really don't want this here: need an application domain + //so Quake can be separated from QuakeForge (ie, Quake itself becomes + //an app using the QuakeForge engine) +} + +static void +vulkan_vid_render_init (void) +{ + vr_data.vid->set_palette = set_palette; + vr_data.vid->init_gl = Vulkan_Init_Common; + vr_data.vid->load_gl (); + vr_funcs = &vulkan_vid_render_funcs; + m_funcs = &model_funcs; +} + +static void +vulkan_vid_render_shutdown (void) +{ + Vulkan_Shutdown_Common (); +} + +static general_funcs_t plugin_info_general_funcs = { + vulkan_vid_render_init, + vulkan_vid_render_shutdown, +}; + +static general_data_t plugin_info_general_data; + +static plugin_funcs_t plugin_info_funcs = { + &plugin_info_general_funcs, + 0, + 0, + 0, + 0, + 0, + &vulkan_vid_render_funcs, +}; + +static plugin_data_t plugin_info_data = { + &plugin_info_general_data, + 0, + 0, + 0, + 0, + 0, + &vid_render_data, +}; + +static plugin_t plugin_info = { + qfp_snd_render, + 0, + QFPLUGIN_VERSION, + "0.1", + "GLSL Renderer", + "Copyright (C) 1996-1997 Id Software, Inc.\n" + "Copyright (C) 1999-2012 contributors of the QuakeForge project\n" + "Please see the file \"AUTHORS\" for a list of contributors", + &plugin_info_funcs, + &plugin_info_data, +}; + +PLUGIN_INFO(vid_render, vulkan) +{ + return &plugin_info; +} diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am new file mode 100644 index 000000000..f3b3d32c5 --- /dev/null +++ b/libs/video/renderer/vulkan/Makefile.am @@ -0,0 +1,26 @@ +AUTOMAKE_OPTIONS= foreign + +AM_CFLAGS= @PREFER_PIC@ +AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES + +vulkan_src = \ + init.c \ + vulkan_draw.c \ + vulkan_funcs.c \ + vulkan_vid_common.c + +noinst_LTLIBRARIES= libvulkan.la +BUILT_SOURCES= $(shader_gen) + +SUFFICES=.frag .vert .fc .vc .slc .glsl +.glsl.slc: + sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ +.frag.fc: + sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ +.vert.vc: + sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ + +libvulkan_la_SOURCES= $(vulkan_src) + +EXTRA_DIST = $(vulkan_src) $(shader_src) namehack.h +CLEANFILES= *.vc *.fc *.slc diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c new file mode 100644 index 000000000..4967c8125 --- /dev/null +++ b/libs/video/renderer/vulkan/init.c @@ -0,0 +1,390 @@ +/* + int.c + + Copyright (C) 2019 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/init.h" + +cvar_t *vulkan_library_name; +cvar_t *vulkan_use_validation; + +static uint32_t numLayers; +static VkLayerProperties *instanceLayerProperties; +static const char **instanceLayerNames; +static uint32_t numExtensions; +static VkExtensionProperties *instanceExtensionProperties; +static const char **instanceExtensionNames; + +static const char *validationLayers[] = { + "VK_LAYER_LUNARG_standard_validation", + 0, +}; + +static const char *debugExtensions[] = { + VK_EXT_DEBUG_UTILS_EXTENSION_NAME, + 0, +}; + +static const char *device_types[] = { + "other", + "integrated gpu", + "discrete gpu", + "virtual gpu", + "cpu", +}; + +static void +get_instance_layers_and_extensions (void) +{ + uint32_t i; + VkLayerProperties *properties; + VkExtensionProperties *extensions; + + vkEnumerateInstanceLayerProperties (&numLayers, 0); + properties = malloc (numLayers * sizeof (VkLayerProperties)); + vkEnumerateInstanceLayerProperties (&numLayers, properties); + instanceLayerNames = (const char **) malloc ((numLayers + 1) + * sizeof (const char **)); + for (i = 0; i < numLayers; i++) { + instanceLayerNames[i] = properties[i].layerName; + } + instanceLayerNames[i] = 0; + + vkEnumerateInstanceExtensionProperties (0, &numExtensions, 0); + extensions = malloc (numExtensions * sizeof (VkLayerProperties)); + vkEnumerateInstanceExtensionProperties (0, &numExtensions, extensions); + instanceExtensionNames = (const char **) malloc ((numExtensions + 1) + * sizeof (const char **)); + for (i = 0; i < numExtensions; i++) { + instanceExtensionNames[i] = extensions[i].extensionName; + } + instanceExtensionNames[i] = 0; + + if (developer->int_val & SYS_VID) { + for (i = 0; i < numLayers; i++) { + Sys_Printf ("%s %x %u %s\n", + properties[i].layerName, + properties[i].specVersion, + properties[i].implementationVersion, + properties[i].description); + } + for (i = 0; i < numExtensions; i++) { + Sys_Printf ("%d %s\n", + extensions[i].specVersion, + extensions[i].extensionName); + } + } + instanceLayerProperties = properties; + instanceExtensionProperties = extensions; +} + +static void +init_physdev (VulkanInstance_t *instance, VkPhysicalDevice dev, VulkanPhysDevice_t *physdev) +{ + physdev->device = dev; + + instance->vkGetPhysicalDeviceProperties (dev, &physdev->properties); + + instance->vkEnumerateDeviceLayerProperties (dev, &physdev->numLayers, 0); + physdev->layers = malloc (physdev->numLayers * sizeof (VkLayerProperties)); + instance->vkEnumerateDeviceLayerProperties (dev, &physdev->numLayers, + physdev->layers); + + instance->vkEnumerateDeviceExtensionProperties (dev, 0, + &physdev->numExtensions, + 0); + physdev->extensions = malloc (physdev->numExtensions + * sizeof (VkExtensionProperties)); + instance->vkEnumerateDeviceExtensionProperties (dev, 0, + &physdev->numExtensions, + physdev->extensions); + + instance->vkGetPhysicalDeviceFeatures (dev, &physdev->features); + + instance->vkGetPhysicalDeviceMemoryProperties (dev, &physdev->memory); + + instance->vkGetPhysicalDeviceQueueFamilyProperties (dev, + &physdev->numQueueFamilies, + 0); + physdev->queueFamilies = malloc (physdev->numQueueFamilies + * sizeof (VkQueueFamilyProperties)); + instance->vkGetPhysicalDeviceQueueFamilyProperties (dev, + &physdev->numQueueFamilies, + physdev->queueFamilies); + + if (developer->int_val & SYS_VID) { + VkPhysicalDeviceProperties *prop = &physdev->properties; + Sys_Printf ("dev: %p\n", dev); + Sys_Printf (" %x %x\n", prop->apiVersion, prop->driverVersion); + Sys_Printf (" %x %x\n", prop->vendorID, prop->deviceID); + Sys_Printf (" %s: %s\n", device_types[prop->deviceType], + prop->deviceName); + for (uint32_t i = 0; i < physdev->numLayers; i++) { + Sys_Printf (" %s %x %u %s\n", + physdev->layers[i].layerName, + physdev->layers[i].specVersion, + physdev->layers[i].implementationVersion, + physdev->layers[i].description); + } + for (uint32_t i = 0; i < physdev->numExtensions; i++) { + Sys_Printf (" %u %s\n", + physdev->extensions[i].specVersion, + physdev->extensions[i].extensionName); + } + Sys_Printf (" memory types:\n"); + for (uint32_t i = 0; i < physdev->memory.memoryTypeCount; i++) { + Sys_Printf (" %x %d\n", + physdev->memory.memoryTypes[i].propertyFlags, + physdev->memory.memoryTypes[i].heapIndex); + } + Sys_Printf (" memory heaps:\n"); + for (uint32_t i = 0; i < physdev->memory.memoryHeapCount; i++) { + Sys_Printf (" %x %ld\n", + physdev->memory.memoryHeaps[i].flags, + physdev->memory.memoryHeaps[i].size); + } + Sys_Printf (" queue families:\n"); + for (uint32_t i = 0; i < physdev->numQueueFamilies; i++) { + VkQueueFamilyProperties *queue = &physdev->queueFamilies[i]; + VkExtent3D gran = queue->minImageTransferGranularity; + Sys_Printf (" %x %3d %3d [%d %d %d]\n", + queue->queueFlags, + queue->queueCount, + queue->timestampValidBits, + gran.width, gran.height, gran.depth); + } + } +} + +static int +count_strings (const char **str) +{ + int count = 0; + + if (str) { + while (*str++) { + count++; + } + } + return count; +} + +static void +merge_strings (const char **out, const char **in1, const char **in2) +{ + if (in1) { + while (*in1) { + *out++ = *in1++; + } + } + if (in2) { + while (*in2) { + *out++ = *in2++; + } + } +} + +static void +prune_strings (const char * const *reference, const char **strings, + uint32_t *count) +{ + for (int i = *count; i-- > 0; ) { + const char *str = strings[i]; + const char * const *ref; + for (ref = reference; *ref; ref++) { + if (!strcmp (*ref, str)) { + break; + } + } + if (!*ref) { + memmove (strings + i, strings + i + 1, + (--(*count) - i) * sizeof (const char **)); + } + } +} + +static int message_severities = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; +static int message_types = + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + +static VKAPI_ATTR VkBool32 VKAPI_CALL +debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* callbackData, + void *data) +{ + fprintf (stderr, "validation layer: %s\n", callbackData->pMessage); + return VK_FALSE; +} + +static void +setup_debug_callback (VulkanInstance_t *instance) +{ + VkDebugUtilsMessengerCreateInfoEXT createInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .messageSeverity = message_severities, + .messageType = message_types, + .pfnUserCallback = debug_callback, + .pUserData = instance, + }; + instance->vkCreateDebugUtilsMessengerEXT(instance->instance, &createInfo, + 0, &instance->debug_callback); +} + +static void +load_instance_funcs (VulkanInstance_t *instance) +{ +#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) \ + instance->name = (PFN_##name) vkGetInstanceProcAddr (instance->instance, \ + #name); \ + if (!instance->name) { \ + Sys_Error ("Couldn't find instance level function %s", #name); \ + } + +#define INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) \ + instance->name = (PFN_##name) vkGetInstanceProcAddr (instance->instance,\ + #name); \ + if (!instance->name) { \ + Sys_Printf ("Couldn't find instance level function %s", #name); \ + } + +#include "QF/Vulkan/funclist.h" +} + +VulkanInstance_t * +Vulkan_CreateInstance (const char *appName, uint32_t appVersion, + const char **layers, const char **extensions) +{ + VkApplicationInfo appInfo = { + VK_STRUCTURE_TYPE_APPLICATION_INFO, 0, + appName, appVersion, + PACKAGE_STRING, 0x000702ff, //FIXME version + VK_API_VERSION_1_0, + }; + VkInstanceCreateInfo createInfo = { + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0, + &appInfo, + 0, 0, + 0, 0, + }; + VkResult res; + VkInstance instance; + uint32_t numDev, i; + VkPhysicalDevice *devices; + VulkanInstance_t *inst; + + if (!instanceLayerProperties) { + get_instance_layers_and_extensions (); + } + + createInfo.enabledLayerCount = count_strings (layers); + createInfo.ppEnabledLayerNames = layers; + createInfo.enabledExtensionCount = count_strings (extensions); + createInfo.ppEnabledExtensionNames = extensions; + if (vulkan_use_validation->int_val) { + createInfo.enabledLayerCount += count_strings (validationLayers); + createInfo.enabledExtensionCount += count_strings (debugExtensions); + } + const char **lay = alloca (createInfo.enabledLayerCount * sizeof (const char *)); + const char **ext = alloca (createInfo.enabledExtensionCount * sizeof (const char *)); + if (vulkan_use_validation->int_val) { + merge_strings (lay, layers, validationLayers); + merge_strings (ext, extensions, debugExtensions); + } else { + merge_strings (lay, layers, 0); + merge_strings (ext, extensions, 0); + } + prune_strings (instanceLayerNames, lay, + &createInfo.enabledLayerCount); + prune_strings (instanceExtensionNames, ext, + &createInfo.enabledExtensionCount); + createInfo.ppEnabledLayerNames = lay; + createInfo.ppEnabledExtensionNames = ext; + + res = vkCreateInstance (&createInfo, 0, &instance); + if (res != VK_SUCCESS) { + Sys_Error ("unable to create vulkan instance\n"); + } + inst = malloc (sizeof(VulkanInstance_t)); + inst->instance = instance; + load_instance_funcs (inst); + + if (vulkan_use_validation->int_val) { + setup_debug_callback (inst); + } + + res = inst->vkEnumeratePhysicalDevices (instance, &numDev, 0); + if (res != VK_SUCCESS) { + Sys_Error ("unable to query vulkan device count: %d\n", res); + } + devices = malloc(numDev * sizeof (VkPhysicalDevice)); + res = inst->vkEnumeratePhysicalDevices (instance, &numDev, devices); + if (res != VK_SUCCESS) { + Sys_Error ("unable to query vulkan device properties: %d\n", res); + } + + inst->numDevices = numDev; + inst->devices = malloc (numDev * sizeof (VulkanPhysDevice_t)); + + for (i = 0; i < numDev; i++) { + init_physdev (inst, devices[i], &inst->devices[i]); + } + + return inst; +} + +void +Vulkan_DestroyInstance (VulkanInstance_t *instance) +{ + for (uint32_t i = 0; i < instance->numDevices; i++) { + free (instance->devices[i].queueFamilies); + free (instance->devices[i].extensions); + free (instance->devices[i].layers); + } + free (instance->devices); + instance->vkDestroyInstance (instance->instance, 0); + free (instance); +} diff --git a/libs/video/renderer/vulkan/namehack.h b/libs/video/renderer/vulkan/namehack.h new file mode 100644 index 000000000..7289995f2 --- /dev/null +++ b/libs/video/renderer/vulkan/namehack.h @@ -0,0 +1,137 @@ +#ifdef NH_DEFINE +#undef NH_DEFINE +#define Draw_Init vulkan_Draw_Init +#define Draw_Character vulkan_Draw_Character +#define Draw_String vulkan_Draw_String +#define Draw_nString vulkan_Draw_nString +#define Draw_AltString vulkan_Draw_AltString +#define Draw_ConsoleBackground vulkan_Draw_ConsoleBackground +#define Draw_Crosshair vulkan_Draw_Crosshair +#define Draw_CrosshairAt vulkan_Draw_CrosshairAt +#define Draw_TileClear vulkan_Draw_TileClear +#define Draw_Fill vulkan_Draw_Fill +#define Draw_TextBox vulkan_Draw_TextBox +#define Draw_FadeScreen vulkan_Draw_FadeScreen +#define Draw_BlendScreen vulkan_Draw_BlendScreen +#define Draw_CachePic vulkan_Draw_CachePic +#define Draw_UncachePic vulkan_Draw_UncachePic +#define Draw_MakePic vulkan_Draw_MakePic +#define Draw_DestroyPic vulkan_Draw_DestroyPic +#define Draw_PicFromWad vulkan_Draw_PicFromWad +#define Draw_Pic vulkan_Draw_Pic +#define Draw_Picf vulkan_Draw_Picf +#define Draw_SubPic vulkan_Draw_SubPic +#define Fog_DisableGFog vulkan_Fog_DisableGFog +#define Fog_EnableGFog vulkan_Fog_EnableGFog +#define Fog_GetColor vulkan_Fog_GetColor +#define Fog_GetDensity vulkan_Fog_GetDensity +#define Fog_Init vulkan_Fog_Init +#define Fog_ParseWorldspawn vulkan_Fog_ParseWorldspawn +#define Fog_SetupFrame vulkan_Fog_SetupFrame +#define Fog_StartAdditive vulkan_Fog_StartAdditive +#define Fog_StopAdditive vulkan_Fog_StopAdditive +#define Fog_Update vulkan_Fog_Update +#define R_AddTexture vulkan_R_AddTexture +#define R_BlendLightmaps vulkan_R_BlendLightmaps +#define R_BuildLightMap vulkan_R_BuildLightMap +#define R_CalcLightmaps vulkan_R_CalcLightmaps +#define R_ClearParticles vulkan_R_ClearParticles +#define R_ClearState vulkan_R_ClearState +#define R_ClearTextures vulkan_R_ClearTextures +#define R_DrawAliasModel vulkan_R_DrawAliasModel +#define R_DrawBrushModel vulkan_R_DrawBrushModel +#define R_DrawParticles vulkan_R_DrawParticles +#define R_DrawSky vulkan_R_DrawSky +#define R_DrawSkyChain vulkan_R_DrawSkyChain +#define R_DrawSprite vulkan_R_DrawSprite +#define R_DrawSpriteModel vulkan_R_DrawSpriteModel +#define R_DrawWaterSurfaces vulkan_R_DrawWaterSurfaces +#define R_DrawWorld vulkan_R_DrawWorld +#define R_InitBubble vulkan_R_InitBubble +#define R_InitGraphTextures vulkan_R_InitGraphTextures +#define R_InitParticles vulkan_R_InitParticles +#define R_InitSky vulkan_R_InitSky +#define R_InitSprites vulkan_R_InitSprites +#define R_InitSurfaceChains vulkan_R_InitSurfaceChains +#define R_LineGraph vulkan_R_LineGraph +#define R_LoadSky_f vulkan_R_LoadSky_f +#define R_LoadSkys vulkan_R_LoadSkys +#define R_NewMap vulkan_R_NewMap +#define R_Particle_New vulkan_R_Particle_New +#define R_Particle_NewRandom vulkan_R_Particle_NewRandom +#define R_Particles_Init_Cvars vulkan_R_Particles_Init_Cvars +#define R_ReadPointFile_f vulkan_R_ReadPointFile_f +#define R_RenderDlights vulkan_R_RenderDlights +#define R_RenderView vulkan_R_RenderView +#define R_RotateForEntity vulkan_R_RotateForEntity +#define R_SetupFrame vulkan_R_SetupFrame +#define R_SpriteBegin vulkan_R_SpriteBegin +#define R_SpriteEnd vulkan_R_SpriteEnd +#define R_TimeRefresh_f vulkan_R_TimeRefresh_f +#define R_ViewChanged vulkan_R_ViewChanged +#define SCR_CaptureBGR vulkan_SCR_CaptureBGR +#define SCR_ScreenShot vulkan_SCR_ScreenShot +#define SCR_ScreenShot_f vulkan_SCR_ScreenShot_f +#define SCR_UpdateScreen vulkan_SCR_UpdateScreen +#define c_alias_polys vulkan_c_alias_polys +#define c_brush_polys vulkan_c_brush_polys +#define r_easter_eggs_f vulkan_r_easter_eggs_f +#define r_particles_style_f vulkan_r_particles_style_f +#define r_world_matrix vulkan_r_world_matrix +#else +#undef Fog_DisableGFog +#undef Fog_EnableGFog +#undef Fog_GetColor +#undef Fog_GetDensity +#undef Fog_Init +#undef Fog_ParseWorldspawn +#undef Fog_SetupFrame +#undef Fog_StartAdditive +#undef Fog_StopAdditive +#undef Fog_Update +#undef R_AddTexture +#undef R_BlendLightmaps +#undef R_BuildLightMap +#undef R_CalcLightmaps +#undef R_ClearParticles +#undef R_ClearState +#undef R_ClearTextures +#undef R_DrawAliasModel +#undef R_DrawBrushModel +#undef R_DrawParticles +#undef R_DrawSky +#undef R_DrawSkyChain +#undef R_DrawSpriteModel +#undef R_DrawWaterSurfaces +#undef R_DrawWorld +#undef R_Init +#undef R_InitBubble +#undef R_InitGraphTextures +#undef R_InitParticles +#undef R_InitSky +#undef R_InitSprites +#undef R_InitSurfaceChains +#undef R_LineGraph +#undef R_LoadSky_f +#undef R_LoadSkys +#undef R_NewMap +#undef R_Particle_New +#undef R_Particle_NewRandom +#undef R_Particles_Init_Cvars +#undef R_ReadPointFile_f +#undef R_RenderDlights +#undef R_RenderView +#undef R_RotateForEntity +#undef R_SetupFrame +#undef R_TimeRefresh_f +#undef R_ViewChanged +#undef SCR_CaptureBGR +#undef SCR_ScreenShot +#undef SCR_ScreenShot_f +#undef SCR_UpdateScreen +#undef c_alias_polys +#undef c_brush_polys +#undef r_easter_eggs_f +#undef r_particles_style_f +#undef r_world_matrix +#endif diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c new file mode 100644 index 000000000..3c8dcc8e4 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -0,0 +1,189 @@ +/* + vulkan_draw.c + + 2D drawing support for Vulkan + + Copyright (C) 2011 Bill Currie + + Author: Bill Currie + Date: 2011/12/23 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define NH_DEFINE +#include "namehack.h" + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/draw.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/vid.h" + +#include "QF/Vulkan/qf_draw.h" +#include "QF/Vulkan/qf_vid.h" + +#include "r_internal.h" + +qpic_t * +vulkan_Draw_MakePic (int width, int height, const byte *data) +{ + return 0; +} + +void +vulkan_Draw_DestroyPic (qpic_t *pic) +{ +} + +qpic_t * +vulkan_Draw_PicFromWad (const char *name) +{ + return 0; +} + +qpic_t * +vulkan_Draw_CachePic (const char *path, qboolean alpha) +{ + return 0; +} + +void +vulkan_Draw_UncachePic (const char *path) +{ +} + +void +vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha) +{ +} + +void +vulkan_Draw_Init (void) +{ +} + +void +vulkan_Draw_Character (int x, int y, unsigned int chr) +{ +} + +void +vulkan_Draw_String (int x, int y, const char *str) +{ +} + +void +vulkan_Draw_nString (int x, int y, const char *str, int count) +{ +} + +void +vulkan_Draw_AltString (int x, int y, const char *str) +{ +} + +void +vulkan_Draw_CrosshairAt (int ch, int x, int y) +{ +} + +void +vulkan_Draw_Crosshair (void) +{ +} + +void +vulkan_Draw_Pic (int x, int y, qpic_t *pic) +{ +} + +void +vulkan_Draw_Picf (float x, float y, qpic_t *pic) +{ +} + +void +vulkan_Draw_SubPic (int x, int y, qpic_t *pic, int srcx, int srcy, int width, + int height) +{ +} + +void +vulkan_Draw_ConsoleBackground (int lines, byte alpha) +{ +} + +void +vulkan_Draw_TileClear (int x, int y, int w, int h) +{ +} + +void +vulkan_Draw_Fill (int x, int y, int w, int h, int c) +{ +} + +void +vulkan_Draw_FadeScreen (void) +{ +} + +void +Vulkan_Set2D (void) +{ +} + +void +Vulkan_Set2DScaled (void) +{ +} + +void +Vulkan_End2D (void) +{ +} + +void +Vulkan_DrawReset (void) +{ +} + +void +Vulkan_FlushText (void) +{ +} + +void +vulkan_Draw_BlendScreen (quat_t color) +{ +} diff --git a/libs/video/renderer/vulkan/vulkan_funcs.c b/libs/video/renderer/vulkan/vulkan_funcs.c new file mode 100644 index 000000000..2d8f79c9a --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_funcs.c @@ -0,0 +1,6 @@ +#include + +#define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; +#define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; + +#include "QF/Vulkan/funclist.h" diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c new file mode 100644 index 000000000..099135be7 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -0,0 +1,129 @@ +/* + vid_common_vulkan.c + + Common Vulkan video driver functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2019 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/init.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" + +static void *vulkan_library; + +static VulkanInstance_t *vulkan_instance; + +static void +load_vulkan_library (void) +{ + vulkan_library = dlopen (vulkan_library_name->string, RTLD_NOW); + if (!vulkan_library) { + Sys_Error ("Couldn't load vulkan library %s: %s", + vulkan_library_name->name, dlerror ()); + } + + #define EXPORTED_VULKAN_FUNCTION(name) \ + name = (PFN_##name) dlsym (vulkan_library, #name); \ + if (!name) { \ + Sys_Error ("Couldn't find exported vulkan function %s", #name); \ + } + + // Can't use vkGetInstanceProcAddr (0, ...) here because it grabs from + // the whole exe and thus sees the function pointers instead of the actual + // functions. Sure, could rename all the function pointers, but while that + // worked for gl and glsl, it also made it a real pain to work with the + // spec (or man pages, etc). Of course, namespaces would help, too. + #define GLOBAL_LEVEL_VULKAN_FUNCTION(name) \ + name = (PFN_##name) dlsym (vulkan_library, #name); \ + if (!name) { \ + Sys_Error ("Couldn't find global-level function %s", #name); \ + } + + #include "QF/Vulkan/funclist.h" +} + +void +Vulkan_Init_Cvars () +{ + vulkan_library_name = Cvar_Get ("vulkan_library", "libvulkan.so.1", + CVAR_ROM, 0, + "the name of the vulkan shared library"); + vulkan_use_validation = Cvar_Get ("vulkan_use_validation", "1", CVAR_NONE, + 0, + "enable LunarG Standard Validation " + "Layer if available (requires instance " + "restart)."); +} + +const char *extensions[] = { + "foo", + 0, +}; + +void +Vulkan_Init_Common (void) +{ + Vulkan_Init_Cvars (); + + load_vulkan_library (); + + vulkan_instance = Vulkan_CreateInstance (PACKAGE_STRING, 0x000702ff, 0, extensions);//FIXME version + Sys_Printf ("Vulkan_Init_Common\n"); + if (developer->int_val & SYS_VID) { + Vulkan_DestroyInstance (vulkan_instance); + Sys_Quit(); + } +} + +void +Vulkan_Shutdown_Common (void) +{ + Vulkan_DestroyInstance (vulkan_instance); +} From ab08e4f20738e7ee9aca220489008c17bb00e662 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 7 Jul 2019 01:28:05 +0900 Subject: [PATCH 002/435] Create a logical device with a single queue A single graphics-capable queue should be enough for now. However, I'm not sure I'm happy with a lot of the code: it's a bit difficult to write flexibly configured code for Vulkan (or seems to be at this stage), especially in C. --- include/QF/Vulkan/funclist.h | 6 +- include/QF/Vulkan/init.h | 14 ++- libs/video/renderer/vulkan/init.c | 20 ++++ .../video/renderer/vulkan/vulkan_vid_common.c | 105 +++++++++++++++++- 4 files changed, 138 insertions(+), 7 deletions(-) diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 1ab96300c..d0cc47a6f 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -24,13 +24,13 @@ GLOBAL_LEVEL_VULKAN_FUNCTION (vkCreateInstance) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumeratePhysicalDevices) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceFeatures) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceQueueFamilyProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkCreateDevice) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetDeviceProcAddr) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkDestroyInstance) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceLayerProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceExtensionProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceMemoryProperties) -INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceQueueFamilyProperties) -INSTANCE_LEVEL_VULKAN_FUNCTION (vkDestroyInstance) #undef INSTANCE_LEVEL_VULKAN_FUNCTION @@ -46,6 +46,8 @@ INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION (vkCreateDebugUtilsMessengerEXT) #define DEVICE_LEVEL_VULKAN_FUNCTION(function) #endif +DEVICE_LEVEL_VULKAN_FUNCTION (vkGetDeviceQueue) + #undef DEVICE_LEVEL_VULKAN_FUNCTION #ifndef DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION diff --git a/include/QF/Vulkan/init.h b/include/QF/Vulkan/init.h index b12dcd42e..4a97b82f8 100644 --- a/include/QF/Vulkan/init.h +++ b/include/QF/Vulkan/init.h @@ -31,14 +31,23 @@ #include "QF/qtypes.h" #include "QF/Vulkan/funcs.h" +typedef struct { + VkDevice device; + VkQueue queue; + + #define DEVICE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; + #define DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) PFN_##name name; + #include "QF/Vulkan/funclist.h" +} VulkanDevice_t; + typedef struct { VkPhysicalDevice device; + VkPhysicalDeviceFeatures features; VkPhysicalDeviceProperties properties; uint32_t numLayers; VkLayerProperties *layers; uint32_t numExtensions; VkExtensionProperties *extensions; - VkPhysicalDeviceFeatures features; VkPhysicalDeviceMemoryProperties memory; uint32_t numQueueFamilies; VkQueueFamilyProperties *queueFamilies; @@ -61,5 +70,8 @@ VulkanInstance_t *Vulkan_CreateInstance (const char *appName, const char **layers, const char **extensions); void Vulkan_DestroyInstance (VulkanInstance_t *instance); +int Vulkan_ExtensionsSupported (const VkExtensionProperties *extensions, + int numExtensions, + const char * const *requested); #endif // __QF_Vulkan_init_h diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c index 4967c8125..2c4fb7ca1 100644 --- a/libs/video/renderer/vulkan/init.c +++ b/libs/video/renderer/vulkan/init.c @@ -388,3 +388,23 @@ Vulkan_DestroyInstance (VulkanInstance_t *instance) instance->vkDestroyInstance (instance->instance, 0); free (instance); } + +int +Vulkan_ExtensionsSupported (const VkExtensionProperties *extensions, + int numExtensions, + const char * const *requested) +{ + while (*requested) { + int i; + for (i = 0; i < numExtensions; i++) { + if (!strcmp (*requested, extensions[i].extensionName)) { + break; + } + } + if (i < numExtensions) { + // requested extension not found + break; + } + } + return !*requested; +} diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 099135be7..43921df30 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -59,6 +59,7 @@ static void *vulkan_library; static VulkanInstance_t *vulkan_instance; +static VulkanDevice_t *vulkan_device; static void load_vulkan_library (void) @@ -102,21 +103,117 @@ Vulkan_Init_Cvars () "restart)."); } -const char *extensions[] = { - "foo", +static const char *instance_extensions[] = { 0, }; +static const char *device_extensions[] = { + 0, +}; + +static int +count_bits (uint32_t val) +{ + int bits = 0; + while (val) { + bits += val & 1; + val >>= 1; + } + return bits; +} + +static int +find_queue_family (VulkanPhysDevice_t *dev, uint32_t flags) +{ + int best_diff = 32; + uint32_t family = -1; + + for (uint32_t i = 0; i < dev->numQueueFamilies; i++) { + VkQueueFamilyProperties *queue = &dev->queueFamilies[i]; + + if ((queue->queueFlags & flags) == flags) { + int diff = count_bits (queue->queueFlags & ~flags); + if (diff < best_diff) { + best_diff = diff; + family = i; + } + } + } + return family; +} + +static void +load_device_funcs (VulkanInstance_t *inst, VulkanDevice_t *dev) +{ +#define DEVICE_LEVEL_VULKAN_FUNCTION(name) \ + dev->name = (PFN_##name) inst->vkGetDeviceProcAddr (dev->device, #name); \ + if (!dev->name) { \ + Sys_Error ("Couldn't find device level function %s", #name); \ + } + +#define DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) \ + dev->name = (PFN_##name) inst->vkGetDeviceProcAddr (dev->device, #name); \ + if (!dev->name) { \ + Sys_Printf ("Couldn't find device level function %s", #name); \ + } + +#include "QF/Vulkan/funclist.h" +} + +static VulkanDevice_t * +create_suitable_device (VulkanInstance_t *instance) +{ + for (uint32_t i = 0; i < instance->numDevices; i++) { + VulkanPhysDevice_t *phys = &instance->devices[i]; + if (!Vulkan_ExtensionsSupported (phys->extensions, phys->numExtensions, + device_extensions)) { + return 0; + } + int family = find_queue_family (phys, VK_QUEUE_GRAPHICS_BIT); + if (family < 0) { + return 0; + } + float priority = 1; + VkDeviceQueueCreateInfo qCreateInfo = { + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0, + family, 1, &priority + }; + VkPhysicalDeviceFeatures features; + VkDeviceCreateInfo dCreateInfo = { + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0, + 1, &qCreateInfo, + 0, 0, + 0, device_extensions, + &features + }; + memset (&features, 0, sizeof (features)); + VulkanDevice_t *device = calloc (1, sizeof (VulkanDevice_t)); + if (instance->vkCreateDevice (phys->device, &dCreateInfo, 0, + &device->device) == VK_SUCCESS) { + load_device_funcs (instance, device); + device->vkGetDeviceQueue (device->device, family, + 0, &device->queue); + return device; + } + } + return 0; +} + void Vulkan_Init_Common (void) { + Sys_Printf ("Vulkan_Init_Common\n"); Vulkan_Init_Cvars (); load_vulkan_library (); - vulkan_instance = Vulkan_CreateInstance (PACKAGE_STRING, 0x000702ff, 0, extensions);//FIXME version - Sys_Printf ("Vulkan_Init_Common\n"); + vulkan_instance = Vulkan_CreateInstance (PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version + vulkan_device = create_suitable_device (vulkan_instance); + if (!vulkan_device) { + Sys_Error ("no suitable vulkan device found"); + } if (developer->int_val & SYS_VID) { + Sys_Printf ("%p %p\n", vulkan_device->device, vulkan_device->queue); Vulkan_DestroyInstance (vulkan_instance); Sys_Quit(); } From 940ef833ae1541af9623c1c797045787a1b133a5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 7 Jul 2019 14:34:02 +0900 Subject: [PATCH 003/435] Shutdown Vulkan properly Well, as properly as can be considering how little is started up :P --- include/QF/Vulkan/funclist.h | 1 + libs/video/renderer/vulkan/vulkan_vid_common.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index d0cc47a6f..2b755889e 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -46,6 +46,7 @@ INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION (vkCreateDebugUtilsMessengerEXT) #define DEVICE_LEVEL_VULKAN_FUNCTION(function) #endif +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyDevice) DEVICE_LEVEL_VULKAN_FUNCTION (vkGetDeviceQueue) #undef DEVICE_LEVEL_VULKAN_FUNCTION diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 43921df30..ba4a16915 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -214,7 +214,7 @@ Vulkan_Init_Common (void) } if (developer->int_val & SYS_VID) { Sys_Printf ("%p %p\n", vulkan_device->device, vulkan_device->queue); - Vulkan_DestroyInstance (vulkan_instance); + Vulkan_Shutdown_Common (); Sys_Quit(); } } @@ -222,5 +222,13 @@ Vulkan_Init_Common (void) void Vulkan_Shutdown_Common (void) { + if (vulkan_device) { + vulkan_device->vkDestroyDevice (vulkan_device->device, 0); + free (vulkan_device); + vulkan_device = 0; + } Vulkan_DestroyInstance (vulkan_instance); + vulkan_instance = 0; + dlclose (vulkan_library); + vulkan_library = 0; } From 77afc3048637e9cd7b63cfa96169d74195e2ceeb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 7 Jul 2019 14:57:56 +0900 Subject: [PATCH 004/435] Fix vid renderer plugin types I guess that plugin type is currently not checked, otherwise I doubt the mistake would have gone unnoticed. --- libs/video/renderer/vid_render_gl.c | 2 +- libs/video/renderer/vid_render_glsl.c | 2 +- libs/video/renderer/vid_render_sw.c | 2 +- libs/video/renderer/vid_render_sw32.c | 2 +- libs/video/renderer/vid_render_vulkan.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index c79bfaa20..42f5df1dc 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -166,7 +166,7 @@ static plugin_data_t plugin_info_data = { }; static plugin_t plugin_info = { - qfp_snd_render, + qfp_vid_render, 0, QFPLUGIN_VERSION, "0.1", diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index f09820ab3..f162231d1 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -166,7 +166,7 @@ static plugin_data_t plugin_info_data = { }; static plugin_t plugin_info = { - qfp_snd_render, + qfp_vid_render, 0, QFPLUGIN_VERSION, "0.1", diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 7ac10a4d4..7c2485911 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -156,7 +156,7 @@ static plugin_data_t plugin_info_data = { }; static plugin_t plugin_info = { - qfp_snd_render, + qfp_vid_render, 0, QFPLUGIN_VERSION, "0.1", diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index 9bc135c78..40034c0dc 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -161,7 +161,7 @@ static plugin_data_t plugin_info_data = { }; static plugin_t plugin_info = { - qfp_snd_render, + qfp_vid_render, 0, QFPLUGIN_VERSION, "0.1", diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 820d58fa6..165d5d832 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -175,7 +175,7 @@ static plugin_data_t plugin_info_data = { }; static plugin_t plugin_info = { - qfp_snd_render, + qfp_vid_render, 0, QFPLUGIN_VERSION, "0.1", From d95e9f9af35010e493e5658bd317c0033a0ba679 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 7 Jul 2019 14:59:20 +0900 Subject: [PATCH 005/435] Correct vulkan plugin strings --- libs/video/renderer/vid_render_vulkan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 165d5d832..ec5ee4ea3 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -179,9 +179,9 @@ static plugin_t plugin_info = { 0, QFPLUGIN_VERSION, "0.1", - "GLSL Renderer", + "Vulkan Renderer", "Copyright (C) 1996-1997 Id Software, Inc.\n" - "Copyright (C) 1999-2012 contributors of the QuakeForge project\n" + "Copyright (C) 1999-2019 contributors of the QuakeForge project\n" "Please see the file \"AUTHORS\" for a list of contributors", &plugin_info_funcs, &plugin_info_data, From a755e50c847c00f5018cac27a7f545a7233d2a8d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 7 Jul 2019 15:38:29 +0900 Subject: [PATCH 006/435] Clean up vid access a little Things are still a mess, but a proper cleanup will be a lot of work and will, really, involve properly splitting quake-specific code* out from the rest of the renderer. * data loading and format specific stuff --- include/r_screen.h | 2 -- libs/video/renderer/r_screen.c | 3 --- libs/video/renderer/vid_common.c | 2 ++ 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/include/r_screen.h b/include/r_screen.h index 4fb5e91cd..7955fdd3d 100644 --- a/include/r_screen.h +++ b/include/r_screen.h @@ -64,8 +64,6 @@ extern struct qpic_s *scr_turtle; extern int clearconsole; extern int clearnotify; -extern viddef_t vid; // global video state - extern vrect_t *pconupdate; extern vrect_t scr_vrect; diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index a6d129674..6eb307229 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -104,8 +104,6 @@ qpic_t *scr_turtle; int clearconsole; -viddef_t vid; // global video state - vrect_t *pconupdate; vrect_t scr_vrect; @@ -365,6 +363,5 @@ SCR_Init (void) scr_ram = vr_funcs->Draw_PicFromWad ("ram"); scr_turtle = vr_funcs->Draw_PicFromWad ("turtle"); - vid = *vr_data.vid; // cache scr_initialized = true; } diff --git a/libs/video/renderer/vid_common.c b/libs/video/renderer/vid_common.c index 5a2cd9d43..74a1140b0 100644 --- a/libs/video/renderer/vid_common.c +++ b/libs/video/renderer/vid_common.c @@ -34,6 +34,8 @@ #include "mod_internal.h" #include "r_internal.h" +viddef_t vid; // global video state + vid_render_data_t vid_render_data = { &vid, &r_refdef, &scr_vrect, 0, 0, 0, From 7137d61c3698a0664c64ed27824b972b8b19b842 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 7 Jul 2019 16:27:55 +0900 Subject: [PATCH 007/435] Add some extensions needed for presentation --- libs/video/renderer/vulkan/Makefile.am | 2 +- libs/video/renderer/vulkan/vulkan_vid_common.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index f3b3d32c5..5d2f65d8e 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -1,7 +1,7 @@ AUTOMAKE_OPTIONS= foreign AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES +AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES -DVK_USE_PLATFORM_XLIB_KHR vulkan_src = \ init.c \ diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index ba4a16915..42b751de0 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -104,6 +104,8 @@ Vulkan_Init_Cvars () } static const char *instance_extensions[] = { + VK_KHR_SURFACE_EXTENSION_NAME, + VK_KHR_XLIB_SURFACE_EXTENSION_NAME, 0, }; From 613779568291aee01dd3656dfe2bcfb12f64b9fd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 7 Jul 2019 16:48:53 +0900 Subject: [PATCH 008/435] Use deep binding for the vulkan loader This fixes the problem with using vkGetInstanceProcAddr to find global vulkan functions. --- libs/video/renderer/vulkan/vulkan_vid_common.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 42b751de0..9366799cb 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -64,7 +64,8 @@ static VulkanDevice_t *vulkan_device; static void load_vulkan_library (void) { - vulkan_library = dlopen (vulkan_library_name->string, RTLD_NOW); + vulkan_library = dlopen (vulkan_library_name->string, + RTLD_DEEPBIND | RTLD_NOW); if (!vulkan_library) { Sys_Error ("Couldn't load vulkan library %s: %s", vulkan_library_name->name, dlerror ()); @@ -76,13 +77,8 @@ load_vulkan_library (void) Sys_Error ("Couldn't find exported vulkan function %s", #name); \ } - // Can't use vkGetInstanceProcAddr (0, ...) here because it grabs from - // the whole exe and thus sees the function pointers instead of the actual - // functions. Sure, could rename all the function pointers, but while that - // worked for gl and glsl, it also made it a real pain to work with the - // spec (or man pages, etc). Of course, namespaces would help, too. #define GLOBAL_LEVEL_VULKAN_FUNCTION(name) \ - name = (PFN_##name) dlsym (vulkan_library, #name); \ + name = (PFN_##name) vkGetInstanceProcAddr (0, #name); \ if (!name) { \ Sys_Error ("Couldn't find global-level function %s", #name); \ } From 3e1520c2469bf40b63fc2661db095878d67e6bad Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 8 Jul 2019 12:46:22 +0900 Subject: [PATCH 009/435] Move vid callback access into vid The plan is to move the callbacks into a "private" struct. --- include/QF/vid.h | 1 + libs/video/targets/vid.c | 7 +++++++ nq/include/client.h | 1 + nq/source/cl_main.c | 8 ++++++++ nq/source/host.c | 5 +---- nq/source/sv_ded.c | 5 +++++ qw/source/cl_main.c | 3 +-- 7 files changed, 24 insertions(+), 6 deletions(-) diff --git a/include/QF/vid.h b/include/QF/vid.h index 70298fa8b..057414b2f 100644 --- a/include/QF/vid.h +++ b/include/QF/vid.h @@ -88,5 +88,6 @@ void VID_Init_Cvars (void); void VID_Init (byte *palette, byte *colormap); void VID_Shutdown (void); void VID_SetCaption (const char *text); +void VID_ClearMemory (void); #endif // __vid_h_ diff --git a/libs/video/targets/vid.c b/libs/video/targets/vid.c index 46507e26d..d7aeb3b2d 100644 --- a/libs/video/targets/vid.c +++ b/libs/video/targets/vid.c @@ -305,3 +305,10 @@ VID_InitBuffers (void) if (viddef.init_caches) viddef.init_caches (viddef.surfcache, cachesize); } + +void +VID_ClearMemory (void) +{ + if (viddef.flush_caches) + viddef.flush_caches (); +} diff --git a/nq/include/client.h b/nq/include/client.h index e6dc80e97..54477f7b4 100644 --- a/nq/include/client.h +++ b/nq/include/client.h @@ -287,6 +287,7 @@ struct cbuf_s; void CL_Init (struct cbuf_s *cbuf); void CL_InitCvars (void); void CL_Shutdown (void); +void CL_ClearMemory (void); void CL_EstablishConnection (const char *host); void CL_Signon1 (void); diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index 7f6dd9e82..3f8e7bde6 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -130,6 +130,14 @@ CL_Shutdown (void) VID_Shutdown (); } +void +CL_ClearMemory (void) +{ + VID_ClearMemory (); + if (r_data) + r_data->force_fullscreen = 0; +} + void CL_InitCvars (void) { diff --git a/nq/source/host.c b/nq/source/host.c index f6b59cf8b..d15dd0431 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -495,8 +495,7 @@ void Host_ClearMemory (void) { Sys_MaskPrintf (SYS_DEV, "Clearing memory\n"); - if (viddef.flush_caches) - viddef.flush_caches (); + CL_ClearMemory (); Mod_ClearAll (); if (host_hunklevel) Hunk_FreeToLowMark (host_hunklevel); @@ -504,8 +503,6 @@ Host_ClearMemory (void) cls.signon = 0; memset (&sv, 0, sizeof (sv)); memset (&cl, 0, sizeof (cl)); - if (r_data) - r_data->force_fullscreen = 0; } /* diff --git a/nq/source/sv_ded.c b/nq/source/sv_ded.c index c22f9cc3a..44dd57408 100644 --- a/nq/source/sv_ded.c +++ b/nq/source/sv_ded.c @@ -68,6 +68,11 @@ CL_UpdateScreen (double realtime) { } +void +CL_ClearMemory (void) +{ +} + void CL_Cmd_ForwardToServer (void) { diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index 09fb1aec2..c2b3c3a35 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -412,8 +412,7 @@ CL_ClearState (void) CL_Init_Entity (&cl.viewent); Sys_MaskPrintf (SYS_DEV, "Clearing memory\n"); - if (viddef.flush_caches) - viddef.flush_caches (); + VID_ClearMemory (); Mod_ClearAll (); if (host_hunklevel) // FIXME: check this... Hunk_FreeToLowMark (host_hunklevel); From 6ee2df84452ab6a8fc25dfbafb993815a1d9fbf4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 8 Jul 2019 13:40:29 +0900 Subject: [PATCH 010/435] Move vid callbacks into vid_internal Currently segfaults because viddef is an alias for *r_data->vid, which has not yet been initialized (chicken and egg). --- include/QF/vid.h | 12 +----------- include/vid_internal.h | 14 ++++++++++++++ libs/video/renderer/gl/gl_rmisc.c | 7 ++++--- libs/video/renderer/gl/gl_screen.c | 5 +++-- libs/video/renderer/gl/qfgl_ext.c | 7 ++++--- libs/video/renderer/glsl/glsl_main.c | 5 +++-- libs/video/renderer/glsl/glsl_screen.c | 3 ++- libs/video/renderer/glsl/qfglsl.c | 5 +++-- libs/video/renderer/r_init.c | 5 +++-- libs/video/renderer/sw/d_init.c | 6 +++--- libs/video/renderer/sw/draw.c | 2 +- libs/video/renderer/sw32/d_init.c | 6 +++--- libs/video/renderer/sw32/draw.c | 2 +- libs/video/renderer/vid_render_gl.c | 7 ++++--- libs/video/renderer/vid_render_glsl.c | 7 ++++--- libs/video/renderer/vid_render_vulkan.c | 7 ++++--- libs/video/targets/vid.c | 23 ++++++++++++----------- libs/video/targets/vid_sdl.c | 14 +++++++++----- libs/video/targets/vid_x11.c | 13 ++++++++----- 19 files changed, 86 insertions(+), 64 deletions(-) diff --git a/include/QF/vid.h b/include/QF/vid.h index 057414b2f..93975ced6 100644 --- a/include/QF/vid.h +++ b/include/QF/vid.h @@ -61,17 +61,7 @@ typedef struct { int conheight; byte *direct; // direct drawing to framebuffer, if not // NULL - int (*surf_cache_size)(int width, int height); - void (*flush_caches)(void); - void (*init_caches)(void *cache, int size); - void (*do_screen_buffer)(void); - void (*set_palette)(const byte *palette); - - // gl stuff - void (*load_gl)(void); - void (*init_gl)(void); - void *(*get_proc_address)(const char *name, qboolean crit); - void (*end_rendering)(void); + struct vid_internal_s *vid_internal; } viddef_t; #define viddef (*r_data->vid) diff --git a/include/vid_internal.h b/include/vid_internal.h index bf1803270..fc1538202 100644 --- a/include/vid_internal.h +++ b/include/vid_internal.h @@ -4,6 +4,20 @@ #include "QF/vid.h" #include "QF/plugin/vid_render.h" +typedef struct vid_internal_s { + int (*surf_cache_size) (int width, int height); + void (*flush_caches) (void); + void (*init_caches) (void *cache, int size); + void (*do_screen_buffer) (void); + void (*set_palette) (const byte *palette); + + // gl stuff + void (*load_gl) (void); + void (*init_gl) (void); + void *(*get_proc_address) (const char *name, qboolean crit); + void (*end_rendering) (void); +} vid_internal_t; + extern struct cvar_s *vid_fullscreen; extern struct cvar_s *vid_system_gamma; extern struct cvar_s *vid_gamma; diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index a399c26bd..e054e37bf 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -64,6 +64,7 @@ #include "mod_internal.h" #include "r_internal.h" #include "varrays.h" +#include "vid_internal.h" /* R_Envmap_f @@ -121,7 +122,7 @@ R_Envmap_f (void) gl_envmap = false; qfglDrawBuffer (GL_BACK); qfglReadBuffer (GL_BACK); - vid.end_rendering (); + vid.vid_internal->end_rendering (); } void @@ -249,13 +250,13 @@ gl_R_TimeRefresh_f (void) double start, stop, time; int i; - vid.end_rendering (); + vid.vid_internal->end_rendering (); start = Sys_DoubleTime (); for (i = 0; i < 128; i++) { r_refdef.viewangles[1] = i * (360.0 / 128.0); gl_R_RenderView (); - vid.end_rendering (); + vid.vid_internal->end_rendering (); } stop = Sys_DoubleTime (); diff --git a/libs/video/renderer/gl/gl_screen.c b/libs/video/renderer/gl/gl_screen.c index d463880d8..73674e70c 100644 --- a/libs/video/renderer/gl/gl_screen.c +++ b/libs/video/renderer/gl/gl_screen.c @@ -59,6 +59,7 @@ #include "compat.h" #include "r_internal.h" #include "sbar.h" +#include "vid_internal.h" /* SCREEN SHOTS */ @@ -206,7 +207,7 @@ gl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) return; if (begun) - vid.end_rendering (); + vid.vid_internal->end_rendering (); vr_data.realtime = realtime; @@ -263,7 +264,7 @@ gl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) qfglFlush (); if (gl_finish->int_val) { - vid.end_rendering (); + vid.vid_internal->end_rendering (); begun = 0; } } diff --git a/libs/video/renderer/gl/qfgl_ext.c b/libs/video/renderer/gl/qfgl_ext.c index a46472609..41fe1f52b 100644 --- a/libs/video/renderer/gl/qfgl_ext.c +++ b/libs/video/renderer/gl/qfgl_ext.c @@ -61,6 +61,7 @@ #include "QF/GL/funcs.h" #include "r_internal.h" +#include "vid_internal.h" // First we need to get all the function pointers declared. #define QFGL_WANT(ret, name, args) \ @@ -75,9 +76,9 @@ qboolean GLF_FindFunctions (void) { #define QFGL_WANT(ret, name, args) \ - qf##name = vid.get_proc_address (#name, false); + qf##name = vid.vid_internal->get_proc_address (#name, false); #define QFGL_NEED(ret, name, args) \ - qf##name = vid.get_proc_address (#name, true); + qf##name = vid.vid_internal->get_proc_address (#name, true); #include "QF/GL/qf_funcs_list.h" #undef QFGL_NEED #undef QFGL_WANT @@ -135,6 +136,6 @@ void * QFGL_ExtensionAddress (const char *name) { if (name) - return vid.get_proc_address (name, false); + return vid.vid_internal->get_proc_address (name, false); return NULL; } diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index 9fd3a9c0c..2bc60bdd4 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -58,6 +58,7 @@ #include "mod_internal.h" #include "r_internal.h" +#include "vid_internal.h" mat4_t glsl_projection; mat4_t glsl_view; @@ -304,13 +305,13 @@ glsl_R_TimeRefresh_f (void) double start, stop, time; int i; - vid.end_rendering (); + vid.vid_internal->end_rendering (); start = Sys_DoubleTime (); for (i = 0; i < 128; i++) { r_refdef.viewangles[1] = i * (360.0 / 128.0); glsl_R_RenderView (); - vid.end_rendering (); + vid.vid_internal->end_rendering (); } stop = Sys_DoubleTime (); diff --git a/libs/video/renderer/glsl/glsl_screen.c b/libs/video/renderer/glsl/glsl_screen.c index eab755325..ecdda6ec8 100644 --- a/libs/video/renderer/glsl/glsl_screen.c +++ b/libs/video/renderer/glsl/glsl_screen.c @@ -60,6 +60,7 @@ #include "QF/GLSL/qf_vid.h" #include "r_internal.h" +#include "vid_internal.h" /* Unknown renamed to GLErr_Unknown to solve conflict with winioctl.h */ static unsigned int GLErr_InvalidEnum; @@ -165,7 +166,7 @@ glsl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, if (begun) { begun = 0; - vid.end_rendering (); + vid.vid_internal->end_rendering (); } vr_data.realtime = realtime; diff --git a/libs/video/renderer/glsl/qfglsl.c b/libs/video/renderer/glsl/qfglsl.c index af3a2f839..b4fd25662 100644 --- a/libs/video/renderer/glsl/qfglsl.c +++ b/libs/video/renderer/glsl/qfglsl.c @@ -60,6 +60,7 @@ #include "QF/GLSL/funcs.h" #include "r_internal.h" +#include "vid_internal.h" // First we need to get all the function pointers declared. #define QFGL_WANT(ret, name, args) \ @@ -74,9 +75,9 @@ qboolean EGLF_FindFunctions (void) { #define QFGL_WANT(ret, name, args) \ - qfe##name = vid.get_proc_address (#name, false); + qfe##name = vid.vid_internal->get_proc_address (#name, false); #define QFGL_NEED(ret, name, args) \ - qfe##name = vid.get_proc_address (#name, true); + qfe##name = vid.vid_internal->get_proc_address (#name, true); #include "QF/GLSL/qf_funcs_list.h" #undef QFGL_NEED #undef QFGL_WANT diff --git a/libs/video/renderer/r_init.c b/libs/video/renderer/r_init.c index d4a7e91cd..98acc39ad 100644 --- a/libs/video/renderer/r_init.c +++ b/libs/video/renderer/r_init.c @@ -46,6 +46,7 @@ #include "QF/plugin/general.h" #include "r_internal.h" +#include "vid_internal.h" cvar_t *vidrend_plugin; plugin_t *vidrendmodule = NULL; @@ -76,8 +77,8 @@ R_LoadModule (void (*load_gl)(void), void (*set_palette) (const byte *palette)) r_funcs = vidrendmodule->functions->vid_render; mod_funcs = r_funcs->model_funcs; r_data = vidrendmodule->data->vid_render; - r_data->vid->load_gl = load_gl; - r_data->vid->set_palette = set_palette; + r_data->vid->vid_internal->load_gl = load_gl; + r_data->vid->vid_internal->set_palette = set_palette; vidrendmodule->functions->general->p_Init (); } diff --git a/libs/video/renderer/sw/d_init.c b/libs/video/renderer/sw/d_init.c index 67e48e71b..00fb21a89 100644 --- a/libs/video/renderer/sw/d_init.c +++ b/libs/video/renderer/sw/d_init.c @@ -56,9 +56,9 @@ D_Init (void) r_worldpolysbacktofront = false; r_recursiveaffinetriangles = true; - vr_data.vid->surf_cache_size = D_SurfaceCacheForRes; - vr_data.vid->flush_caches = D_FlushCaches; - vr_data.vid->init_caches = D_InitCaches; + vr_data.vid->vid_internal->surf_cache_size = D_SurfaceCacheForRes; + vr_data.vid->vid_internal->flush_caches = D_FlushCaches; + vr_data.vid->vid_internal->init_caches = D_InitCaches; VID_InitBuffers (); } diff --git a/libs/video/renderer/sw/draw.c b/libs/video/renderer/sw/draw.c index e3728af66..775888a21 100644 --- a/libs/video/renderer/sw/draw.c +++ b/libs/video/renderer/sw/draw.c @@ -825,5 +825,5 @@ Draw_BlendScreen (quat_t color) newpal[2] = vid.gammatable[b]; newpal += 3; } - vid.set_palette (pal); + vid.vid_internal->set_palette (pal); } diff --git a/libs/video/renderer/sw32/d_init.c b/libs/video/renderer/sw32/d_init.c index ccb5f7392..e786cf32b 100644 --- a/libs/video/renderer/sw32/d_init.c +++ b/libs/video/renderer/sw32/d_init.c @@ -66,9 +66,9 @@ sw32_D_Init (void) sw32_d_zitable[i] = (65536.0 * 65536.0 / (double) i); } - vr_data.vid->surf_cache_size = sw32_D_SurfaceCacheForRes; - vr_data.vid->flush_caches = sw32_D_FlushCaches; - vr_data.vid->init_caches = sw32_D_InitCaches; + vr_data.vid->vid_internal->surf_cache_size = sw32_D_SurfaceCacheForRes; + vr_data.vid->vid_internal->flush_caches = sw32_D_FlushCaches; + vr_data.vid->vid_internal->init_caches = sw32_D_InitCaches; VID_InitBuffers (); VID_MakeColormaps(); diff --git a/libs/video/renderer/sw32/draw.c b/libs/video/renderer/sw32/draw.c index a420c8ac0..13454c437 100644 --- a/libs/video/renderer/sw32/draw.c +++ b/libs/video/renderer/sw32/draw.c @@ -1299,7 +1299,7 @@ sw32_Draw_BlendScreen (quat_t color) newpal[2] = vid.gammatable[b]; newpal += 3; } - vid.set_palette (pal); + vid.vid_internal->set_palette (pal); } break; case 2: diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 42f5df1dc..91f4178b5 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -38,6 +38,7 @@ #include "mod_internal.h" #include "r_internal.h" +#include "vid_internal.h" #include "gl/namehack.h" @@ -126,9 +127,9 @@ vid_render_funcs_t gl_vid_render_funcs = { static void gl_vid_render_init (void) { - vr_data.vid->set_palette = GL_SetPalette; - vr_data.vid->init_gl = GL_Init_Common; - vr_data.vid->load_gl (); + vr_data.vid->vid_internal->set_palette = GL_SetPalette; + vr_data.vid->vid_internal->init_gl = GL_Init_Common; + vr_data.vid->vid_internal->load_gl (); vr_funcs = &gl_vid_render_funcs; m_funcs = &model_funcs; } diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index f162231d1..d1f380ae5 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -38,6 +38,7 @@ #include "mod_internal.h" #include "r_internal.h" +#include "vid_internal.h" #include "glsl/namehack.h" @@ -126,9 +127,9 @@ vid_render_funcs_t glsl_vid_render_funcs = { static void glsl_vid_render_init (void) { - vr_data.vid->set_palette = GLSL_SetPalette; - vr_data.vid->init_gl = GLSL_Init_Common; - vr_data.vid->load_gl (); + vr_data.vid->vid_internal->set_palette = GLSL_SetPalette; + vr_data.vid->vid_internal->init_gl = GLSL_Init_Common; + vr_data.vid->vid_internal->load_gl (); vr_funcs = &glsl_vid_render_funcs; m_funcs = &model_funcs; } diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index ec5ee4ea3..c71264fcb 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -38,6 +38,7 @@ #include "mod_internal.h" #include "r_internal.h" +#include "vid_internal.h" #include "vulkan/namehack.h" @@ -134,9 +135,9 @@ set_palette (const byte *palette) static void vulkan_vid_render_init (void) { - vr_data.vid->set_palette = set_palette; - vr_data.vid->init_gl = Vulkan_Init_Common; - vr_data.vid->load_gl (); + vr_data.vid->vid_internal->set_palette = set_palette; + vr_data.vid->vid_internal->init_gl = Vulkan_Init_Common; + vr_data.vid->vid_internal->load_gl (); vr_funcs = &vulkan_vid_render_funcs; m_funcs = &model_funcs; } diff --git a/libs/video/targets/vid.c b/libs/video/targets/vid.c index d7aeb3b2d..651101539 100644 --- a/libs/video/targets/vid.c +++ b/libs/video/targets/vid.c @@ -214,7 +214,7 @@ VID_UpdateGamma (cvar_t *vid_gamma) VID_BuildGammaTable (gamma); for (i = 0; i < 256 * 3; i++) viddef.palette[i] = viddef.gammatable[viddef.basepal[i]]; - viddef.set_palette (viddef.palette); // update with the new palette + viddef.vid_internal->set_palette (viddef.palette); // update with the new palette } } @@ -256,8 +256,9 @@ VID_InitBuffers (void) // Calculate the sizes we want first buffersize = viddef.rowbytes * viddef.height; zbuffersize = viddef.width * viddef.height * sizeof (*viddef.zbuffer); - if (viddef.surf_cache_size) - cachesize = viddef.surf_cache_size (viddef.width, viddef.height); + if (viddef.vid_internal->surf_cache_size) + cachesize = viddef.vid_internal->surf_cache_size (viddef.width, + viddef.height); // Free the old z-buffer if (viddef.zbuffer) { @@ -266,13 +267,13 @@ VID_InitBuffers (void) } // Free the old surface cache if (viddef.surfcache) { - if (viddef.flush_caches) - viddef.flush_caches (); + if (viddef.vid_internal->flush_caches) + viddef.vid_internal->flush_caches (); free (viddef.surfcache); viddef.surfcache = NULL; } - if (viddef.do_screen_buffer) { - viddef.do_screen_buffer (); + if (viddef.vid_internal->do_screen_buffer) { + viddef.vid_internal->do_screen_buffer (); } else { // Free the old screen buffer if (viddef.buffer) { @@ -302,13 +303,13 @@ VID_InitBuffers (void) Sys_Error ("Not enough memory for video mode"); } - if (viddef.init_caches) - viddef.init_caches (viddef.surfcache, cachesize); + if (viddef.vid_internal->init_caches) + viddef.vid_internal->init_caches (viddef.surfcache, cachesize); } void VID_ClearMemory (void) { - if (viddef.flush_caches) - viddef.flush_caches (); + if (viddef.vid_internal->flush_caches) + viddef.vid_internal->flush_caches (); } diff --git a/libs/video/targets/vid_sdl.c b/libs/video/targets/vid_sdl.c index b32efbee1..e48baea51 100644 --- a/libs/video/targets/vid_sdl.c +++ b/libs/video/targets/vid_sdl.c @@ -78,6 +78,8 @@ SDL_Surface *screen = NULL; # endif #endif +static vid_internal_t vid_internal; + static void (*set_vid_mode) (Uint32 flags); static void (GLAPIENTRY *qfglFinish) (void); @@ -157,7 +159,7 @@ sdlgl_set_vid_mode (Uint32 flags) success: viddef.numpages = 2; - viddef.init_gl (); + viddef.vid_internal->init_gl (); } static void @@ -170,8 +172,8 @@ sdlgl_end_rendering (void) static void sdl_load_gl (void) { - viddef.get_proc_address = QFGL_ProcAddress; - viddef.end_rendering = sdlgl_end_rendering; + viddef.vid_internal->get_proc_address = QFGL_ProcAddress; + viddef.vid_internal->end_rendering = sdlgl_end_rendering; set_vid_mode = sdlgl_set_vid_mode; if (SDL_GL_LoadLibrary (gl_driver->string) != 0) @@ -220,7 +222,7 @@ sdl_set_vid_mode (Uint32 flags) // now know everything we need to know about the buffer VGA_width = viddef.width; VGA_height = viddef.height; - viddef.do_screen_buffer = do_screen_buffer; + viddef.vid_internal->do_screen_buffer = do_screen_buffer; VGA_pagebase = viddef.buffer = screen->pixels; VGA_rowbytes = viddef.rowbytes = screen->pitch; viddef.conbuffer = viddef.buffer; @@ -235,6 +237,8 @@ VID_Init (byte *palette, byte *colormap) { Uint32 flags; + viddef.vid_internal = &vid_internal; + set_vid_mode = sdl_set_vid_mode; // Load the SDL library @@ -269,7 +273,7 @@ VID_Init (byte *palette, byte *colormap) VID_SDL_GammaCheck (); VID_InitGamma (palette); - viddef.set_palette (viddef.palette); + viddef.vid_internal->set_palette (viddef.palette); viddef.initialized = true; diff --git a/libs/video/targets/vid_x11.c b/libs/video/targets/vid_x11.c index 1050d6adb..905620080 100644 --- a/libs/video/targets/vid_x11.c +++ b/libs/video/targets/vid_x11.c @@ -79,6 +79,7 @@ #include "dga_check.h" #include "vid_internal.h" +static vid_internal_t vid_internal; int XShmGetEventBase (Display *x); // for broken X11 headers static GC x_gc; @@ -209,7 +210,7 @@ glx_create_context (void) XSync (x_disp, 0); ctx = qfglXCreateContext (x_disp, x_visinfo, NULL, True); qfglXMakeCurrent (x_disp, x_win, ctx); - viddef.init_gl (); + viddef.vid_internal->init_gl (); } static void @@ -227,8 +228,8 @@ glx_load_gl (void) choose_visual = glx_choose_visual; create_context = glx_create_context; - viddef.get_proc_address = QFGL_ProcAddress; - viddef.end_rendering = glx_end_rendering; + viddef.vid_internal->get_proc_address = QFGL_ProcAddress; + viddef.vid_internal->end_rendering = glx_end_rendering; #ifdef RTLD_GLOBAL flags |= RTLD_GLOBAL; @@ -623,7 +624,7 @@ x11_create_context (void) x_shmeventtype = XShmGetEventBase (x_disp) + ShmCompletion; } - viddef.do_screen_buffer = x11_init_buffers; + viddef.vid_internal->do_screen_buffer = x11_init_buffers; VID_InitBuffers (); // XSynchronize (x_disp, False); @@ -666,6 +667,8 @@ VID_SetPalette (const byte *palette) void VID_Init (byte *palette, byte *colormap) { + viddef.vid_internal = &vid_internal; + choose_visual = x11_choose_visual; create_context = x11_create_context; @@ -686,7 +689,7 @@ VID_Init (byte *palette, byte *colormap) create_context (); VID_InitGamma (palette); - viddef.set_palette (viddef.palette); + viddef.vid_internal->set_palette (viddef.palette); Sys_MaskPrintf (SYS_VID, "Video mode %dx%d initialized.\n", viddef.width, viddef.height); From cb10175824d9c829b95b92cef8956c3e7d2a6cd2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 8 Jul 2019 14:02:24 +0900 Subject: [PATCH 011/435] Pass vid_internal to R_LoadModule This fixes the segfault and pushes things very much in the desired direction of proper system independence for rendering and presentation separation (though things were headed in the right direction before). --- include/QF/render.h | 4 ++-- libs/video/renderer/r_init.c | 5 ++--- libs/video/targets/vid_sdl.c | 5 +++-- libs/video/targets/vid_x11.c | 5 +++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/QF/render.h b/include/QF/render.h index cc08c3800..03cebfa1c 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -172,8 +172,8 @@ extern struct texture_s *r_notexture_mip; extern entity_t r_worldentity; void R_Init (void); -void R_LoadModule (void (*load_gl)(void), - void (*set_palette) (const byte *palette)); +struct vid_internal_s; +void R_LoadModule (struct vid_internal_s *vid_internal); struct progs_s; void R_Progs_Init (struct progs_s *pr); diff --git a/libs/video/renderer/r_init.c b/libs/video/renderer/r_init.c index 98acc39ad..330d0d76d 100644 --- a/libs/video/renderer/r_init.c +++ b/libs/video/renderer/r_init.c @@ -64,7 +64,7 @@ static U void (*const r_progs_init)(struct progs_s *) = R_Progs_Init; #undef U VISIBLE void -R_LoadModule (void (*load_gl)(void), void (*set_palette) (const byte *palette)) +R_LoadModule (vid_internal_t *vid_internal) { PI_RegisterPlugins (vidrend_plugin_list); vidrend_plugin = Cvar_Get ("vid_render", VID_RENDER_DEFAULT, CVAR_ROM, 0, @@ -77,8 +77,7 @@ R_LoadModule (void (*load_gl)(void), void (*set_palette) (const byte *palette)) r_funcs = vidrendmodule->functions->vid_render; mod_funcs = r_funcs->model_funcs; r_data = vidrendmodule->data->vid_render; - r_data->vid->vid_internal->load_gl = load_gl; - r_data->vid->vid_internal->set_palette = set_palette; + r_data->vid->vid_internal = vid_internal; vidrendmodule->functions->general->p_Init (); } diff --git a/libs/video/targets/vid_sdl.c b/libs/video/targets/vid_sdl.c index e48baea51..514b8020e 100644 --- a/libs/video/targets/vid_sdl.c +++ b/libs/video/targets/vid_sdl.c @@ -237,7 +237,8 @@ VID_Init (byte *palette, byte *colormap) { Uint32 flags; - viddef.vid_internal = &vid_internal; + vid_internal.set_palette = VID_SetPalette; + vid_internal.load_gl = sdl_load_gl; set_vid_mode = sdl_set_vid_mode; @@ -245,7 +246,7 @@ VID_Init (byte *palette, byte *colormap) if (SDL_Init (SDL_INIT_VIDEO) < 0) Sys_Error ("VID: Couldn't load SDL: %s", SDL_GetError ()); - R_LoadModule (sdl_load_gl, VID_SetPalette); + R_LoadModule (&vid_internal); viddef.numpages = 1; viddef.colormap8 = colormap; diff --git a/libs/video/targets/vid_x11.c b/libs/video/targets/vid_x11.c index 905620080..bc4b4b6dc 100644 --- a/libs/video/targets/vid_x11.c +++ b/libs/video/targets/vid_x11.c @@ -667,12 +667,13 @@ VID_SetPalette (const byte *palette) void VID_Init (byte *palette, byte *colormap) { - viddef.vid_internal = &vid_internal; + vid_internal.load_gl = glx_load_gl; + vid_internal.set_palette = VID_SetPalette; choose_visual = x11_choose_visual; create_context = x11_create_context; - R_LoadModule (glx_load_gl, VID_SetPalette); + R_LoadModule (&vid_internal); viddef.numpages = 2; viddef.colormap8 = colormap; From 53a62e4d623828d199d12d641daabd3e42fb1341 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 00:44:48 +0900 Subject: [PATCH 012/435] Add checks for some dlopen flags Checks aren't used yet, though. --- config.d/library_functions.m4 | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/config.d/library_functions.m4 b/config.d/library_functions.m4 index 66ff31edc..ba76c574e 100644 --- a/config.d/library_functions.m4 +++ b/config.d/library_functions.m4 @@ -35,6 +35,25 @@ if test "x$ac_cv_func_dlopen" != "xyes"; then fi AC_SUBST(DL_LIBS) +if test "x$DL_LIBS" != "x"; then +AC_MSG_CHECKING([for RTLD_NOW]) +AC_TRY_COMPILE( + [#include ], + [int foo = RTLD_NOW], + AC_DEFINE(HAVE_RTLD_NOW, 1, [Define if you have RTLD_NOW.]) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no) +) +AC_MSG_CHECKING([for RTLD_DEEPBIND]) +AC_TRY_COMPILE( + [#include ], + [int foo = RTLD_DEEPBIND], + AC_DEFINE(HAVE_RTLD_DEEPBIND, 1, [Define if you have RTLD_DEEPBIND.]) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no) +) +fi + dnl Checks for stricmp/strcasecmp #AC_CHECK_FUNC(strcasecmp, # , From 8ee06d75a9547a143c7054c1fb615a38a44c0f9b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 01:00:47 +0900 Subject: [PATCH 013/435] Separate render and presentation initialization This paves the way for clean initialization of the Vulkan renderer, and very much cleans up the older renderer initialization code as gl and sw are no longer intertwined. --- config.d/vulkan.m4 | 16 +- configure.ac | 2 +- include/QF/Vulkan/cvars.h | 1 - include/QF/Vulkan/funclist.h | 11 + include/QF/Vulkan/funcs.h | 9 - include/QF/Vulkan/init.h | 1 - include/context_sdl.h | 12 + include/context_x11.h | 9 + include/r_cvar.h | 1 - include/vid_gl.h | 20 + include/vid_internal.h | 13 +- include/vid_sw.h | 18 + include/vid_vulkan.h | 29 + libs/video/renderer/gl/gl_rmisc.c | 8 +- libs/video/renderer/gl/gl_screen.c | 6 +- libs/video/renderer/gl/qfgl_ext.c | 8 +- libs/video/renderer/glsl/glsl_main.c | 6 +- libs/video/renderer/glsl/glsl_screen.c | 4 +- libs/video/renderer/glsl/qfglsl.c | 6 +- libs/video/renderer/sw/screen.c | 3 +- libs/video/renderer/sw/sw_rmisc.c | 3 +- libs/video/renderer/sw32/screen.c | 3 +- libs/video/renderer/sw32/sw32_rmisc.c | 4 +- libs/video/renderer/vid_render_gl.c | 24 +- libs/video/renderer/vid_render_glsl.c | 23 +- libs/video/renderer/vid_render_sw.c | 24 +- libs/video/renderer/vid_render_sw32.c | 22 + libs/video/renderer/vid_render_vulkan.c | 9 +- libs/video/renderer/vulkan/Makefile.am | 3 +- libs/video/renderer/vulkan/init.c | 22 +- libs/video/renderer/vulkan/vulkan_funcs.c | 6 - .../video/renderer/vulkan/vulkan_vid_common.c | 39 +- libs/video/targets/Makefile.am | 14 +- libs/video/targets/context_sdl.c | 9 +- libs/video/targets/vid_sdl.c | 244 +------ libs/video/targets/vid_sdl_gl.c | 178 +++++ libs/video/targets/vid_sdl_sw.c | 183 +++++ libs/video/targets/vid_x11.c | 643 +----------------- libs/video/targets/vid_x11_gl.c | 209 ++++++ libs/video/targets/vid_x11_sw.c | 542 +++++++++++++++ libs/video/targets/vid_x11_vulkan.c | 169 +++++ 41 files changed, 1576 insertions(+), 980 deletions(-) delete mode 100644 include/QF/Vulkan/funcs.h create mode 100644 include/vid_gl.h create mode 100644 include/vid_sw.h create mode 100644 include/vid_vulkan.h delete mode 100644 libs/video/renderer/vulkan/vulkan_funcs.c create mode 100644 libs/video/targets/vid_sdl_gl.c create mode 100644 libs/video/targets/vid_sdl_sw.c create mode 100644 libs/video/targets/vid_x11_gl.c create mode 100644 libs/video/targets/vid_x11_sw.c create mode 100644 libs/video/targets/vid_x11_vulkan.c diff --git a/config.d/vulkan.m4 b/config.d/vulkan.m4 index c82900f58..4c9df43f4 100644 --- a/config.d/vulkan.m4 +++ b/config.d/vulkan.m4 @@ -9,16 +9,12 @@ if test "x$HAVE_VULKAN" != xno; then LDFLAGS="$LDFLAGS -L$VULKAN_SDK/lib" glslangvalidator="$VULKAN_SDK/bin/glslangValidator" ], [glslangvalidator="glslangValidator"]) - AC_CHECK_HEADER( - [vulkan/vulkan.h], - dnl Make sure the library "works" - [AC_CHECK_LIB([vulkan], [vkCreateInstance], - [AC_DEFINE([HAVE_VULKAN], [1], [Define if yhou have the Vulkan libs]) - VULKAN_LIBS=-lvulkan], - [AC_MSG_RESULT(no)]) - ], - [AC_MSG_RESULT(no)] - ) + AC_CHECK_HEADER([vulkan/vulkan.h], [HAVE_VULKAN=yes], [HAVE_VULKAN=no]) CPPFLAGS="$save_CPPFLAGS" fi +if test "x$HAVE_VULKAN" = xyes; then + AC_DEFINE([HAVE_VULKAN], [1], [Define if yhou have the Vulkan libs]) +fi AC_SUBST(VULKAN_LIBS) + +AM_CONDITIONAL(X11_VULKAN, test "x$HAVE_VULKAN" = "xyes") diff --git a/configure.ac b/configure.ac index aaf6492ea..fe398b273 100644 --- a/configure.ac +++ b/configure.ac @@ -63,8 +63,8 @@ m4_include(config.d/compression.m4) m4_include(config.d/mgl.m4) m4_include(config.d/fbdev.m4) m4_include(config.d/svga.m4) -m4_include(config.d/x11.m4) m4_include(config.d/vulkan.m4) +m4_include(config.d/x11.m4) m4_include(config.d/sdl.m4) m4_include(config.d/curses.m4) diff --git a/include/QF/Vulkan/cvars.h b/include/QF/Vulkan/cvars.h index 9f318b8f0..b6110e353 100644 --- a/include/QF/Vulkan/cvars.h +++ b/include/QF/Vulkan/cvars.h @@ -1,7 +1,6 @@ #ifndef __QF_Vulkan_cvars_h #define __QF_Vulkan_cvars_h -extern struct cvar_s *vulkan_library_name; extern struct cvar_s *vulkan_use_validation; #endif//__QF_Vulkan_cvars_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 2b755889e..79af14277 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -21,6 +21,16 @@ GLOBAL_LEVEL_VULKAN_FUNCTION (vkCreateInstance) #define INSTANCE_LEVEL_VULKAN_FUNCTION(function) #endif +#if defined(VK_USE_PLATFORM_XLIB_KHR) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceXlibPresentationSupportKHR) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkCreateXlibSurfaceKHR) +#elif defined(VK_USE_PLATFORM_WIN32_KHR) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceWin32PresentationSupportKHR) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkCreateWin32SurfaceKHR) +#elif defined(VK_USE_PLATFORM_XCB_KHR) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceXcbPresentationSupportKHR) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkCreateXcbSurfaceKHR) +#else INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumeratePhysicalDevices) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceFeatures) @@ -31,6 +41,7 @@ INSTANCE_LEVEL_VULKAN_FUNCTION (vkDestroyInstance) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceLayerProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceExtensionProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceMemoryProperties) +#endif #undef INSTANCE_LEVEL_VULKAN_FUNCTION diff --git a/include/QF/Vulkan/funcs.h b/include/QF/Vulkan/funcs.h deleted file mode 100644 index 975f5485b..000000000 --- a/include/QF/Vulkan/funcs.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __QF_Vulkan_funcs_h -#define __QF_Vulkan_funcs_h - -#define EXPORTED_VULKAN_FUNCTION(fname) extern PFN_##fname fname; -#define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) extern PFN_##fname fname; - -#include "QF/Vulkan/funclist.h" - -#endif//__QF_Vulkan_funcs_h diff --git a/include/QF/Vulkan/init.h b/include/QF/Vulkan/init.h index 4a97b82f8..85efb44e1 100644 --- a/include/QF/Vulkan/init.h +++ b/include/QF/Vulkan/init.h @@ -29,7 +29,6 @@ #include #include "QF/qtypes.h" -#include "QF/Vulkan/funcs.h" typedef struct { VkDevice device; diff --git a/include/context_sdl.h b/include/context_sdl.h index b097587f1..f6f1dbbe7 100644 --- a/include/context_sdl.h +++ b/include/context_sdl.h @@ -30,7 +30,19 @@ #ifndef __context_sdl_h_ #define __context_sdl_h_ +#include + +extern SDL_Surface *sdl_screen; + void VID_SDL_GammaCheck (void); void SDL_Init_Cvars (void); +struct gl_ctx_s *SDL_GL_Context (void); +void SDL_GL_Init_Cvars (void); + +struct sw_ctx_s *SDL_SW_Context (void); +void SDL_SW_Init_Cvars (void); + +extern uint32_t sdl_flags; + #endif // __context_sdl_h_ diff --git a/include/context_x11.h b/include/context_x11.h index b513e587a..884fafe9e 100644 --- a/include/context_x11.h +++ b/include/context_x11.h @@ -77,4 +77,13 @@ void X11_SaveMouseAcceleration (void); void X11_RemoveMouseAcceleration (void); void X11_RestoreMouseAcceleration (void); +struct gl_ctx_s *X11_GL_Context (void); +void X11_GL_Init_Cvars (void); + +struct sw_ctx_s *X11_SW_Context (void); +void X11_SW_Init_Cvars (void); + +struct vulkan_ctx_s *X11_Vulkan_Context (void); +void X11_Vulkan_Init_Cvars (void); + #endif // __context_x11_h_ diff --git a/include/r_cvar.h b/include/r_cvar.h index 8383f4705..e8a85a679 100644 --- a/include/r_cvar.h +++ b/include/r_cvar.h @@ -16,7 +16,6 @@ extern quat_t crosshair_color; extern struct cvar_s *d_mipcap; extern struct cvar_s *d_mipscale; -extern struct cvar_s *gl_driver; extern struct cvar_s *gl_affinemodels; extern struct cvar_s *gl_anisotropy; extern struct cvar_s *gl_clear; diff --git a/include/vid_gl.h b/include/vid_gl.h new file mode 100644 index 000000000..2561af575 --- /dev/null +++ b/include/vid_gl.h @@ -0,0 +1,20 @@ +#ifndef __vid_gl_h +#define __vid_gl_h + +// GLXContext is a pointer to opaque data +typedef struct __GLXcontextRec *GLXContext; + +typedef struct gl_ctx_s { + GLXContext context; + void (*load_gl) (void); + void (*choose_visual) (struct gl_ctx_s *ctx); + void (*create_context) (struct gl_ctx_s *ctx); + void (*init_gl) (void); + void *(*get_proc_address) (const char *name, qboolean crit); + void (*end_rendering) (void); +} gl_ctx_t; + +extern gl_ctx_t *gl_ctx; +extern gl_ctx_t *glsl_ctx; + +#endif//__vid_gl_h diff --git a/include/vid_internal.h b/include/vid_internal.h index fc1538202..e922508a4 100644 --- a/include/vid_internal.h +++ b/include/vid_internal.h @@ -11,11 +11,12 @@ typedef struct vid_internal_s { void (*do_screen_buffer) (void); void (*set_palette) (const byte *palette); - // gl stuff - void (*load_gl) (void); - void (*init_gl) (void); - void *(*get_proc_address) (const char *name, qboolean crit); - void (*end_rendering) (void); + void (*choose_visual) (void); + void (*create_context) (void); + + struct gl_ctx_s *(*gl_context) (void); + struct sw_ctx_s *(*sw_context) (void); + struct vulkan_ctx_s *(*vulkan_context) (void); } vid_internal_t; extern struct cvar_s *vid_fullscreen; @@ -30,11 +31,9 @@ void VID_InitGamma (unsigned char *); qboolean VID_SetGamma (double); void VID_UpdateGamma (struct cvar_s *); -void VID_Update (vrect_t *rects); void VID_LockBuffer (void); void VID_UnlockBuffer (void); void VID_InitBuffers (void); void VID_MakeColormaps (void); - #endif//__vid_internal_h diff --git a/include/vid_sw.h b/include/vid_sw.h new file mode 100644 index 000000000..2a5ab20a5 --- /dev/null +++ b/include/vid_sw.h @@ -0,0 +1,18 @@ +#ifndef __vid_sw_h +#define __vid_sw_h + +// GLXContext is a pointer to opaque data +typedef struct __GLXcontextRec *GLXContext; +struct vrect_s; +typedef struct sw_ctx_s { + GLXContext context; + void (*choose_visual) (struct sw_ctx_s *ctx); + void (*create_context) (struct sw_ctx_s *ctx); + void (*set_palette) (const byte *palette); + void (*update) (struct vrect_s *rects); +} sw_ctx_t; + +extern sw_ctx_t *sw_ctx; +extern sw_ctx_t *sw32_ctx; + +#endif//__vid_sw_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h new file mode 100644 index 000000000..627269cdb --- /dev/null +++ b/include/vid_vulkan.h @@ -0,0 +1,29 @@ +#ifndef __vid_vulkan_h +#define __vid_vulkan_h + +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + +typedef struct vulkan_ctx_s { + void (*load_vulkan) (struct vulkan_ctx_s *ctx); + void (*unload_vulkan) (struct vulkan_ctx_s *ctx); + void (*init_vulkan) (void); + + const char * const *required_extensions; + struct vulkan_presentation_s *presentation; + int (*get_presentation_support) (struct vulkan_ctx_s *ctx, + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex); + VkSurfaceKHR (*create_surface) (struct vulkan_ctx_s *ctx); + VkInstance instance; + VkPhysicalDevice physicalDevice; +#define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; +#define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; +#include "QF/Vulkan/funclist.h" +} vulkan_ctx_t; + +extern vulkan_ctx_t *vulkan_ctx; + +#endif//__vid_vulkan_h diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index e054e37bf..a47e6ba42 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -64,7 +64,7 @@ #include "mod_internal.h" #include "r_internal.h" #include "varrays.h" -#include "vid_internal.h" +#include "vid_gl.h" /* R_Envmap_f @@ -122,7 +122,7 @@ R_Envmap_f (void) gl_envmap = false; qfglDrawBuffer (GL_BACK); qfglReadBuffer (GL_BACK); - vid.vid_internal->end_rendering (); + gl_ctx->end_rendering (); } void @@ -250,13 +250,13 @@ gl_R_TimeRefresh_f (void) double start, stop, time; int i; - vid.vid_internal->end_rendering (); + gl_ctx->end_rendering (); start = Sys_DoubleTime (); for (i = 0; i < 128; i++) { r_refdef.viewangles[1] = i * (360.0 / 128.0); gl_R_RenderView (); - vid.vid_internal->end_rendering (); + gl_ctx->end_rendering (); } stop = Sys_DoubleTime (); diff --git a/libs/video/renderer/gl/gl_screen.c b/libs/video/renderer/gl/gl_screen.c index 73674e70c..fbe47106f 100644 --- a/libs/video/renderer/gl/gl_screen.c +++ b/libs/video/renderer/gl/gl_screen.c @@ -59,7 +59,7 @@ #include "compat.h" #include "r_internal.h" #include "sbar.h" -#include "vid_internal.h" +#include "vid_gl.h" /* SCREEN SHOTS */ @@ -207,7 +207,7 @@ gl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) return; if (begun) - vid.vid_internal->end_rendering (); + gl_ctx->end_rendering (); vr_data.realtime = realtime; @@ -264,7 +264,7 @@ gl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) qfglFlush (); if (gl_finish->int_val) { - vid.vid_internal->end_rendering (); + gl_ctx->end_rendering (); begun = 0; } } diff --git a/libs/video/renderer/gl/qfgl_ext.c b/libs/video/renderer/gl/qfgl_ext.c index 41fe1f52b..f012726de 100644 --- a/libs/video/renderer/gl/qfgl_ext.c +++ b/libs/video/renderer/gl/qfgl_ext.c @@ -61,7 +61,7 @@ #include "QF/GL/funcs.h" #include "r_internal.h" -#include "vid_internal.h" +#include "vid_gl.h" // First we need to get all the function pointers declared. #define QFGL_WANT(ret, name, args) \ @@ -76,9 +76,9 @@ qboolean GLF_FindFunctions (void) { #define QFGL_WANT(ret, name, args) \ - qf##name = vid.vid_internal->get_proc_address (#name, false); + qf##name = gl_ctx->get_proc_address (#name, false); #define QFGL_NEED(ret, name, args) \ - qf##name = vid.vid_internal->get_proc_address (#name, true); + qf##name = gl_ctx->get_proc_address (#name, true); #include "QF/GL/qf_funcs_list.h" #undef QFGL_NEED #undef QFGL_WANT @@ -136,6 +136,6 @@ void * QFGL_ExtensionAddress (const char *name) { if (name) - return vid.vid_internal->get_proc_address (name, false); + return gl_ctx->get_proc_address (name, false); return NULL; } diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index 2bc60bdd4..32688b2ae 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -58,7 +58,7 @@ #include "mod_internal.h" #include "r_internal.h" -#include "vid_internal.h" +#include "vid_gl.h" mat4_t glsl_projection; mat4_t glsl_view; @@ -305,13 +305,13 @@ glsl_R_TimeRefresh_f (void) double start, stop, time; int i; - vid.vid_internal->end_rendering (); + glsl_ctx->end_rendering (); start = Sys_DoubleTime (); for (i = 0; i < 128; i++) { r_refdef.viewangles[1] = i * (360.0 / 128.0); glsl_R_RenderView (); - vid.vid_internal->end_rendering (); + glsl_ctx->end_rendering (); } stop = Sys_DoubleTime (); diff --git a/libs/video/renderer/glsl/glsl_screen.c b/libs/video/renderer/glsl/glsl_screen.c index ecdda6ec8..89276999d 100644 --- a/libs/video/renderer/glsl/glsl_screen.c +++ b/libs/video/renderer/glsl/glsl_screen.c @@ -60,7 +60,7 @@ #include "QF/GLSL/qf_vid.h" #include "r_internal.h" -#include "vid_internal.h" +#include "vid_gl.h" /* Unknown renamed to GLErr_Unknown to solve conflict with winioctl.h */ static unsigned int GLErr_InvalidEnum; @@ -166,7 +166,7 @@ glsl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, if (begun) { begun = 0; - vid.vid_internal->end_rendering (); + glsl_ctx->end_rendering (); } vr_data.realtime = realtime; diff --git a/libs/video/renderer/glsl/qfglsl.c b/libs/video/renderer/glsl/qfglsl.c index b4fd25662..0e48e9354 100644 --- a/libs/video/renderer/glsl/qfglsl.c +++ b/libs/video/renderer/glsl/qfglsl.c @@ -60,7 +60,7 @@ #include "QF/GLSL/funcs.h" #include "r_internal.h" -#include "vid_internal.h" +#include "vid_gl.h" // First we need to get all the function pointers declared. #define QFGL_WANT(ret, name, args) \ @@ -75,9 +75,9 @@ qboolean EGLF_FindFunctions (void) { #define QFGL_WANT(ret, name, args) \ - qfe##name = vid.vid_internal->get_proc_address (#name, false); + qfe##name = glsl_ctx->get_proc_address (#name, false); #define QFGL_NEED(ret, name, args) \ - qfe##name = vid.vid_internal->get_proc_address (#name, true); + qfe##name = glsl_ctx->get_proc_address (#name, true); #include "QF/GLSL/qf_funcs_list.h" #undef QFGL_NEED #undef QFGL_WANT diff --git a/libs/video/renderer/sw/screen.c b/libs/video/renderer/sw/screen.c index d425f6549..5b69e7a0d 100644 --- a/libs/video/renderer/sw/screen.c +++ b/libs/video/renderer/sw/screen.c @@ -51,6 +51,7 @@ #include "compat.h" #include "r_internal.h" #include "vid_internal.h" +#include "vid_sw.h" /* SCREEN SHOTS */ @@ -263,5 +264,5 @@ SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) vrect.height = scr_vrect.height; vrect.next = 0; } - VID_Update (&vrect); + sw_ctx->update (&vrect); } diff --git a/libs/video/renderer/sw/sw_rmisc.c b/libs/video/renderer/sw/sw_rmisc.c index f30200ffa..b2272ff14 100644 --- a/libs/video/renderer/sw/sw_rmisc.c +++ b/libs/video/renderer/sw/sw_rmisc.c @@ -37,6 +37,7 @@ #include "compat.h" #include "r_internal.h" #include "vid_internal.h" +#include "vid_sw.h" static void @@ -74,7 +75,7 @@ R_TimeRefresh_f (void) vr.width = r_refdef.vrect.width; vr.height = r_refdef.vrect.height; vr.next = NULL; - VID_Update (&vr); + sw_ctx->update (&vr); } stop = Sys_DoubleTime (); time = stop - start; diff --git a/libs/video/renderer/sw32/screen.c b/libs/video/renderer/sw32/screen.c index bcadb5c9b..e4779d8da 100644 --- a/libs/video/renderer/sw32/screen.c +++ b/libs/video/renderer/sw32/screen.c @@ -54,6 +54,7 @@ #include "compat.h" #include "r_internal.h" #include "vid_internal.h" +#include "vid_sw.h" /* SCREEN SHOTS */ @@ -221,5 +222,5 @@ sw32_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs vrect.height = scr_vrect.height; vrect.next = 0; } - VID_Update (&vrect); + sw32_ctx->update (&vrect); } diff --git a/libs/video/renderer/sw32/sw32_rmisc.c b/libs/video/renderer/sw32/sw32_rmisc.c index cb12395d3..1b329b54f 100644 --- a/libs/video/renderer/sw32/sw32_rmisc.c +++ b/libs/video/renderer/sw32/sw32_rmisc.c @@ -40,7 +40,7 @@ #include "compat.h" #include "r_internal.h" #include "vid_internal.h" - +#include "vid_sw.h" static void R_CheckVariables (void) @@ -77,7 +77,7 @@ sw32_R_TimeRefresh_f (void) vr.width = r_refdef.vrect.width; vr.height = r_refdef.vrect.height; vr.next = NULL; - VID_Update (&vr); + sw32_ctx->update (&vr); } stop = Sys_DoubleTime (); time = stop - start; diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 91f4178b5..9085e751d 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -39,9 +39,12 @@ #include "mod_internal.h" #include "r_internal.h" #include "vid_internal.h" +#include "vid_gl.h" #include "gl/namehack.h" +gl_ctx_t *gl_ctx; + static vid_model_funcs_t model_funcs = { gl_Mod_LoadExternalTextures, gl_Mod_LoadLighting, @@ -124,12 +127,29 @@ vid_render_funcs_t gl_vid_render_funcs = { &model_funcs }; +static void +gl_vid_render_choose_visual (void) +{ + gl_ctx->choose_visual (gl_ctx); +} + +static void +gl_vid_render_create_context (void) +{ + gl_ctx->create_context (gl_ctx); +} + static void gl_vid_render_init (void) { + gl_ctx = vr_data.vid->vid_internal->gl_context (); + gl_ctx->init_gl = GL_Init_Common; + gl_ctx->load_gl (); + vr_data.vid->vid_internal->set_palette = GL_SetPalette; - vr_data.vid->vid_internal->init_gl = GL_Init_Common; - vr_data.vid->vid_internal->load_gl (); + vr_data.vid->vid_internal->choose_visual = gl_vid_render_choose_visual; + vr_data.vid->vid_internal->create_context = gl_vid_render_create_context; + vr_funcs = &gl_vid_render_funcs; m_funcs = &model_funcs; } diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index d1f380ae5..22de04ea3 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -39,9 +39,12 @@ #include "mod_internal.h" #include "r_internal.h" #include "vid_internal.h" +#include "vid_gl.h" #include "glsl/namehack.h" +gl_ctx_t *glsl_ctx; + static vid_model_funcs_t model_funcs = { glsl_Mod_LoadExternalTextures, glsl_Mod_LoadLighting, @@ -124,12 +127,28 @@ vid_render_funcs_t glsl_vid_render_funcs = { &model_funcs }; +static void +glsl_vid_render_choose_visual (void) +{ + glsl_ctx->choose_visual (glsl_ctx); +} + +static void +glsl_vid_render_create_context (void) +{ + glsl_ctx->create_context (glsl_ctx); +} + static void glsl_vid_render_init (void) { + glsl_ctx = vr_data.vid->vid_internal->gl_context (); + glsl_ctx->init_gl = GLSL_Init_Common; + glsl_ctx->load_gl (); + vr_data.vid->vid_internal->set_palette = GLSL_SetPalette; - vr_data.vid->vid_internal->init_gl = GLSL_Init_Common; - vr_data.vid->vid_internal->load_gl (); + vr_data.vid->vid_internal->choose_visual = glsl_vid_render_choose_visual; + vr_data.vid->vid_internal->create_context = glsl_vid_render_create_context; vr_funcs = &glsl_vid_render_funcs; m_funcs = &model_funcs; } diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 7c2485911..dcfb4abc7 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -1,5 +1,5 @@ /* - vid_render_gl.c + vid_render_sw.c SW version of the renderer @@ -33,6 +33,10 @@ #include "mod_internal.h" #include "r_internal.h" +#include "vid_internal.h" +#include "vid_sw.h" + +sw_ctx_t *sw_ctx; static vid_model_funcs_t model_funcs = { sw_Mod_LoadExternalTextures, @@ -116,9 +120,27 @@ vid_render_funcs_t sw_vid_render_funcs = { &model_funcs }; +static void +sw_vid_render_choose_visual (void) +{ + sw_ctx->choose_visual (sw_ctx); +} + +static void +sw_vid_render_create_context (void) +{ + sw_ctx->create_context (sw_ctx); +} + static void sw_vid_render_init (void) { + sw_ctx = vr_data.vid->vid_internal->sw_context (); + + vr_data.vid->vid_internal->set_palette = sw_ctx->set_palette; + vr_data.vid->vid_internal->choose_visual = sw_vid_render_choose_visual; + vr_data.vid->vid_internal->create_context = sw_vid_render_create_context; + vr_funcs = &sw_vid_render_funcs; m_funcs = &model_funcs; } diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index 40034c0dc..ed7414a85 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -36,9 +36,13 @@ #include "mod_internal.h" #include "r_internal.h" +#include "vid_internal.h" +#include "vid_sw.h" #include "sw32/namehack.h" +sw_ctx_t *sw32_ctx; + static vid_model_funcs_t model_funcs = { sw_Mod_LoadExternalTextures, sw_Mod_LoadLighting, @@ -121,9 +125,27 @@ vid_render_funcs_t sw32_vid_render_funcs = { &model_funcs }; +static void +sw32_vid_render_choose_visual (void) +{ + sw32_ctx->choose_visual (sw32_ctx); +} + +static void +sw32_vid_render_create_context (void) +{ + sw32_ctx->create_context (sw32_ctx); +} + static void sw32_vid_render_init (void) { + sw32_ctx = vr_data.vid->vid_internal->sw_context (); + + vr_data.vid->vid_internal->set_palette = sw32_ctx->set_palette; + vr_data.vid->vid_internal->choose_visual = sw32_vid_render_choose_visual; + vr_data.vid->vid_internal->create_context = sw32_vid_render_create_context; + vr_funcs = &sw32_vid_render_funcs; m_funcs = &model_funcs; } diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index c71264fcb..2a94f31cb 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -39,9 +39,12 @@ #include "mod_internal.h" #include "r_internal.h" #include "vid_internal.h" +#include "vid_vulkan.h" #include "vulkan/namehack.h" +vulkan_ctx_t *vulkan_ctx; + static vid_model_funcs_t model_funcs = { /* vulkan_Mod_LoadExternalTextures, vulkan_Mod_LoadLighting, @@ -135,9 +138,11 @@ set_palette (const byte *palette) static void vulkan_vid_render_init (void) { + vulkan_ctx = vr_data.vid->vid_internal->vulkan_context (); + vulkan_ctx->init_vulkan = Vulkan_Init_Common; + vulkan_ctx->load_vulkan (vulkan_ctx); + vr_data.vid->vid_internal->set_palette = set_palette; - vr_data.vid->vid_internal->init_gl = Vulkan_Init_Common; - vr_data.vid->vid_internal->load_gl (); vr_funcs = &vulkan_vid_render_funcs; m_funcs = &model_funcs; } diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index 5d2f65d8e..e4102ec9d 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -1,12 +1,11 @@ AUTOMAKE_OPTIONS= foreign AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES -DVK_USE_PLATFORM_XLIB_KHR +AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES vulkan_src = \ init.c \ vulkan_draw.c \ - vulkan_funcs.c \ vulkan_vid_common.c noinst_LTLIBRARIES= libvulkan.la diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c index 2c4fb7ca1..e3181fc07 100644 --- a/libs/video/renderer/vulkan/init.c +++ b/libs/video/renderer/vulkan/init.c @@ -43,7 +43,8 @@ #include "QF/vid.h" #include "QF/Vulkan/init.h" -cvar_t *vulkan_library_name; +#include "vid_vulkan.h" + cvar_t *vulkan_use_validation; static uint32_t numLayers; @@ -78,9 +79,9 @@ get_instance_layers_and_extensions (void) VkLayerProperties *properties; VkExtensionProperties *extensions; - vkEnumerateInstanceLayerProperties (&numLayers, 0); + vulkan_ctx->vkEnumerateInstanceLayerProperties (&numLayers, 0); properties = malloc (numLayers * sizeof (VkLayerProperties)); - vkEnumerateInstanceLayerProperties (&numLayers, properties); + vulkan_ctx->vkEnumerateInstanceLayerProperties (&numLayers, properties); instanceLayerNames = (const char **) malloc ((numLayers + 1) * sizeof (const char **)); for (i = 0; i < numLayers; i++) { @@ -88,9 +89,10 @@ get_instance_layers_and_extensions (void) } instanceLayerNames[i] = 0; - vkEnumerateInstanceExtensionProperties (0, &numExtensions, 0); + vulkan_ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, 0); extensions = malloc (numExtensions * sizeof (VkLayerProperties)); - vkEnumerateInstanceExtensionProperties (0, &numExtensions, extensions); + vulkan_ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, + extensions); instanceExtensionNames = (const char **) malloc ((numExtensions + 1) * sizeof (const char **)); for (i = 0; i < numExtensions; i++) { @@ -278,15 +280,15 @@ static void load_instance_funcs (VulkanInstance_t *instance) { #define INSTANCE_LEVEL_VULKAN_FUNCTION(name) \ - instance->name = (PFN_##name) vkGetInstanceProcAddr (instance->instance, \ - #name); \ + instance->name = (PFN_##name) \ + vulkan_ctx->vkGetInstanceProcAddr (instance->instance, #name); \ if (!instance->name) { \ Sys_Error ("Couldn't find instance level function %s", #name); \ } #define INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) \ - instance->name = (PFN_##name) vkGetInstanceProcAddr (instance->instance,\ - #name); \ + instance->name = (PFN_##name) \ + vulkan_ctx->vkGetInstanceProcAddr (instance->instance, #name); \ if (!instance->name) { \ Sys_Printf ("Couldn't find instance level function %s", #name); \ } @@ -344,7 +346,7 @@ Vulkan_CreateInstance (const char *appName, uint32_t appVersion, createInfo.ppEnabledLayerNames = lay; createInfo.ppEnabledExtensionNames = ext; - res = vkCreateInstance (&createInfo, 0, &instance); + res = vulkan_ctx->vkCreateInstance (&createInfo, 0, &instance); if (res != VK_SUCCESS) { Sys_Error ("unable to create vulkan instance\n"); } diff --git a/libs/video/renderer/vulkan/vulkan_funcs.c b/libs/video/renderer/vulkan/vulkan_funcs.c deleted file mode 100644 index 2d8f79c9a..000000000 --- a/libs/video/renderer/vulkan/vulkan_funcs.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -#define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; -#define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; - -#include "QF/Vulkan/funclist.h" diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 9366799cb..98a4d3dc3 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -39,8 +39,6 @@ # include #endif -#include - #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/input.h" @@ -55,43 +53,14 @@ #include "compat.h" #include "d_iface.h" #include "r_internal.h" - -static void *vulkan_library; +#include "vid_vulkan.h" static VulkanInstance_t *vulkan_instance; static VulkanDevice_t *vulkan_device; -static void -load_vulkan_library (void) -{ - vulkan_library = dlopen (vulkan_library_name->string, - RTLD_DEEPBIND | RTLD_NOW); - if (!vulkan_library) { - Sys_Error ("Couldn't load vulkan library %s: %s", - vulkan_library_name->name, dlerror ()); - } - - #define EXPORTED_VULKAN_FUNCTION(name) \ - name = (PFN_##name) dlsym (vulkan_library, #name); \ - if (!name) { \ - Sys_Error ("Couldn't find exported vulkan function %s", #name); \ - } - - #define GLOBAL_LEVEL_VULKAN_FUNCTION(name) \ - name = (PFN_##name) vkGetInstanceProcAddr (0, #name); \ - if (!name) { \ - Sys_Error ("Couldn't find global-level function %s", #name); \ - } - - #include "QF/Vulkan/funclist.h" -} - void Vulkan_Init_Cvars () { - vulkan_library_name = Cvar_Get ("vulkan_library", "libvulkan.so.1", - CVAR_ROM, 0, - "the name of the vulkan shared library"); vulkan_use_validation = Cvar_Get ("vulkan_use_validation", "1", CVAR_NONE, 0, "enable LunarG Standard Validation " @@ -101,7 +70,6 @@ Vulkan_Init_Cvars () static const char *instance_extensions[] = { VK_KHR_SURFACE_EXTENSION_NAME, - VK_KHR_XLIB_SURFACE_EXTENSION_NAME, 0, }; @@ -203,8 +171,6 @@ Vulkan_Init_Common (void) Sys_Printf ("Vulkan_Init_Common\n"); Vulkan_Init_Cvars (); - load_vulkan_library (); - vulkan_instance = Vulkan_CreateInstance (PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version vulkan_device = create_suitable_device (vulkan_instance); if (!vulkan_device) { @@ -227,6 +193,5 @@ Vulkan_Shutdown_Common (void) } Vulkan_DestroyInstance (vulkan_instance); vulkan_instance = 0; - dlclose (vulkan_library); - vulkan_library = 0; + vulkan_ctx->unload_vulkan (vulkan_ctx); } diff --git a/libs/video/targets/Makefile.am b/libs/video/targets/Makefile.am index b883b676b..d7241f528 100644 --- a/libs/video/targets/Makefile.am +++ b/libs/video/targets/Makefile.am @@ -27,6 +27,15 @@ joy_src= $(joy_null_src) endif endif +x11_gl_src=vid_x11_gl.c +x11_sw_src=vid_x11_sw.c +x11_vulkan_src=vid_x11_vulkan.c +if X11_VULKAN +x11_src= $(x11_gl_src) $(x11_sw_src) $(x11_vulkan_src) +else +x11_src= $(x11_gl_src) $(x11_sw_src) +endif + js_libs=$(top_builddir)/libs/util/libQFutil.la libQFjs_la_LDFLAGS= $(lib_ldflags) @@ -41,15 +50,16 @@ libvid_common_la_SOURCES= \ libvid_common_la_CFLAGS= @PREFER_NON_PIC@ libvid_common_la_LDFLAGS= @STATIC@ -libvid_x11_la_SOURCES= in_x11.c context_x11.c dga_check.c +libvid_x11_la_SOURCES= in_x11.c context_x11.c dga_check.c $(x11_src) libvid_x11_la_CFLAGS= @PREFER_NON_PIC@ $(X_CFLAGS) libvid_x11_la_LDFLAGS= @STATIC@ +EXTRA_libvid_x11_la_SOURCES= $(x11_vulkan_src) libvid_svga_la_SOURCES= in_svgalib.c libvid_svga_la_CFLAGS= @PREFER_NON_PIC@ $(SVGA_CFLAGS) libvid_svga_la_LDFLAGS= @STATIC@ -libvid_sdl_la_SOURCES= in_sdl.c context_sdl.c +libvid_sdl_la_SOURCES= in_sdl.c context_sdl.c vid_sdl_gl.c vid_sdl_sw.c libvid_sdl_la_CFLAGS= @PREFER_NON_PIC@ $(SDL_CFLAGS) libvid_sdl_la_LDFLAGS= @STATIC@ diff --git a/libs/video/targets/context_sdl.c b/libs/video/targets/context_sdl.c index 105d7e1f6..7426ea8f8 100644 --- a/libs/video/targets/context_sdl.c +++ b/libs/video/targets/context_sdl.c @@ -23,9 +23,6 @@ cvar_t *vid_bitdepth; -extern SDL_Surface *screen; - - void VID_SDL_GammaCheck (void) { @@ -67,9 +64,9 @@ VID_UpdateFullscreen (cvar_t *vid_fullscreen) { if (!r_data || !viddef.initialized) return; - if ((vid_fullscreen->int_val && !(screen->flags & SDL_FULLSCREEN)) - || (!vid_fullscreen->int_val && screen->flags & SDL_FULLSCREEN)) - if (!SDL_WM_ToggleFullScreen (screen)) + if ((vid_fullscreen->int_val && !(sdl_screen->flags & SDL_FULLSCREEN)) + || (!vid_fullscreen->int_val && sdl_screen->flags & SDL_FULLSCREEN)) + if (!SDL_WM_ToggleFullScreen (sdl_screen)) Sys_Printf ("VID_UpdateFullscreen: error setting fullscreen\n"); IN_UpdateGrab (in_grab); } diff --git a/libs/video/targets/vid_sdl.c b/libs/video/targets/vid_sdl.c index 514b8020e..9b1938d30 100644 --- a/libs/video/targets/vid_sdl.c +++ b/libs/video/targets/vid_sdl.c @@ -58,190 +58,17 @@ HWND mainwindow; #define BASEWIDTH 320 #define BASEHEIGHT 200 -byte *VGA_pagebase; -int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes = 0; - -SDL_Surface *screen = NULL; - -// Define GLAPIENTRY to a useful value -#ifndef GLAPIENTRY -# ifdef _WIN32 -# include -# define GLAPIENTRY WINAPI -# undef LoadImage -# else -# ifdef APIENTRY -# define GLAPIENTRY APIENTRY -# else -# define GLAPIENTRY -# endif -# endif -#endif +SDL_Surface *sdl_screen = NULL; static vid_internal_t vid_internal; -static void (*set_vid_mode) (Uint32 flags); - -static void (GLAPIENTRY *qfglFinish) (void); -static int use_gl_procaddress = 0; -static cvar_t *gl_driver; - -static byte cached_palette[256 * 3]; -static int update_palette; - -static void * -QFGL_ProcAddress (const char *name, qboolean crit) -{ - void *glfunc = NULL; - - Sys_MaskPrintf (SYS_VID, "DEBUG: Finding symbol %s ... ", name); - - glfunc = SDL_GL_GetProcAddress (name); - if (glfunc) { - Sys_MaskPrintf (SYS_VID, "found [%p]\n", glfunc); - return glfunc; - } - Sys_MaskPrintf (SYS_VID, "not found\n"); - - if (crit) { - if (strncmp ("fxMesa", name, 6) == 0) { - Sys_Printf ("This target requires a special version of Mesa with " - "support for Glide and SVGAlib.\n"); - Sys_Printf ("If you are in X, try using a GLX or SGL target.\n"); - } - Sys_Error ("Couldn't load critical OpenGL function %s, exiting...", - name); - } - return NULL; -} - -static void -sdlgl_set_vid_mode (Uint32 flags) -{ - int i, j; - - flags |= SDL_OPENGL; - - // Setup GL Attributes - SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); -// SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 0); // Try for 0, 8 -// SDL_GL_SetAttribute (SDL_GL_STEREO, 1); // Someday... - - for (i = 0; i < 5; i++) { - int k; - int color[5] = {32, 24, 16, 15, 0}; - int rgba[5][4] = { - {8, 8, 8, 0}, - {8, 8, 8, 8}, - {5, 6, 5, 0}, - {5, 5, 5, 0}, - {5, 5, 5, 1}, - }; - - SDL_GL_SetAttribute (SDL_GL_RED_SIZE, rgba[i][0]); - SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, rgba[i][1]); - SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, rgba[i][2]); - SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, rgba[i][3]); - - for (j = 0; j < 5; j++) { - for (k = 32; k >= 16; k -= 8) { - SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, k); - if ((screen = SDL_SetVideoMode (viddef.width, viddef.height, - color[j], flags))) - goto success; - } - } - } - - Sys_Error ("Couldn't set video mode: %s", SDL_GetError ()); - SDL_Quit (); - -success: - viddef.numpages = 2; - - viddef.vid_internal->init_gl (); -} - -static void -sdlgl_end_rendering (void) -{ - qfglFinish (); - SDL_GL_SwapBuffers (); -} - -static void -sdl_load_gl (void) -{ - viddef.vid_internal->get_proc_address = QFGL_ProcAddress; - viddef.vid_internal->end_rendering = sdlgl_end_rendering; - set_vid_mode = sdlgl_set_vid_mode; - - if (SDL_GL_LoadLibrary (gl_driver->string) != 0) - Sys_Error ("Couldn't load OpenGL library %s!", gl_driver->string); - - use_gl_procaddress = 1; - - qfglFinish = QFGL_ProcAddress ("glFinish", true); -} - -static void -sdl_update_palette (const byte *palette) -{ - SDL_Color colors[256]; - int i; - - for (i = 0; i < 256; ++i) { - colors[i].r = *palette++; - colors[i].g = *palette++; - colors[i].b = *palette++; - } - SDL_SetColors (screen, colors, 0, 256); -} - -static void -VID_SetPalette (const byte *palette) -{ - if (memcmp (cached_palette, palette, sizeof (cached_palette))) { - memcpy (cached_palette, palette, sizeof (cached_palette)); - update_palette = 1; - } -} - -static void -do_screen_buffer (void) -{ -} - -static void -sdl_set_vid_mode (Uint32 flags) -{ - // Initialize display - if (!(screen = SDL_SetVideoMode (viddef.width, viddef.height, 8, flags))) - Sys_Error ("VID: Couldn't set video mode: %s", SDL_GetError ()); - - // now know everything we need to know about the buffer - VGA_width = viddef.width; - VGA_height = viddef.height; - viddef.vid_internal->do_screen_buffer = do_screen_buffer; - VGA_pagebase = viddef.buffer = screen->pixels; - VGA_rowbytes = viddef.rowbytes = screen->pitch; - viddef.conbuffer = viddef.buffer; - viddef.conrowbytes = viddef.rowbytes; - viddef.direct = 0; - - VID_InitBuffers (); // allocate z buffer and surface cache -} +uint32_t sdl_flags; void VID_Init (byte *palette, byte *colormap) { - Uint32 flags; - - vid_internal.set_palette = VID_SetPalette; - vid_internal.load_gl = sdl_load_gl; - - set_vid_mode = sdl_set_vid_mode; - + vid_internal.gl_context = SDL_GL_Context; + vid_internal.sw_context = SDL_SW_Context; // Load the SDL library if (SDL_Init (SDL_INIT_VIDEO) < 0) Sys_Error ("VID: Couldn't load SDL: %s", SDL_GetError ()); @@ -256,9 +83,9 @@ VID_Init (byte *palette, byte *colormap) VID_GetWindowSize (BASEWIDTH, BASEHEIGHT); // Set video width, height and flags - flags = (SDL_SWSURFACE | SDL_HWPALETTE); + sdl_flags = (SDL_SWSURFACE | SDL_HWPALETTE); if (vid_fullscreen->int_val) { - flags |= SDL_FULLSCREEN; + sdl_flags |= SDL_FULLSCREEN; #ifndef _WIN32 // Don't annoy Mesa/3dfx folks // doesn't hurt if not using a gl renderer // FIXME: Maybe this could be put in a different spot, but I don't @@ -270,11 +97,10 @@ VID_Init (byte *palette, byte *colormap) #endif } - set_vid_mode (flags); + vid_internal.create_context (); VID_SDL_GammaCheck (); VID_InitGamma (palette); - viddef.vid_internal->set_palette (viddef.palette); viddef.initialized = true; @@ -296,46 +122,8 @@ void VID_Init_Cvars () { SDL_Init_Cvars (); - gl_driver = Cvar_Get ("gl_driver", GL_DRIVER, CVAR_ROM, NULL, - "The OpenGL library to use. (path optional)"); -} - -void -VID_Update (vrect_t *rects) -{ - static SDL_Rect *sdlrects; - static int num_sdlrects; - int i, n; - vrect_t *rect; - - if (update_palette) { - update_palette = 0; - sdl_update_palette (cached_palette); - } - // Two-pass system, since Quake doesn't do it the SDL way... - - // First, count the number of rectangles - n = 0; - for (rect = rects; rect; rect = rect->next) - ++n; - - if (n > num_sdlrects) { - num_sdlrects = n; - sdlrects = realloc (sdlrects, n * sizeof (SDL_Rect)); - if (!sdlrects) - Sys_Error ("Out of memory!"); - } - - // Second, copy them to SDL rectangles and update - i = 0; - for (rect = rects; rect; rect = rect->next) { - sdlrects[i].x = rect->x; - sdlrects[i].y = rect->y; - sdlrects[i].w = rect->width; - sdlrects[i].h = rect->height; - ++i; - } - SDL_UpdateRects (screen, n, sdlrects); + SDL_GL_Init_Cvars (); + SDL_SW_Init_Cvars (); } void @@ -343,14 +131,14 @@ D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) { Uint8 *offset; - if (!screen) + if (!sdl_screen) return; if (x < 0) - x = screen->w + x - 1; - offset = (Uint8 *) screen->pixels + y * screen->pitch + x; + x = sdl_screen->w + x - 1; + offset = (Uint8 *) sdl_screen->pixels + y * sdl_screen->pitch + x; while (height--) { memcpy (offset, pbitmap, width); - offset += screen->pitch; + offset += sdl_screen->pitch; pbitmap += width; } } @@ -358,11 +146,11 @@ D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) void D_EndDirectRect (int x, int y, int width, int height) { - if (!screen) + if (!sdl_screen) return; if (x < 0) - x = screen->w + x - 1; - SDL_UpdateRect (screen, x, y, width, height); + x = sdl_screen->w + x - 1; + SDL_UpdateRect (sdl_screen, x, y, width, height); } void diff --git a/libs/video/targets/vid_sdl_gl.c b/libs/video/targets/vid_sdl_gl.c new file mode 100644 index 000000000..829ca2860 --- /dev/null +++ b/libs/video/targets/vid_sdl_gl.c @@ -0,0 +1,178 @@ +/* + vid_sdl.c + + Video driver for Sam Lantinga's Simple DirectMedia Layer + + Copyright (C) 1996-1997 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include + +#include "QF/console.h" +#include "QF/cvar.h" +#include "QF/qendian.h" +#include "QF/sys.h" +#include "QF/vid.h" + +#include "context_sdl.h" +#include "d_iface.h" +#include "vid_internal.h" +#include "vid_gl.h" + +// Define GLAPIENTRY to a useful value +#ifndef GLAPIENTRY +# ifdef _WIN32 +# include +# define GLAPIENTRY WINAPI +# undef LoadImage +# else +# ifdef APIENTRY +# define GLAPIENTRY APIENTRY +# else +# define GLAPIENTRY +# endif +# endif +#endif + +static void (GLAPIENTRY *qfglFinish) (void); +static int use_gl_procaddress = 0; +static cvar_t *gl_driver; + +static void * +QFGL_ProcAddress (const char *name, qboolean crit) +{ + void *glfunc = NULL; + + Sys_MaskPrintf (SYS_VID, "DEBUG: Finding symbol %s ... ", name); + + glfunc = SDL_GL_GetProcAddress (name); + if (glfunc) { + Sys_MaskPrintf (SYS_VID, "found [%p]\n", glfunc); + return glfunc; + } + Sys_MaskPrintf (SYS_VID, "not found\n"); + + if (crit) { + if (strncmp ("fxMesa", name, 6) == 0) { + Sys_Printf ("This target requires a special version of Mesa with " + "support for Glide and SVGAlib.\n"); + Sys_Printf ("If you are in X, try using a GLX or SGL target.\n"); + } + Sys_Error ("Couldn't load critical OpenGL function %s, exiting...", + name); + } + return NULL; +} + +static void +sdlgl_set_vid_mode (gl_ctx_t *ctx) +{ + int i, j; + + sdl_flags |= SDL_OPENGL; + + // Setup GL Attributes + SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); +// SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 0); // Try for 0, 8 +// SDL_GL_SetAttribute (SDL_GL_STEREO, 1); // Someday... + + for (i = 0; i < 5; i++) { + int k; + int color[5] = {32, 24, 16, 15, 0}; + int rgba[5][4] = { + {8, 8, 8, 0}, + {8, 8, 8, 8}, + {5, 6, 5, 0}, + {5, 5, 5, 0}, + {5, 5, 5, 1}, + }; + + SDL_GL_SetAttribute (SDL_GL_RED_SIZE, rgba[i][0]); + SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, rgba[i][1]); + SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, rgba[i][2]); + SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, rgba[i][3]); + + for (j = 0; j < 5; j++) { + for (k = 32; k >= 16; k -= 8) { + SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, k); + if ((sdl_screen = SDL_SetVideoMode (viddef.width, viddef.height, + color[j], sdl_flags))) + goto success; + } + } + } + + Sys_Error ("Couldn't set video mode: %s", SDL_GetError ()); + SDL_Quit (); + +success: + viddef.numpages = 2; + + ctx->init_gl (); +} + +static void +sdlgl_end_rendering (void) +{ + qfglFinish (); + SDL_GL_SwapBuffers (); +} + +static void +sdl_load_gl (void) +{ + if (SDL_GL_LoadLibrary (gl_driver->string) != 0) + Sys_Error ("Couldn't load OpenGL library %s!", gl_driver->string); + + use_gl_procaddress = 1; + + qfglFinish = QFGL_ProcAddress ("glFinish", true); +} + +gl_ctx_t * +SDL_GL_Context (void) +{ + gl_ctx_t *ctx = calloc (1, sizeof (gl_ctx_t)); + ctx->load_gl = sdl_load_gl; + ctx->create_context = sdlgl_set_vid_mode; + ctx->get_proc_address = QFGL_ProcAddress; + ctx->end_rendering = sdlgl_end_rendering; + return ctx; +} + +void +SDL_GL_Init_Cvars () +{ + gl_driver = Cvar_Get ("gl_driver", GL_DRIVER, CVAR_ROM, NULL, + "The OpenGL library to use. (path optional)"); +} diff --git a/libs/video/targets/vid_sdl_sw.c b/libs/video/targets/vid_sdl_sw.c new file mode 100644 index 000000000..2d4f806d4 --- /dev/null +++ b/libs/video/targets/vid_sdl_sw.c @@ -0,0 +1,183 @@ +/* + vid_sdl.c + + Video driver for Sam Lantinga's Simple DirectMedia Layer + + Copyright (C) 1996-1997 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include + +#include "QF/console.h" +#include "QF/cvar.h" +#include "QF/qendian.h" +#include "QF/sys.h" +#include "QF/vid.h" + +#include "context_sdl.h" +#include "d_iface.h" +#include "vid_internal.h" +#include "vid_sw.h" + +#ifdef _WIN32 // FIXME: evil hack to get full DirectSound support with SDL +#include +#include +HWND mainwindow; +#endif + +// The original defaults +#define BASEWIDTH 320 +#define BASEHEIGHT 200 + +byte *VGA_pagebase; +int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes = 0; + +// Define GLAPIENTRY to a useful value +#ifndef GLAPIENTRY +# ifdef _WIN32 +# include +# define GLAPIENTRY WINAPI +# undef LoadImage +# else +# ifdef APIENTRY +# define GLAPIENTRY APIENTRY +# else +# define GLAPIENTRY +# endif +# endif +#endif + +static byte cached_palette[256 * 3]; +static int update_palette; + +static void +sdl_update_palette (const byte *palette) +{ + SDL_Color colors[256]; + int i; + + for (i = 0; i < 256; ++i) { + colors[i].r = *palette++; + colors[i].g = *palette++; + colors[i].b = *palette++; + } + SDL_SetColors (sdl_screen, colors, 0, 256); +} + +static void +VID_SetPalette (const byte *palette) +{ + if (memcmp (cached_palette, palette, sizeof (cached_palette))) { + memcpy (cached_palette, palette, sizeof (cached_palette)); + update_palette = 1; + } +} + +static void +do_screen_buffer (void) +{ +} + +static void +sdl_set_vid_mode (sw_ctx_t *ctx) +{ + // Initialize display + if (!(sdl_screen = SDL_SetVideoMode (viddef.width, viddef.height, 8, + sdl_flags))) + Sys_Error ("VID: Couldn't set video mode: %s", SDL_GetError ()); + + // now know everything we need to know about the buffer + VGA_width = viddef.width; + VGA_height = viddef.height; + viddef.vid_internal->do_screen_buffer = do_screen_buffer; + VGA_pagebase = viddef.buffer = sdl_screen->pixels; + VGA_rowbytes = viddef.rowbytes = sdl_screen->pitch; + viddef.conbuffer = viddef.buffer; + viddef.conrowbytes = viddef.rowbytes; + viddef.direct = 0; + + VID_InitBuffers (); // allocate z buffer and surface cache +} + +static void +sdl_sw_update (vrect_t *rects) +{ + static SDL_Rect *sdlrects; + static int num_sdlrects; + int i, n; + vrect_t *rect; + + if (update_palette) { + update_palette = 0; + sdl_update_palette (cached_palette); + } + // Two-pass system, since Quake doesn't do it the SDL way... + + // First, count the number of rectangles + n = 0; + for (rect = rects; rect; rect = rect->next) + ++n; + + if (n > num_sdlrects) { + num_sdlrects = n; + sdlrects = realloc (sdlrects, n * sizeof (SDL_Rect)); + if (!sdlrects) + Sys_Error ("Out of memory!"); + } + + // Second, copy them to SDL rectangles and update + i = 0; + for (rect = rects; rect; rect = rect->next) { + sdlrects[i].x = rect->x; + sdlrects[i].y = rect->y; + sdlrects[i].w = rect->width; + sdlrects[i].h = rect->height; + ++i; + } + SDL_UpdateRects (sdl_screen, n, sdlrects); +} + +sw_ctx_t * +SDL_SW_Context (void) +{ + sw_ctx_t *ctx = calloc (1, sizeof (sw_ctx_t)); + ctx->set_palette = VID_SetPalette; + ctx->create_context = sdl_set_vid_mode; + ctx->update = sdl_sw_update; + return ctx; +} + +void +SDL_SW_Init_Cvars () +{ +} diff --git a/libs/video/targets/vid_x11.c b/libs/video/targets/vid_x11.c index bc4b4b6dc..946824547 100644 --- a/libs/video/targets/vid_x11.c +++ b/libs/video/targets/vid_x11.c @@ -44,21 +44,10 @@ # include #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include -#include #ifdef HAVE_VIDMODE # include @@ -67,7 +56,6 @@ #include "QF/cmd.h" #include "QF/console.h" #include "QF/cvar.h" -#include "QF/qargs.h" #include "QF/qendian.h" #include "QF/screen.h" #include "QF/sys.h" @@ -80,339 +68,9 @@ #include "vid_internal.h" static vid_internal_t vid_internal; -int XShmGetEventBase (Display *x); // for broken X11 headers - -static GC x_gc; - -static qboolean doShm; -static XShmSegmentInfo x_shminfo[2]; - -static int current_framebuffer; -static XImage *x_framebuffer[2] = { 0, 0 }; int VID_options_items = 1; -static byte current_palette[768]; - -typedef unsigned char PIXEL8; -typedef unsigned short PIXEL16; -typedef unsigned int PIXEL24; - -static PIXEL16 st2d_8to16table[256]; -static PIXEL24 st2d_8to24table[256]; -static int shiftmask_fl = 0; -static long r_shift, g_shift, b_shift; -static unsigned long r_mask, g_mask, b_mask; - -#define GLX_RGBA 4 // true if RGBA mode -#define GLX_DOUBLEBUFFER 5 // double buffering supported -#define GLX_RED_SIZE 8 // number of red component bits -#define GLX_GREEN_SIZE 9 // number of green component bits -#define GLX_BLUE_SIZE 10 // number of blue component bits -#define GLX_DEPTH_SIZE 12 // number of depth bits - -// GLXContext is a pointer to opaque data -typedef struct __GLXcontextRec *GLXContext; -typedef XID GLXDrawable; - -// Define GLAPIENTRY to a useful value -#ifndef GLAPIENTRY -# ifdef _WIN32 -# include -# define GLAPIENTRY WINAPI -# undef LoadImage -# else -# ifdef APIENTRY -# define GLAPIENTRY APIENTRY -# else -# define GLAPIENTRY -# endif -# endif -#endif -static GLXContext ctx = NULL; -static void *libgl_handle; -static void (*qfglXSwapBuffers) (Display *dpy, GLXDrawable drawable); -static XVisualInfo* (*qfglXChooseVisual) (Display *dpy, int screen, - int *attribList); -static GLXContext (*qfglXCreateContext) (Display *dpy, XVisualInfo *vis, - GLXContext shareList, Bool direct); -static Bool (*qfglXMakeCurrent) (Display *dpy, GLXDrawable drawable, - GLXContext ctx); -static void (GLAPIENTRY *qfglFinish) (void); -static void *(*glGetProcAddress) (const char *symbol) = NULL; -static int use_gl_procaddress = 0; -static cvar_t *gl_driver; - -static void (*choose_visual) (void); -static void (*create_context) (void); - -static void * -QFGL_GetProcAddress (void *handle, const char *name) -{ - void *glfunc = NULL; - - if (use_gl_procaddress && glGetProcAddress) - glfunc = glGetProcAddress (name); - if (!glfunc) - glfunc = dlsym (handle, name); - return glfunc; -} - -static void * -QFGL_ProcAddress (const char *name, qboolean crit) -{ - void *glfunc = NULL; - - Sys_MaskPrintf (SYS_VID, "DEBUG: Finding symbol %s ... ", name); - - glfunc = QFGL_GetProcAddress (libgl_handle, name); - if (glfunc) { - Sys_MaskPrintf (SYS_VID, "found [%p]\n", glfunc); - return glfunc; - } - Sys_MaskPrintf (SYS_VID, "not found\n"); - - if (crit) { - if (strncmp ("fxMesa", name, 6) == 0) { - Sys_Printf ("This target requires a special version of Mesa with " - "support for Glide and SVGAlib.\n"); - Sys_Printf ("If you are in X, try using a GLX or SGL target.\n"); - } - Sys_Error ("Couldn't load critical OpenGL function %s, exiting...", - name); - } - return NULL; -} - -static void -glx_choose_visual (void) -{ - int attrib[] = { - GLX_RGBA, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DOUBLEBUFFER, - GLX_DEPTH_SIZE, 1, - None - }; - - x_visinfo = qfglXChooseVisual (x_disp, x_screen, attrib); - if (!x_visinfo) { - Sys_Error ("Error couldn't get an RGB, Double-buffered, Depth visual"); - } - x_vis = x_visinfo->visual; -} - -static void -glx_create_context (void) -{ - XSync (x_disp, 0); - ctx = qfglXCreateContext (x_disp, x_visinfo, NULL, True); - qfglXMakeCurrent (x_disp, x_win, ctx); - viddef.vid_internal->init_gl (); -} - -static void -glx_end_rendering (void) -{ - qfglFinish (); - qfglXSwapBuffers (x_disp, x_win); -} - -static void -glx_load_gl (void) -{ - int flags = RTLD_NOW; - - choose_visual = glx_choose_visual; - create_context = glx_create_context; - - viddef.vid_internal->get_proc_address = QFGL_ProcAddress; - viddef.vid_internal->end_rendering = glx_end_rendering; - -#ifdef RTLD_GLOBAL - flags |= RTLD_GLOBAL; -#endif - if (!(libgl_handle = dlopen (gl_driver->string, flags))) { - Sys_Error ("Couldn't load OpenGL library %s: %s", gl_driver->string, - dlerror ()); - } - glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddress"); - if (!glGetProcAddress) - glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddressARB"); - - qfglXSwapBuffers = QFGL_ProcAddress ("glXSwapBuffers", true); - qfglXChooseVisual = QFGL_ProcAddress ("glXChooseVisual", true); - qfglXCreateContext = QFGL_ProcAddress ("glXCreateContext", true); - qfglXMakeCurrent = QFGL_ProcAddress ("glXMakeCurrent", true); - - use_gl_procaddress = 1; - - qfglFinish = QFGL_ProcAddress ("glFinish", true); -} - -static void -shiftmask_init (void) -{ - unsigned long long x; - - r_mask = x_vis->red_mask; - g_mask = x_vis->green_mask; - b_mask = x_vis->blue_mask; - - for (r_shift = -8, x = 1; x < r_mask; x <<= 1) - r_shift++; - for (g_shift = -8, x = 1; x < g_mask; x <<= 1) - g_shift++; - for (b_shift = -8, x = 1; x < b_mask; x <<= 1) - b_shift++; - shiftmask_fl = 1; -} - -static PIXEL16 -xlib_rgb16 (int r, int g, int b) -{ - PIXEL16 p = 0; - - if (!shiftmask_fl) - shiftmask_init (); - - if (r_shift > 0) { - p = (r << (r_shift)) & r_mask; - } else { - if (r_shift < 0) { - p = (r >> (-r_shift)) & r_mask; - } else { - p |= (r & r_mask); - } - } - - if (g_shift > 0) { - p |= (g << (g_shift)) & g_mask; - } else { - if (g_shift < 0) { - p |= (g >> (-g_shift)) & g_mask; - } else { - p |= (g & g_mask); - } - } - - if (b_shift > 0) { - p |= (b << (b_shift)) & b_mask; - } else { - if (b_shift < 0) { - p |= (b >> (-b_shift)) & b_mask; - } else { - p |= (b & b_mask); - } - } - - return p; -} - -static PIXEL24 -xlib_rgb24 (int r, int g, int b) -{ - PIXEL24 p = 0; - - if (!shiftmask_fl) - shiftmask_init (); - - if (r_shift > 0) { - p = (r << (r_shift)) & r_mask; - } else { - if (r_shift < 0) { - p = (r >> (-r_shift)) & r_mask; - } else { - p |= (r & r_mask); - } - } - - if (g_shift > 0) { - p |= (g << (g_shift)) & g_mask; - } else { - if (g_shift < 0) { - p |= (g >> (-g_shift)) & g_mask; - } else { - p |= (g & g_mask); - } - } - - if (b_shift > 0) { - p |= (b << (b_shift)) & b_mask; - } else { - if (b_shift < 0) { - p |= (b >> (-b_shift)) & b_mask; - } else { - p |= (b & b_mask); - } - } - - return p; -} - -static void -st2_fixup (XImage *framebuf, int x, int y, int width, int height) -{ - int xi, yi; - unsigned char *src; - PIXEL16 *dest; - - if (x < 0 || y < 0) - return; - - for (yi = y; yi < (y + height); yi++) { - src = &((byte *)viddef.buffer)[yi * viddef.width]; - dest = (PIXEL16 *) &framebuf->data[yi * framebuf->bytes_per_line]; - for (xi = x; xi < x + width; xi++) { - dest[xi] = st2d_8to16table[src[xi]]; - } - } -} - -static void -st3_fixup (XImage * framebuf, int x, int y, int width, int height) -{ - int yi; - unsigned char *src; - PIXEL24 *dest; - register int count, n; - - if (x < 0 || y < 0) - return; - - for (yi = y; yi < (y + height); yi++) { - src = &((byte *)viddef.buffer)[yi * viddef.width + x]; - dest = (PIXEL24 *) &framebuf->data[yi * framebuf->bytes_per_line + x]; - - // Duff's Device - count = width; - n = (count + 7) / 8; - - switch (count % 8) { - case 0: - do { - *dest++ = st2d_8to24table[*src++]; - case 7: - *dest++ = st2d_8to24table[*src++]; - case 6: - *dest++ = st2d_8to24table[*src++]; - case 5: - *dest++ = st2d_8to24table[*src++]; - case 4: - *dest++ = st2d_8to24table[*src++]; - case 3: - *dest++ = st2d_8to24table[*src++]; - case 2: - *dest++ = st2d_8to24table[*src++]; - case 1: - *dest++ = st2d_8to24table[*src++]; - } while (--n > 0); - } - } -} - void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) { @@ -425,240 +83,6 @@ D_EndDirectRect (int x, int y, int width, int height) // direct drawing of the "accessing disk" icon isn't supported } -static void -ResetFrameBuffer (void) -{ - int mem, pwidth; - char *buf; - - if (x_framebuffer[0]) { - XDestroyImage (x_framebuffer[0]); - } - - pwidth = x_visinfo->depth / 8; - - if (pwidth == 3) - pwidth = 4; - mem = ((viddef.width * pwidth + 7) & ~7) * viddef.height; - buf = malloc (mem); - SYS_CHECKMEM (buf); - - // allocate new screen buffer - x_framebuffer[0] = XCreateImage (x_disp, x_vis, x_visinfo->depth, - ZPixmap, 0, buf, viddef.width, - viddef.height, 32, 0); - - if (!x_framebuffer[0]) { - Sys_Error ("VID: XCreateImage failed"); - } -} - -static void -ResetSharedFrameBuffers (void) -{ - int size; - int key; - int minsize = getpagesize (); - int frm; - - for (frm = 0; frm < 2; frm++) { - - // free up old frame buffer memory - if (x_framebuffer[frm]) { - XShmDetach (x_disp, &x_shminfo[frm]); - free (x_framebuffer[frm]); - shmdt (x_shminfo[frm].shmaddr); - } - // create the image - x_framebuffer[frm] = XShmCreateImage (x_disp, x_vis, x_visinfo->depth, - ZPixmap, 0, &x_shminfo[frm], - viddef.width, viddef.height); - - // grab shared memory - size = x_framebuffer[frm]->bytes_per_line * x_framebuffer[frm]->height; - - if (size < minsize) - Sys_Error ("VID: Window must use at least %d bytes", minsize); - - key = random (); - x_shminfo[frm].shmid = shmget ((key_t) key, size, IPC_CREAT | 0777); - if (x_shminfo[frm].shmid == -1) - Sys_Error ("VID: Could not get any shared memory (%s)", - strerror (errno)); - - // attach to the shared memory segment - x_shminfo[frm].shmaddr = (void *) shmat (x_shminfo[frm].shmid, 0, 0); - - Sys_MaskPrintf (SYS_VID, "VID: shared memory id=%d, addr=0x%lx\n", - x_shminfo[frm].shmid, (long) x_shminfo[frm].shmaddr); - - x_framebuffer[frm]->data = x_shminfo[frm].shmaddr; - - // get the X server to attach to it - if (!XShmAttach (x_disp, &x_shminfo[frm])) - Sys_Error ("VID: XShmAttach() failed"); - XSync (x_disp, 0); - shmctl (x_shminfo[frm].shmid, IPC_RMID, 0); - - } -} - -static void -x11_init_buffers (void) -{ - if (doShm) - ResetSharedFrameBuffers (); - else - ResetFrameBuffer (); - - current_framebuffer = 0; - - viddef.direct = 0; - viddef.rowbytes = viddef.width; - if (x_visinfo->depth != 8) { - if (viddef.buffer) - free (viddef.buffer); - viddef.buffer = calloc (viddef.width, viddef.height); - if (!viddef.buffer) - Sys_Error ("Not enough memory for video mode"); - } else { - viddef.buffer = x_framebuffer[current_framebuffer]->data; - } - viddef.conbuffer = viddef.buffer; - - viddef.conrowbytes = viddef.rowbytes; -} - -static void -x11_choose_visual (void) -{ - int pnum, i; - XVisualInfo template; - int num_visuals; - int template_mask; - - // specify a visual id - if ((pnum = COM_CheckParm ("-visualid"))) { - if (pnum >= com_argc - 1) - Sys_Error ("VID: -visualid "); - template.visualid = atoi (com_argv[pnum + 1]); - template_mask = VisualIDMask; - } else { // If not specified, use default - // visual - template.visualid = - XVisualIDFromVisual (XDefaultVisual (x_disp, x_screen)); - template_mask = VisualIDMask; - } - - // pick a visual -- warn if more than one was available - x_visinfo = XGetVisualInfo (x_disp, template_mask, &template, - &num_visuals); - - if (x_visinfo->depth == 8 && x_visinfo->class == PseudoColor) - x_cmap = XCreateColormap (x_disp, x_win, x_vis, AllocAll); - x_vis = x_visinfo->visual; - - if (num_visuals > 1) { - Sys_MaskPrintf (SYS_VID, - "Found more than one visual id at depth %d:\n", - template.depth); - for (i = 0; i < num_visuals; i++) - Sys_MaskPrintf (SYS_VID, " -visualid %d\n", - (int) x_visinfo[i].visualid); - } else { - if (num_visuals == 0) { - if (template_mask == VisualIDMask) { - Sys_Error ("VID: Bad visual ID %ld", template.visualid); - } else { - Sys_Error ("VID: No visuals at depth %d", template.depth); - } - } - } - - Sys_MaskPrintf (SYS_VID, "Using visualid %d:\n", - (int) x_visinfo->visualid); - Sys_MaskPrintf (SYS_VID, " class %d\n", x_visinfo->class); - Sys_MaskPrintf (SYS_VID, " screen %d\n", x_visinfo->screen); - Sys_MaskPrintf (SYS_VID, " depth %d\n", x_visinfo->depth); - Sys_MaskPrintf (SYS_VID, " red_mask 0x%x\n", - (int) x_visinfo->red_mask); - Sys_MaskPrintf (SYS_VID, " green_mask 0x%x\n", - (int) x_visinfo->green_mask); - Sys_MaskPrintf (SYS_VID, " blue_mask 0x%x\n", - (int) x_visinfo->blue_mask); - Sys_MaskPrintf (SYS_VID, " colormap_size %d\n", - x_visinfo->colormap_size); - Sys_MaskPrintf (SYS_VID, " bits_per_rgb %d\n", - x_visinfo->bits_per_rgb); -} - -static void -x11_create_context (void) -{ - // create the GC - { - XGCValues xgcvalues; - int valuemask = GCGraphicsExposures; - - xgcvalues.graphics_exposures = False; - x_gc = XCreateGC (x_disp, x_win, valuemask, &xgcvalues); - } - - // even if MITSHM is available, make sure it's a local connection - if (XShmQueryExtension (x_disp)) { - char *displayname; - char *d; - - doShm = true; - - if ((displayname = XDisplayName (NULL))) { - if ((d = strchr (displayname, ':'))) - *d = '\0'; - - if (!(!strcasecmp (displayname, "unix") || !*displayname)) - doShm = false; - } - } - - if (doShm) { - x_shmeventtype = XShmGetEventBase (x_disp) + ShmCompletion; - } - - viddef.vid_internal->do_screen_buffer = x11_init_buffers; - VID_InitBuffers (); - -// XSynchronize (x_disp, False); -// X11_AddEvent (x_shmeventtype, event_shm); -} - -static void -VID_SetPalette (const byte *palette) -{ - int i; - XColor colors[256]; - - for (i = 0; i < 256; i++) { - st2d_8to16table[i] = xlib_rgb16 (palette[i * 3], palette[i * 3 + 1], - palette[i * 3 + 2]); - st2d_8to24table[i] = xlib_rgb24 (palette[i * 3], palette[i * 3 + 1], - palette[i * 3 + 2]); - } - - if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) { - if (palette != current_palette) { - memcpy (current_palette, palette, 768); - } - for (i = 0; i < 256; i++) { - colors[i].pixel = i; - colors[i].flags = DoRed | DoGreen | DoBlue; - colors[i].red = palette[(i * 3)] << 8; - colors[i].green = palette[(i * 3) + 1] << 8; - colors[i].blue = palette[(i * 3) + 2] << 8; - } - XStoreColors (x_disp, x_cmap, colors, 256); - } -} - /* Set up color translation tables and the window. Takes a 256-color 8-bit palette. Palette data will go away after the call, so copy it if you'll @@ -667,11 +91,11 @@ VID_SetPalette (const byte *palette) void VID_Init (byte *palette, byte *colormap) { - vid_internal.load_gl = glx_load_gl; - vid_internal.set_palette = VID_SetPalette; - - choose_visual = x11_choose_visual; - create_context = x11_create_context; + vid_internal.gl_context = X11_GL_Context; + vid_internal.sw_context = X11_SW_Context; +#ifdef HAVE_VULKAN + vid_internal.vulkan_context = X11_Vulkan_Context; +#endif R_LoadModule (&vid_internal); @@ -683,11 +107,11 @@ VID_Init (byte *palette, byte *colormap) VID_GetWindowSize (320, 200); X11_OpenDisplay (); - choose_visual (); + vid_internal.choose_visual (); X11_SetVidMode (viddef.width, viddef.height); X11_CreateWindow (viddef.width, viddef.height); X11_CreateNullCursor (); // hide mouse pointer - create_context (); + vid_internal.create_context (); VID_InitGamma (palette); viddef.vid_internal->set_palette (viddef.palette); @@ -703,8 +127,10 @@ void VID_Init_Cvars () { X11_Init_Cvars (); - gl_driver = Cvar_Get ("gl_driver", GL_DRIVER, CVAR_ROM, NULL, - "The OpenGL library to use. (path optional)"); +#ifdef HAVE_VULKAN + X11_Vulkan_Init_Cvars (); +#endif + X11_GL_Init_Cvars (); } /* @@ -719,17 +145,13 @@ VID_Shutdown (void) X11_CloseDisplay (); } +#if 0 static int config_notify = 0; static int config_notify_width; static int config_notify_height; -/* - VID_Update - - Flush the given rectangles from the view buffer to the screen. -*/ -void -VID_Update (vrect_t *rects) +static void +update () { /* If the window changes dimension, skip this frame. */ if (config_notify) { @@ -744,43 +166,8 @@ VID_Update (vrect_t *rects) Con_CheckResize (); return; } - - while (rects) { - switch (x_visinfo->depth) { - case 16: - st2_fixup (x_framebuffer[current_framebuffer], - rects->x, rects->y, rects->width, rects->height); - break; - case 24: - st3_fixup (x_framebuffer[current_framebuffer], - rects->x, rects->y, rects->width, rects->height); - break; - } - if (doShm) { - if (!XShmPutImage (x_disp, x_win, x_gc, - x_framebuffer[current_framebuffer], - rects->x, rects->y, rects->x, rects->y, - rects->width, rects->height, True)) { - Sys_Error ("VID_Update: XShmPutImage failed"); - } - oktodraw = false; - while (!oktodraw) - X11_ProcessEvent (); - rects = rects->next; - - current_framebuffer = !current_framebuffer; - } else { - if (XPutImage (x_disp, x_win, x_gc, x_framebuffer[0], - rects->x, rects->y, rects->x, rects->y, - rects->width, rects->height)) { - Sys_Error ("VID_Update: XPutImage failed"); - } - rects = rects->next; - } - } - XSync (x_disp, False); - r_data->scr_fullupdate = 0; } +#endif void VID_LockBuffer (void) diff --git a/libs/video/targets/vid_x11_gl.c b/libs/video/targets/vid_x11_gl.c new file mode 100644 index 000000000..28b2f3294 --- /dev/null +++ b/libs/video/targets/vid_x11_gl.c @@ -0,0 +1,209 @@ +/* + vid_x11_gl.c + + GLX X11 video driver + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 1999-2000 contributors of the QuakeForge project + Copyright (C) 2000 Marcus Sundberg [mackan@stacken.kth.se] + Copyright (C) 1999,2000 contributors of the QuakeForge project + Please see the file "AUTHORS" for a list of contributors + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include + +#include "QF/cvar.h" +#include "QF/sys.h" +#include "QF/vid.h" + +#include "context_x11.h" +#include "r_internal.h" +#include "vid_internal.h" +#include "vid_gl.h" + +#define GLX_RGBA 4 // true if RGBA mode +#define GLX_DOUBLEBUFFER 5 // double buffering supported +#define GLX_RED_SIZE 8 // number of red component bits +#define GLX_GREEN_SIZE 9 // number of green component bits +#define GLX_BLUE_SIZE 10 // number of blue component bits +#define GLX_DEPTH_SIZE 12 // number of depth bits + +typedef XID GLXDrawable; + +// Define GLAPIENTRY to a useful value +#ifndef GLAPIENTRY +# ifdef _WIN32 +# include +# define GLAPIENTRY WINAPI +# undef LoadImage +# else +# ifdef APIENTRY +# define GLAPIENTRY APIENTRY +# else +# define GLAPIENTRY +# endif +# endif +#endif +static void *libgl_handle; +static void (*qfglXSwapBuffers) (Display *dpy, GLXDrawable drawable); +static XVisualInfo* (*qfglXChooseVisual) (Display *dpy, int screen, + int *attribList); +static GLXContext (*qfglXCreateContext) (Display *dpy, XVisualInfo *vis, + GLXContext shareList, Bool direct); +static Bool (*qfglXMakeCurrent) (Display *dpy, GLXDrawable drawable, + GLXContext ctx); +static void (GLAPIENTRY *qfglFinish) (void); +static void *(*glGetProcAddress) (const char *symbol) = NULL; +static int use_gl_procaddress = 0; + +static cvar_t *gl_driver; + +static void * +QFGL_GetProcAddress (void *handle, const char *name) +{ + void *glfunc = NULL; + + if (use_gl_procaddress && glGetProcAddress) + glfunc = glGetProcAddress (name); + if (!glfunc) + glfunc = dlsym (handle, name); + return glfunc; +} + +static void * +QFGL_ProcAddress (const char *name, qboolean crit) +{ + void *glfunc = NULL; + + Sys_MaskPrintf (SYS_VID, "DEBUG: Finding symbol %s ... ", name); + + glfunc = QFGL_GetProcAddress (libgl_handle, name); + if (glfunc) { + Sys_MaskPrintf (SYS_VID, "found [%p]\n", glfunc); + return glfunc; + } + Sys_MaskPrintf (SYS_VID, "not found\n"); + + if (crit) { + if (strncmp ("fxMesa", name, 6) == 0) { + Sys_Printf ("This target requires a special version of Mesa with " + "support for Glide and SVGAlib.\n"); + Sys_Printf ("If you are in X, try using a GLX or SGL target.\n"); + } + Sys_Error ("Couldn't load critical OpenGL function %s, exiting...", + name); + } + return NULL; +} + +static void +glx_choose_visual (gl_ctx_t *ctx) +{ + int attrib[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, 1, + None + }; + + x_visinfo = qfglXChooseVisual (x_disp, x_screen, attrib); + if (!x_visinfo) { + Sys_Error ("Error couldn't get an RGB, Double-buffered, Depth visual"); + } + x_vis = x_visinfo->visual; +} + +static void +glx_create_context (gl_ctx_t *ctx) +{ + XSync (x_disp, 0); + ctx->context = qfglXCreateContext (x_disp, x_visinfo, NULL, True); + qfglXMakeCurrent (x_disp, x_win, ctx->context); + ctx->init_gl (); +} + +static void +glx_end_rendering (void) +{ + qfglFinish (); + qfglXSwapBuffers (x_disp, x_win); +} + +static void +glx_load_gl (void) +{ + libgl_handle = dlopen (gl_driver->string, RTLD_NOW); + if (!libgl_handle) { + Sys_Error ("Couldn't load OpenGL library %s: %s", gl_driver->string, + dlerror ()); + } + glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddress"); + if (!glGetProcAddress) + glGetProcAddress = dlsym (libgl_handle, "glXGetProcAddressARB"); + + qfglXSwapBuffers = QFGL_ProcAddress ("glXSwapBuffers", true); + qfglXChooseVisual = QFGL_ProcAddress ("glXChooseVisual", true); + qfglXCreateContext = QFGL_ProcAddress ("glXCreateContext", true); + qfglXMakeCurrent = QFGL_ProcAddress ("glXMakeCurrent", true); + + use_gl_procaddress = 1; + + qfglFinish = QFGL_ProcAddress ("glFinish", true); +} + +gl_ctx_t * +X11_GL_Context (void) +{ + gl_ctx_t *ctx = calloc (1, sizeof (gl_ctx_t)); + ctx->load_gl = glx_load_gl; + ctx->choose_visual = glx_choose_visual; + ctx->create_context = glx_create_context; + ctx->get_proc_address = QFGL_ProcAddress; + ctx->end_rendering = glx_end_rendering; + return ctx; +} + +void +X11_GL_Init_Cvars (void) +{ + gl_driver = Cvar_Get ("gl_driver", GL_DRIVER, CVAR_ROM, NULL, + "The OpenGL library to use. (path optional)"); +} diff --git a/libs/video/targets/vid_x11_sw.c b/libs/video/targets/vid_x11_sw.c new file mode 100644 index 000000000..9c734a635 --- /dev/null +++ b/libs/video/targets/vid_x11_sw.c @@ -0,0 +1,542 @@ +/* + vid_x11_sw.c + + Software X11 video driver (8/32 bit) + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 1999-2000 contributors of the QuakeForge project + Copyright (C) 2000 Marcus Sundberg [mackan@stacken.kth.se] + Copyright (C) 1999,2000 contributors of the QuakeForge project + Please see the file "AUTHORS" for a list of contributors + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "QF/cvar.h" +#include "QF/qargs.h" +#include "QF/sys.h" +#include "QF/vid.h" + +#include "context_x11.h" +#include "r_internal.h" +#include "vid_internal.h" +#include "vid_sw.h" + +int XShmGetEventBase (Display *x); // for broken X11 headers + +static GC x_gc; + +static qboolean doShm; +static XShmSegmentInfo x_shminfo[2]; + +static int current_framebuffer; +static XImage *x_framebuffer[2] = { 0, 0 }; + +typedef unsigned char PIXEL8; +typedef unsigned short PIXEL16; +typedef unsigned int PIXEL24; + +static PIXEL16 st2d_8to16table[256]; +static PIXEL24 st2d_8to24table[256]; + +static byte current_palette[768]; +static int shiftmask_fl = 0; +static long r_shift, g_shift, b_shift; +static unsigned long r_mask, g_mask, b_mask; + +static void +shiftmask_init (void) +{ + unsigned long long x; + + r_mask = x_vis->red_mask; + g_mask = x_vis->green_mask; + b_mask = x_vis->blue_mask; + + for (r_shift = -8, x = 1; x < r_mask; x <<= 1) + r_shift++; + for (g_shift = -8, x = 1; x < g_mask; x <<= 1) + g_shift++; + for (b_shift = -8, x = 1; x < b_mask; x <<= 1) + b_shift++; + shiftmask_fl = 1; +} + +static PIXEL16 +xlib_rgb16 (int r, int g, int b) +{ + PIXEL16 p = 0; + + if (!shiftmask_fl) + shiftmask_init (); + + if (r_shift > 0) { + p = (r << (r_shift)) & r_mask; + } else { + if (r_shift < 0) { + p = (r >> (-r_shift)) & r_mask; + } else { + p |= (r & r_mask); + } + } + + if (g_shift > 0) { + p |= (g << (g_shift)) & g_mask; + } else { + if (g_shift < 0) { + p |= (g >> (-g_shift)) & g_mask; + } else { + p |= (g & g_mask); + } + } + + if (b_shift > 0) { + p |= (b << (b_shift)) & b_mask; + } else { + if (b_shift < 0) { + p |= (b >> (-b_shift)) & b_mask; + } else { + p |= (b & b_mask); + } + } + + return p; +} + +static PIXEL24 +xlib_rgb24 (int r, int g, int b) +{ + PIXEL24 p = 0; + + if (!shiftmask_fl) + shiftmask_init (); + + if (r_shift > 0) { + p = (r << (r_shift)) & r_mask; + } else { + if (r_shift < 0) { + p = (r >> (-r_shift)) & r_mask; + } else { + p |= (r & r_mask); + } + } + + if (g_shift > 0) { + p |= (g << (g_shift)) & g_mask; + } else { + if (g_shift < 0) { + p |= (g >> (-g_shift)) & g_mask; + } else { + p |= (g & g_mask); + } + } + + if (b_shift > 0) { + p |= (b << (b_shift)) & b_mask; + } else { + if (b_shift < 0) { + p |= (b >> (-b_shift)) & b_mask; + } else { + p |= (b & b_mask); + } + } + + return p; +} + +static void +VID_SetPalette (const byte *palette) +{ + int i; + XColor colors[256]; + + for (i = 0; i < 256; i++) { + st2d_8to16table[i] = xlib_rgb16 (palette[i * 3], palette[i * 3 + 1], + palette[i * 3 + 2]); + st2d_8to24table[i] = xlib_rgb24 (palette[i * 3], palette[i * 3 + 1], + palette[i * 3 + 2]); + } + + if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) { + if (palette != current_palette) { + memcpy (current_palette, palette, 768); + } + for (i = 0; i < 256; i++) { + colors[i].pixel = i; + colors[i].flags = DoRed | DoGreen | DoBlue; + colors[i].red = palette[(i * 3)] << 8; + colors[i].green = palette[(i * 3) + 1] << 8; + colors[i].blue = palette[(i * 3) + 2] << 8; + } + XStoreColors (x_disp, x_cmap, colors, 256); + } +} + +static void +st2_fixup (XImage *framebuf, int x, int y, int width, int height) +{ + int xi, yi; + unsigned char *src; + PIXEL16 *dest; + + if (x < 0 || y < 0) + return; + + for (yi = y; yi < (y + height); yi++) { + src = &((byte *)viddef.buffer)[yi * viddef.width]; + dest = (PIXEL16 *) &framebuf->data[yi * framebuf->bytes_per_line]; + for (xi = x; xi < x + width; xi++) { + dest[xi] = st2d_8to16table[src[xi]]; + } + } +} + +static void +st3_fixup (XImage * framebuf, int x, int y, int width, int height) +{ + int yi; + unsigned char *src; + PIXEL24 *dest; + register int count, n; + + if (x < 0 || y < 0) + return; + + for (yi = y; yi < (y + height); yi++) { + src = &((byte *)viddef.buffer)[yi * viddef.width + x]; + dest = (PIXEL24 *) &framebuf->data[yi * framebuf->bytes_per_line + x]; + + // Duff's Device + count = width; + n = (count + 7) / 8; + + switch (count % 8) { + case 0: + do { + *dest++ = st2d_8to24table[*src++]; + case 7: + *dest++ = st2d_8to24table[*src++]; + case 6: + *dest++ = st2d_8to24table[*src++]; + case 5: + *dest++ = st2d_8to24table[*src++]; + case 4: + *dest++ = st2d_8to24table[*src++]; + case 3: + *dest++ = st2d_8to24table[*src++]; + case 2: + *dest++ = st2d_8to24table[*src++]; + case 1: + *dest++ = st2d_8to24table[*src++]; + } while (--n > 0); + } + } +} + +/* + Flush the given rectangles from the view buffer to the screen. +*/ +static void +x11_sw_update (vrect_t *rects) +{ + while (rects) { + switch (x_visinfo->depth) { + case 16: + st2_fixup (x_framebuffer[current_framebuffer], + rects->x, rects->y, rects->width, rects->height); + break; + case 24: + st3_fixup (x_framebuffer[current_framebuffer], + rects->x, rects->y, rects->width, rects->height); + break; + } + if (doShm) { + if (!XShmPutImage (x_disp, x_win, x_gc, + x_framebuffer[current_framebuffer], + rects->x, rects->y, rects->x, rects->y, + rects->width, rects->height, True)) { + Sys_Error ("VID_Update: XShmPutImage failed"); + } + oktodraw = false; + while (!oktodraw) + X11_ProcessEvent (); + rects = rects->next; + + current_framebuffer = !current_framebuffer; + } else { + if (XPutImage (x_disp, x_win, x_gc, x_framebuffer[0], + rects->x, rects->y, rects->x, rects->y, + rects->width, rects->height)) { + Sys_Error ("VID_Update: XPutImage failed"); + } + rects = rects->next; + } + } + XSync (x_disp, False); + r_data->scr_fullupdate = 0; +} + +static void +x11_choose_visual (sw_ctx_t *ctx) +{ + int pnum, i; + XVisualInfo template; + int num_visuals; + int template_mask; + + // specify a visual id + if ((pnum = COM_CheckParm ("-visualid"))) { + if (pnum >= com_argc - 1) + Sys_Error ("VID: -visualid "); + template.visualid = atoi (com_argv[pnum + 1]); + template_mask = VisualIDMask; + } else { // If not specified, use default + // visual + template.visualid = + XVisualIDFromVisual (XDefaultVisual (x_disp, x_screen)); + template_mask = VisualIDMask; + } + + // pick a visual -- warn if more than one was available + x_visinfo = XGetVisualInfo (x_disp, template_mask, &template, + &num_visuals); + + if (x_visinfo->depth == 8 && x_visinfo->class == PseudoColor) + x_cmap = XCreateColormap (x_disp, x_win, x_vis, AllocAll); + x_vis = x_visinfo->visual; + + if (num_visuals > 1) { + Sys_MaskPrintf (SYS_VID, + "Found more than one visual id at depth %d:\n", + template.depth); + for (i = 0; i < num_visuals; i++) + Sys_MaskPrintf (SYS_VID, " -visualid %d\n", + (int) x_visinfo[i].visualid); + } else { + if (num_visuals == 0) { + if (template_mask == VisualIDMask) { + Sys_Error ("VID: Bad visual ID %ld", template.visualid); + } else { + Sys_Error ("VID: No visuals at depth %d", template.depth); + } + } + } + + Sys_MaskPrintf (SYS_VID, "Using visualid %d:\n", + (int) x_visinfo->visualid); + Sys_MaskPrintf (SYS_VID, " class %d\n", x_visinfo->class); + Sys_MaskPrintf (SYS_VID, " screen %d\n", x_visinfo->screen); + Sys_MaskPrintf (SYS_VID, " depth %d\n", x_visinfo->depth); + Sys_MaskPrintf (SYS_VID, " red_mask 0x%x\n", + (int) x_visinfo->red_mask); + Sys_MaskPrintf (SYS_VID, " green_mask 0x%x\n", + (int) x_visinfo->green_mask); + Sys_MaskPrintf (SYS_VID, " blue_mask 0x%x\n", + (int) x_visinfo->blue_mask); + Sys_MaskPrintf (SYS_VID, " colormap_size %d\n", + x_visinfo->colormap_size); + Sys_MaskPrintf (SYS_VID, " bits_per_rgb %d\n", + x_visinfo->bits_per_rgb); +} + +static void +ResetFrameBuffer (void) +{ + int mem, pwidth; + char *buf; + + if (x_framebuffer[0]) { + XDestroyImage (x_framebuffer[0]); + } + + pwidth = x_visinfo->depth / 8; + + if (pwidth == 3) + pwidth = 4; + mem = ((viddef.width * pwidth + 7) & ~7) * viddef.height; + buf = malloc (mem); + SYS_CHECKMEM (buf); + + // allocate new screen buffer + x_framebuffer[0] = XCreateImage (x_disp, x_vis, x_visinfo->depth, + ZPixmap, 0, buf, viddef.width, + viddef.height, 32, 0); + + if (!x_framebuffer[0]) { + Sys_Error ("VID: XCreateImage failed"); + } +} + +static void +ResetSharedFrameBuffers (void) +{ + int size; + int key; + int minsize = getpagesize (); + int frm; + + for (frm = 0; frm < 2; frm++) { + + // free up old frame buffer memory + if (x_framebuffer[frm]) { + XShmDetach (x_disp, &x_shminfo[frm]); + free (x_framebuffer[frm]); + shmdt (x_shminfo[frm].shmaddr); + } + // create the image + x_framebuffer[frm] = XShmCreateImage (x_disp, x_vis, x_visinfo->depth, + ZPixmap, 0, &x_shminfo[frm], + viddef.width, viddef.height); + + // grab shared memory + size = x_framebuffer[frm]->bytes_per_line * x_framebuffer[frm]->height; + + if (size < minsize) + Sys_Error ("VID: Window must use at least %d bytes", minsize); + + key = random (); + x_shminfo[frm].shmid = shmget ((key_t) key, size, IPC_CREAT | 0777); + if (x_shminfo[frm].shmid == -1) + Sys_Error ("VID: Could not get any shared memory (%s)", + strerror (errno)); + + // attach to the shared memory segment + x_shminfo[frm].shmaddr = (void *) shmat (x_shminfo[frm].shmid, 0, 0); + + Sys_MaskPrintf (SYS_VID, "VID: shared memory id=%d, addr=0x%lx\n", + x_shminfo[frm].shmid, (long) x_shminfo[frm].shmaddr); + + x_framebuffer[frm]->data = x_shminfo[frm].shmaddr; + + // get the X server to attach to it + if (!XShmAttach (x_disp, &x_shminfo[frm])) + Sys_Error ("VID: XShmAttach() failed"); + XSync (x_disp, 0); + shmctl (x_shminfo[frm].shmid, IPC_RMID, 0); + + } +} + +static void +x11_init_buffers (void) +{ + if (doShm) + ResetSharedFrameBuffers (); + else + ResetFrameBuffer (); + + current_framebuffer = 0; + + viddef.direct = 0; + viddef.rowbytes = viddef.width; + if (x_visinfo->depth != 8) { + if (viddef.buffer) + free (viddef.buffer); + viddef.buffer = calloc (viddef.width, viddef.height); + if (!viddef.buffer) + Sys_Error ("Not enough memory for video mode"); + } else { + viddef.buffer = x_framebuffer[current_framebuffer]->data; + } + viddef.conbuffer = viddef.buffer; + + viddef.conrowbytes = viddef.rowbytes; +} + +static void +x11_create_context (sw_ctx_t *ctx) +{ + // create the GC + { + XGCValues xgcvalues; + int valuemask = GCGraphicsExposures; + + xgcvalues.graphics_exposures = False; + x_gc = XCreateGC (x_disp, x_win, valuemask, &xgcvalues); + } + + // even if MITSHM is available, make sure it's a local connection + if (XShmQueryExtension (x_disp)) { + char *displayname; + char *d; + + doShm = true; + + if ((displayname = XDisplayName (NULL))) { + if ((d = strchr (displayname, ':'))) + *d = '\0'; + + if (!(!strcasecmp (displayname, "unix") || !*displayname)) + doShm = false; + } + } + + if (doShm) { + x_shmeventtype = XShmGetEventBase (x_disp) + ShmCompletion; + } + + viddef.vid_internal->do_screen_buffer = x11_init_buffers; + VID_InitBuffers (); + +// XSynchronize (x_disp, False); +// X11_AddEvent (x_shmeventtype, event_shm); +} + +sw_ctx_t * +X11_SW_Context (void) +{ + sw_ctx_t *ctx = calloc (1, sizeof (sw_ctx_t)); + ctx->set_palette = VID_SetPalette; + ctx->choose_visual = x11_choose_visual; + ctx->create_context = x11_create_context; + ctx->update = x11_sw_update; + return ctx; +} + +void +X11_SW_Init_Cvars (void) +{ +} diff --git a/libs/video/targets/vid_x11_vulkan.c b/libs/video/targets/vid_x11_vulkan.c new file mode 100644 index 000000000..e472c0c0e --- /dev/null +++ b/libs/video/targets/vid_x11_vulkan.c @@ -0,0 +1,169 @@ +/* + vid_x11_vulkan.c + + Vulkan X11 video driver + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 1999-2000 contributors of the QuakeForge project + Copyright (C) 2000 Marcus Sundberg [mackan@stacken.kth.se] + Copyright (C) 1999,2000 contributors of the QuakeForge project + Please see the file "AUTHORS" for a list of contributors + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include +#define VK_NO_PROTOTYPES +#define VK_USE_PLATFORM_XLIB_KHR +#include + +#include "QF/cvar.h" +#include "QF/set.h" +#include "QF/sys.h" + +#include "context_x11.h" +#include "vid_internal.h" +#include "vid_vulkan.h" + +static cvar_t *vulkan_library_name; + +typedef struct vulkan_presentation_s { +#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; +#include "QF/Vulkan/funclist.h" + + Display *display; + Window window; + int num_visuals; + XVisualInfo *visinfo; + set_t *usable_visuals; +} vulkan_presentation_t; + +static const char *required_extensions[] = { + VK_KHR_XLIB_SURFACE_EXTENSION_NAME, + 0 +}; + +static void *vulkan_library; + +static void +load_vulkan_library (vulkan_ctx_t *ctx) +{ + vulkan_library = dlopen (vulkan_library_name->string, + RTLD_DEEPBIND | RTLD_NOW); + if (!vulkan_library) { + Sys_Error ("Couldn't load vulkan library %s: %s", + vulkan_library_name->name, dlerror ()); + } + + #define EXPORTED_VULKAN_FUNCTION(name) \ + ctx->name = (PFN_##name) dlsym (vulkan_library, #name); \ + if (!ctx->name) { \ + Sys_Error ("Couldn't find exported vulkan function %s", #name); \ + } + + #define GLOBAL_LEVEL_VULKAN_FUNCTION(name) \ + ctx->name = (PFN_##name) ctx->vkGetInstanceProcAddr (0, #name); \ + if (!ctx->name) { \ + Sys_Error ("Couldn't find global-level function %s", #name); \ + } + + #include "QF/Vulkan/funclist.h" +} + +static void +unload_vulkan_library (vulkan_ctx_t *ctx) +{ + dlclose (vulkan_library); + vulkan_library = 0; +} + +static int +x11_vulkan_get_presentation_support (vulkan_ctx_t *ctx, + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex) +{ + vulkan_presentation_t *pres = ctx->presentation; + + set_empty (pres->usable_visuals); + for (int i = 0; i < pres->num_visuals; i++) { + VisualID visID = pres->visinfo[i].visualid; + + if (pres->vkGetPhysicalDeviceXlibPresentationSupportKHR ( + physicalDevice, queueFamilyIndex, pres->display, visID)) { + set_add (pres->usable_visuals, i); + } + } + return !set_is_empty (pres->usable_visuals); +} + +static VkSurfaceKHR +x11_vulkan_create_surface (vulkan_ctx_t *ctx) +{ + vulkan_presentation_t *pres = ctx->presentation; + VkSurfaceKHR surface; + VkXlibSurfaceCreateInfoKHR createInfo = { + .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + .flags = 0, + .dpy = pres->display, + .window = pres->window + }; + + if (pres->vkCreateXlibSurfaceKHR (ctx->instance, &createInfo, 0, &surface) + != VK_SUCCESS) { + return 0; + } + return surface; +} + +vulkan_ctx_t * +X11_Vulkan_Context (void) +{ + vulkan_ctx_t *ctx = calloc (1, sizeof (vulkan_ctx_t)); + ctx->load_vulkan = load_vulkan_library; + ctx->unload_vulkan = unload_vulkan_library; + ctx->get_presentation_support = x11_vulkan_get_presentation_support; + ctx->create_surface = x11_vulkan_create_surface; + ctx->required_extensions = required_extensions; + return ctx; +} + +void +X11_Vulkan_Init_Cvars (void) +{ + vulkan_library_name = Cvar_Get ("vulkan_library", "libvulkan.so.1", + CVAR_ROM, 0, + "the name of the vulkan shared library"); +} From e9f1bc7b30b77d41a733f914ffd507524a056c3a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 01:03:26 +0900 Subject: [PATCH 014/435] Make vulkan building actually conditional --- config.d/build_control.m4 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/config.d/build_control.m4 b/config.d/build_control.m4 index 94a7415af..a4df4a3a4 100644 --- a/config.d/build_control.m4 +++ b/config.d/build_control.m4 @@ -71,7 +71,11 @@ if test "x$HAVE_X" = xyes; then NQ_DESKTOP_DATA="$NQ_DESKTOP_DATA quakeforge-nq-x11.desktop" CL_TARGETS="$CL_TARGETS X11" VID_TARGETS="$VID_TARGETS libQFx11.la" - QF_NEED(vid_render, [sw sw32 gl glsl vulkan]) + if test "$HAVE_VULKAN" = "yes"; then + QF_NEED(vid_render, [sw sw32 gl glsl vulkan]) + else + QF_NEED(vid_render, [sw sw32 gl glsl]) + fi QF_NEED(models, [sw gl glsl]) QF_NEED(alias, [sw gl glsl]) QF_NEED(brush, [sw gl glsl]) @@ -95,7 +99,11 @@ if test "x$HAVE_SDL" = xyes; then NQ_DESKTOP_DATA="$NQ_DESKTOP_DATA quakeforge-nq-sdl.desktop" CL_TARGETS="$CL_TARGETS SDL" VID_TARGETS="$VID_TARGETS libQFsdl.la" - QF_NEED(vid_render, [sw sw32 gl glsl vulkan]) + if test "$HAVE_VULKAN" = "yes"; then + QF_NEED(vid_render, [sw sw32 gl glsl vulkan]) + else + QF_NEED(vid_render, [sw sw32 gl glsl]) + fi QF_NEED(models, [sw gl glsl]) QF_NEED(alias, [sw gl glsl]) QF_NEED(brush, [sw gl glsl]) From 707bdfc5f24fed2ac8b72c79b9c84ad835afe605 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 09:06:35 +0900 Subject: [PATCH 015/435] Get vulkan back to where it was --- include/vid_vulkan.h | 2 -- libs/video/renderer/vid_render_vulkan.c | 18 +++++++++++++++++- libs/video/renderer/vulkan/vulkan_vid_common.c | 12 +++++++----- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 627269cdb..ae83ae397 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -9,7 +9,6 @@ typedef struct vulkan_ctx_s { void (*load_vulkan) (struct vulkan_ctx_s *ctx); void (*unload_vulkan) (struct vulkan_ctx_s *ctx); - void (*init_vulkan) (void); const char * const *required_extensions; struct vulkan_presentation_s *presentation; @@ -18,7 +17,6 @@ typedef struct vulkan_ctx_s { uint32_t queueFamilyIndex); VkSurfaceKHR (*create_surface) (struct vulkan_ctx_s *ctx); VkInstance instance; - VkPhysicalDevice physicalDevice; #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; #include "QF/Vulkan/funclist.h" diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 2a94f31cb..840505e10 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -135,14 +135,30 @@ set_palette (const byte *palette) //an app using the QuakeForge engine) } +static void +vulkan_vid_render_choose_visual (void) +{ + //vulkan_ctx->coose_visual (vulkan_ctx); +} + +static void +vulkan_vid_render_create_context (void) +{ + vulkan_ctx->create_surface (vulkan_ctx); +} + static void vulkan_vid_render_init (void) { vulkan_ctx = vr_data.vid->vid_internal->vulkan_context (); - vulkan_ctx->init_vulkan = Vulkan_Init_Common; vulkan_ctx->load_vulkan (vulkan_ctx); + Vulkan_Init_Common (); + vr_data.vid->vid_internal->set_palette = set_palette; + vr_data.vid->vid_internal->choose_visual = vulkan_vid_render_choose_visual; + vr_data.vid->vid_internal->create_context = vulkan_vid_render_create_context; + vr_funcs = &vulkan_vid_render_funcs; m_funcs = &model_funcs; } diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 98a4d3dc3..cfd2a980f 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -165,6 +165,8 @@ create_suitable_device (VulkanInstance_t *instance) return 0; } +int x = 1; + void Vulkan_Init_Common (void) { @@ -176,11 +178,11 @@ Vulkan_Init_Common (void) if (!vulkan_device) { Sys_Error ("no suitable vulkan device found"); } - if (developer->int_val & SYS_VID) { - Sys_Printf ("%p %p\n", vulkan_device->device, vulkan_device->queue); - Vulkan_Shutdown_Common (); - Sys_Quit(); - } + // only for now... + Sys_Printf ("%p %p\n", vulkan_device->device, vulkan_device->queue); + Vulkan_Shutdown_Common (); + if (x) + Sys_Quit(); } void From b3d982bfc3a053e7058cace4e058050ff916c801 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 11:54:23 +0900 Subject: [PATCH 016/435] Remove global vulkan_ctx While I can't say that I'm happy with the details of vulkan_ctx_t, I am pretty sure I don't want to be limited to having only one. --- include/QF/Vulkan/init.h | 6 ++-- include/QF/Vulkan/qf_vid.h | 5 +-- include/vid_vulkan.h | 6 ++-- libs/video/renderer/vid_render_vulkan.c | 6 ++-- libs/video/renderer/vulkan/init.c | 34 ++++++++++--------- .../video/renderer/vulkan/vulkan_vid_common.c | 10 +++--- 6 files changed, 36 insertions(+), 31 deletions(-) diff --git a/include/QF/Vulkan/init.h b/include/QF/Vulkan/init.h index 85efb44e1..c964e6c41 100644 --- a/include/QF/Vulkan/init.h +++ b/include/QF/Vulkan/init.h @@ -52,7 +52,7 @@ typedef struct { VkQueueFamilyProperties *queueFamilies; } VulkanPhysDevice_t; -typedef struct { +typedef struct VulkanInstance_s { VkInstance instance; VkDebugUtilsMessengerEXT debug_callback; uint32_t numDevices; @@ -64,7 +64,9 @@ typedef struct { } VulkanInstance_t; void Vulkan_Init_Cvars (void); -VulkanInstance_t *Vulkan_CreateInstance (const char *appName, +struct vulkan_ctx_s; +VulkanInstance_t *Vulkan_CreateInstance (struct vulkan_ctx_s *ctx, + const char *appName, uint32_t appVersion, const char **layers, const char **extensions); diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index d032a075a..8e1825b48 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -30,7 +30,8 @@ #include "QF/Vulkan/cvars.h" -void Vulkan_Init_Common (void); -void Vulkan_Shutdown_Common (void); +struct vulkan_ctx_s; +void Vulkan_Init_Common (struct vulkan_ctx_s *ctx); +void Vulkan_Shutdown_Common (struct vulkan_ctx_s *ctx); #endif // __QF_Vulkan_vid_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index ae83ae397..eea285ae4 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -10,18 +10,18 @@ typedef struct vulkan_ctx_s { void (*load_vulkan) (struct vulkan_ctx_s *ctx); void (*unload_vulkan) (struct vulkan_ctx_s *ctx); - const char * const *required_extensions; + const char **required_extensions; struct vulkan_presentation_s *presentation; int (*get_presentation_support) (struct vulkan_ctx_s *ctx, VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); VkSurfaceKHR (*create_surface) (struct vulkan_ctx_s *ctx); + + struct VulkanInstance_s *vtx; VkInstance instance; #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; #include "QF/Vulkan/funclist.h" } vulkan_ctx_t; -extern vulkan_ctx_t *vulkan_ctx; - #endif//__vid_vulkan_h diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 840505e10..60c7c1b5e 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -43,7 +43,7 @@ #include "vulkan/namehack.h" -vulkan_ctx_t *vulkan_ctx; +static vulkan_ctx_t *vulkan_ctx; static vid_model_funcs_t model_funcs = { /* vulkan_Mod_LoadExternalTextures, @@ -153,7 +153,7 @@ vulkan_vid_render_init (void) vulkan_ctx = vr_data.vid->vid_internal->vulkan_context (); vulkan_ctx->load_vulkan (vulkan_ctx); - Vulkan_Init_Common (); + Vulkan_Init_Common (vulkan_ctx); vr_data.vid->vid_internal->set_palette = set_palette; vr_data.vid->vid_internal->choose_visual = vulkan_vid_render_choose_visual; @@ -166,7 +166,7 @@ vulkan_vid_render_init (void) static void vulkan_vid_render_shutdown (void) { - Vulkan_Shutdown_Common (); + Vulkan_Shutdown_Common (vulkan_ctx); } static general_funcs_t plugin_info_general_funcs = { diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c index e3181fc07..af3f21b4b 100644 --- a/libs/video/renderer/vulkan/init.c +++ b/libs/video/renderer/vulkan/init.c @@ -73,15 +73,15 @@ static const char *device_types[] = { }; static void -get_instance_layers_and_extensions (void) +get_instance_layers_and_extensions (vulkan_ctx_t *ctx) { uint32_t i; VkLayerProperties *properties; VkExtensionProperties *extensions; - vulkan_ctx->vkEnumerateInstanceLayerProperties (&numLayers, 0); + ctx->vkEnumerateInstanceLayerProperties (&numLayers, 0); properties = malloc (numLayers * sizeof (VkLayerProperties)); - vulkan_ctx->vkEnumerateInstanceLayerProperties (&numLayers, properties); + ctx->vkEnumerateInstanceLayerProperties (&numLayers, properties); instanceLayerNames = (const char **) malloc ((numLayers + 1) * sizeof (const char **)); for (i = 0; i < numLayers; i++) { @@ -89,9 +89,9 @@ get_instance_layers_and_extensions (void) } instanceLayerNames[i] = 0; - vulkan_ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, 0); + ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, 0); extensions = malloc (numExtensions * sizeof (VkLayerProperties)); - vulkan_ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, + ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, extensions); instanceExtensionNames = (const char **) malloc ((numExtensions + 1) * sizeof (const char **)); @@ -277,19 +277,19 @@ setup_debug_callback (VulkanInstance_t *instance) } static void -load_instance_funcs (VulkanInstance_t *instance) +load_instance_funcs (vulkan_ctx_t *ctx) { + VulkanInstance_t *vtx = ctx->vtx; + VkInstance instance = vtx->instance; #define INSTANCE_LEVEL_VULKAN_FUNCTION(name) \ - instance->name = (PFN_##name) \ - vulkan_ctx->vkGetInstanceProcAddr (instance->instance, #name); \ - if (!instance->name) { \ + vtx->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, #name); \ + if (!vtx->name) { \ Sys_Error ("Couldn't find instance level function %s", #name); \ } #define INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) \ - instance->name = (PFN_##name) \ - vulkan_ctx->vkGetInstanceProcAddr (instance->instance, #name); \ - if (!instance->name) { \ + vtx->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, #name); \ + if (!vtx->name) { \ Sys_Printf ("Couldn't find instance level function %s", #name); \ } @@ -297,7 +297,8 @@ load_instance_funcs (VulkanInstance_t *instance) } VulkanInstance_t * -Vulkan_CreateInstance (const char *appName, uint32_t appVersion, +Vulkan_CreateInstance (vulkan_ctx_t *ctx, + const char *appName, uint32_t appVersion, const char **layers, const char **extensions) { VkApplicationInfo appInfo = { @@ -319,7 +320,7 @@ Vulkan_CreateInstance (const char *appName, uint32_t appVersion, VulkanInstance_t *inst; if (!instanceLayerProperties) { - get_instance_layers_and_extensions (); + get_instance_layers_and_extensions (ctx); } createInfo.enabledLayerCount = count_strings (layers); @@ -346,13 +347,14 @@ Vulkan_CreateInstance (const char *appName, uint32_t appVersion, createInfo.ppEnabledLayerNames = lay; createInfo.ppEnabledExtensionNames = ext; - res = vulkan_ctx->vkCreateInstance (&createInfo, 0, &instance); + res = ctx->vkCreateInstance (&createInfo, 0, &instance); if (res != VK_SUCCESS) { Sys_Error ("unable to create vulkan instance\n"); } inst = malloc (sizeof(VulkanInstance_t)); inst->instance = instance; - load_instance_funcs (inst); + ctx->vtx = inst; + load_instance_funcs (ctx); if (vulkan_use_validation->int_val) { setup_debug_callback (inst); diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index cfd2a980f..96094303a 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -168,25 +168,25 @@ create_suitable_device (VulkanInstance_t *instance) int x = 1; void -Vulkan_Init_Common (void) +Vulkan_Init_Common (vulkan_ctx_t *ctx) { Sys_Printf ("Vulkan_Init_Common\n"); Vulkan_Init_Cvars (); - vulkan_instance = Vulkan_CreateInstance (PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version + vulkan_instance = Vulkan_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version vulkan_device = create_suitable_device (vulkan_instance); if (!vulkan_device) { Sys_Error ("no suitable vulkan device found"); } // only for now... Sys_Printf ("%p %p\n", vulkan_device->device, vulkan_device->queue); - Vulkan_Shutdown_Common (); + Vulkan_Shutdown_Common (ctx); if (x) Sys_Quit(); } void -Vulkan_Shutdown_Common (void) +Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) { if (vulkan_device) { vulkan_device->vkDestroyDevice (vulkan_device->device, 0); @@ -195,5 +195,5 @@ Vulkan_Shutdown_Common (void) } Vulkan_DestroyInstance (vulkan_instance); vulkan_instance = 0; - vulkan_ctx->unload_vulkan (vulkan_ctx); + ctx->unload_vulkan (ctx); } From 0f511e8342e5ce27a419ef4504defa3db6f3234d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 14:24:55 +0900 Subject: [PATCH 017/435] Move the string list funcs to their own file They're not (at this stage, at least) worthy of being promoted out to the utils lib. --- libs/video/renderer/vulkan/Makefile.am | 3 +- libs/video/renderer/vulkan/init.c | 51 +--------------- libs/video/renderer/vulkan/util.c | 83 ++++++++++++++++++++++++++ libs/video/renderer/vulkan/util.h | 9 +++ 4 files changed, 97 insertions(+), 49 deletions(-) create mode 100644 libs/video/renderer/vulkan/util.c create mode 100644 libs/video/renderer/vulkan/util.h diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index e4102ec9d..b134d1f91 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -5,6 +5,7 @@ AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES vulkan_src = \ init.c \ + util.c \ vulkan_draw.c \ vulkan_vid_common.c @@ -21,5 +22,5 @@ SUFFICES=.frag .vert .fc .vc .slc .glsl libvulkan_la_SOURCES= $(vulkan_src) -EXTRA_DIST = $(vulkan_src) $(shader_src) namehack.h +EXTRA_DIST = $(vulkan_src) $(shader_src) namehack.h util.h CLEANFILES= *.vc *.fc *.slc diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c index af3f21b4b..7b553d5f6 100644 --- a/libs/video/renderer/vulkan/init.c +++ b/libs/video/renderer/vulkan/init.c @@ -1,5 +1,5 @@ /* - int.c + init.c Copyright (C) 2019 Bill Currie @@ -45,6 +45,8 @@ #include "vid_vulkan.h" +#include "util.h" + cvar_t *vulkan_use_validation; static uint32_t numLayers; @@ -196,53 +198,6 @@ init_physdev (VulkanInstance_t *instance, VkPhysicalDevice dev, VulkanPhysDevice } } -static int -count_strings (const char **str) -{ - int count = 0; - - if (str) { - while (*str++) { - count++; - } - } - return count; -} - -static void -merge_strings (const char **out, const char **in1, const char **in2) -{ - if (in1) { - while (*in1) { - *out++ = *in1++; - } - } - if (in2) { - while (*in2) { - *out++ = *in2++; - } - } -} - -static void -prune_strings (const char * const *reference, const char **strings, - uint32_t *count) -{ - for (int i = *count; i-- > 0; ) { - const char *str = strings[i]; - const char * const *ref; - for (ref = reference; *ref; ref++) { - if (!strcmp (*ref, str)) { - break; - } - } - if (!*ref) { - memmove (strings + i, strings + i + 1, - (--(*count) - i) * sizeof (const char **)); - } - } -} - static int message_severities = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | diff --git a/libs/video/renderer/vulkan/util.c b/libs/video/renderer/vulkan/util.c new file mode 100644 index 000000000..5603bbd5d --- /dev/null +++ b/libs/video/renderer/vulkan/util.c @@ -0,0 +1,83 @@ +/* + util.c + + Copyright (C) 2019 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "util.h" + +int +count_strings (const char **str) +{ + int count = 0; + + if (str) { + while (*str++) { + count++; + } + } + return count; +} + +void +merge_strings (const char **out, const char **in1, const char **in2) +{ + if (in1) { + while (*in1) { + *out++ = *in1++; + } + } + if (in2) { + while (*in2) { + *out++ = *in2++; + } + } +} + +void +prune_strings (const char * const *reference, const char **strings, + uint32_t *count) +{ + for (int i = *count; i-- > 0; ) { + const char *str = strings[i]; + const char * const *ref; + for (ref = reference; *ref; ref++) { + if (!strcmp (*ref, str)) { + break; + } + } + if (!*ref) { + memmove (strings + i, strings + i + 1, + (--(*count) - i) * sizeof (const char **)); + } + } +} diff --git a/libs/video/renderer/vulkan/util.h b/libs/video/renderer/vulkan/util.h new file mode 100644 index 000000000..8d1a967a3 --- /dev/null +++ b/libs/video/renderer/vulkan/util.h @@ -0,0 +1,9 @@ +#ifndef __util_h +#define __util_h + +#include +int count_strings (const char **str); +void merge_strings (const char **out, const char **in1, const char **in2); +void prune_strings (const char * const *reference, const char **strings, uint32_t *count); + +#endif//__util_h From 68449d0f6f5ccd98aeb6b2d5b5fa159675e0d164 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 16:33:44 +0900 Subject: [PATCH 018/435] Create a window and a surface for vulkan Yay, segfaults in R_Init :) --- include/QF/Vulkan/init.h | 8 +- include/QF/Vulkan/qf_vid.h | 1 + include/vid_vulkan.h | 4 + libs/video/renderer/vid_render_vulkan.c | 10 +- libs/video/renderer/vulkan/init.c | 66 +++++++---- libs/video/renderer/vulkan/util.c | 5 +- libs/video/renderer/vulkan/util.h | 8 +- .../video/renderer/vulkan/vulkan_vid_common.c | 107 ++++++++++-------- libs/video/targets/vid_x11_vulkan.c | 48 ++++++++ 9 files changed, 180 insertions(+), 77 deletions(-) diff --git a/include/QF/Vulkan/init.h b/include/QF/Vulkan/init.h index c964e6c41..3afab0179 100644 --- a/include/QF/Vulkan/init.h +++ b/include/QF/Vulkan/init.h @@ -30,9 +30,10 @@ #include "QF/qtypes.h" -typedef struct { +typedef struct VulkanDevice_s { VkDevice device; VkQueue queue; + VkSurfaceKHR surface; #define DEVICE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; #define DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) PFN_##name name; @@ -63,6 +64,8 @@ typedef struct VulkanInstance_s { #include "QF/Vulkan/funclist.h" } VulkanInstance_t; +extern const char * const vulkanValidationLayers[]; + void Vulkan_Init_Cvars (void); struct vulkan_ctx_s; VulkanInstance_t *Vulkan_CreateInstance (struct vulkan_ctx_s *ctx, @@ -74,5 +77,8 @@ void Vulkan_DestroyInstance (VulkanInstance_t *instance); int Vulkan_ExtensionsSupported (const VkExtensionProperties *extensions, int numExtensions, const char * const *requested); +int Vulkan_LayersSupported (const VkLayerProperties *extensions, + int numLayers, + const char * const *requested); #endif // __QF_Vulkan_init_h diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index 8e1825b48..877bebaa3 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -31,6 +31,7 @@ #include "QF/Vulkan/cvars.h" struct vulkan_ctx_s; +void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx); void Vulkan_Init_Common (struct vulkan_ctx_s *ctx); void Vulkan_Shutdown_Common (struct vulkan_ctx_s *ctx); diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index eea285ae4..387a82078 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -15,10 +15,14 @@ typedef struct vulkan_ctx_s { int (*get_presentation_support) (struct vulkan_ctx_s *ctx, VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); + void (*choose_visual) (struct vulkan_ctx_s *ctx); + void (*create_window) (struct vulkan_ctx_s *ctx); VkSurfaceKHR (*create_surface) (struct vulkan_ctx_s *ctx); struct VulkanInstance_s *vtx; + struct VulkanDevice_s *dev; VkInstance instance; + VkDevice device; #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; #include "QF/Vulkan/funclist.h" diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 60c7c1b5e..c09bfe5e4 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -31,10 +31,13 @@ #define NH_DEFINE #include "vulkan/namehack.h" +#include "QF/sys.h" + #include "QF/plugin/general.h" #include "QF/plugin/vid_render.h" #include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/init.h" #include "mod_internal.h" #include "r_internal.h" @@ -138,13 +141,16 @@ set_palette (const byte *palette) static void vulkan_vid_render_choose_visual (void) { - //vulkan_ctx->coose_visual (vulkan_ctx); + Vulkan_CreateDevice (vulkan_ctx); + vulkan_ctx->choose_visual (vulkan_ctx); + Sys_Printf ("%p %p\n", vulkan_ctx->dev->device, vulkan_ctx->dev->queue); } static void vulkan_vid_render_create_context (void) { - vulkan_ctx->create_surface (vulkan_ctx); + vulkan_ctx->create_window (vulkan_ctx); + vulkan_ctx->dev->surface = vulkan_ctx->create_surface (vulkan_ctx); } static void diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c index 7b553d5f6..eba6fa4be 100644 --- a/libs/video/renderer/vulkan/init.c +++ b/libs/video/renderer/vulkan/init.c @@ -56,17 +56,17 @@ static uint32_t numExtensions; static VkExtensionProperties *instanceExtensionProperties; static const char **instanceExtensionNames; -static const char *validationLayers[] = { +const char * const vulkanValidationLayers[] = { "VK_LAYER_LUNARG_standard_validation", 0, }; -static const char *debugExtensions[] = { +static const char * const debugExtensions[] = { VK_EXT_DEBUG_UTILS_EXTENSION_NAME, 0, }; -static const char *device_types[] = { +static const char * const device_types[] = { "other", "integrated gpu", "discrete gpu", @@ -278,28 +278,30 @@ Vulkan_CreateInstance (vulkan_ctx_t *ctx, get_instance_layers_and_extensions (ctx); } - createInfo.enabledLayerCount = count_strings (layers); - createInfo.ppEnabledLayerNames = layers; - createInfo.enabledExtensionCount = count_strings (extensions); - createInfo.ppEnabledExtensionNames = extensions; + uint32_t nlay = count_strings (layers); + uint32_t next = count_strings (extensions) + + count_strings (ctx->required_extensions); if (vulkan_use_validation->int_val) { - createInfo.enabledLayerCount += count_strings (validationLayers); - createInfo.enabledExtensionCount += count_strings (debugExtensions); + nlay += count_strings (vulkanValidationLayers); + next += count_strings (debugExtensions); } - const char **lay = alloca (createInfo.enabledLayerCount * sizeof (const char *)); - const char **ext = alloca (createInfo.enabledExtensionCount * sizeof (const char *)); + const char **lay = alloca (nlay * sizeof (const char *)); + const char **ext = alloca (next * sizeof (const char *)); + // ensure there are null pointers so merge_strings can act as append + // since it does not add a null + memset (lay, 0, nlay * sizeof (const char *)); + memset (ext, 0, next * sizeof (const char *)); + merge_strings (lay, layers, 0); + merge_strings (ext, extensions, ctx->required_extensions); if (vulkan_use_validation->int_val) { - merge_strings (lay, layers, validationLayers); - merge_strings (ext, extensions, debugExtensions); - } else { - merge_strings (lay, layers, 0); - merge_strings (ext, extensions, 0); + merge_strings (lay, lay, vulkanValidationLayers); + merge_strings (ext, ext, debugExtensions); } - prune_strings (instanceLayerNames, lay, - &createInfo.enabledLayerCount); - prune_strings (instanceExtensionNames, ext, - &createInfo.enabledExtensionCount); + prune_strings (instanceLayerNames, lay, &nlay); + prune_strings (instanceExtensionNames, ext, &next); + createInfo.enabledLayerCount = nlay; createInfo.ppEnabledLayerNames = lay; + createInfo.enabledExtensionCount = next; createInfo.ppEnabledExtensionNames = ext; res = ctx->vkCreateInstance (&createInfo, 0, &instance); @@ -348,6 +350,27 @@ Vulkan_DestroyInstance (VulkanInstance_t *instance) free (instance); } +int +Vulkan_LayersSupported (const VkLayerProperties *layers, + int numLayers, + const char * const *requested) +{ + while (*requested) { + int i; + for (i = 0; i < numLayers; i++) { + if (!strcmp (*requested, layers[i].layerName)) { + break; + } + } + if (i == numLayers) { + // requested layer not found + break; + } + requested++; + } + return !*requested; +} + int Vulkan_ExtensionsSupported (const VkExtensionProperties *extensions, int numExtensions, @@ -360,10 +383,11 @@ Vulkan_ExtensionsSupported (const VkExtensionProperties *extensions, break; } } - if (i < numExtensions) { + if (i == numExtensions) { // requested extension not found break; } + requested++; } return !*requested; } diff --git a/libs/video/renderer/vulkan/util.c b/libs/video/renderer/vulkan/util.c index 5603bbd5d..8fa5c2a72 100644 --- a/libs/video/renderer/vulkan/util.c +++ b/libs/video/renderer/vulkan/util.c @@ -36,7 +36,7 @@ #include "util.h" int -count_strings (const char **str) +count_strings (const char * const *str) { int count = 0; @@ -49,7 +49,8 @@ count_strings (const char **str) } void -merge_strings (const char **out, const char **in1, const char **in2) +merge_strings (const char **out, const char * const *in1, + const char * const *in2) { if (in1) { while (*in1) { diff --git a/libs/video/renderer/vulkan/util.h b/libs/video/renderer/vulkan/util.h index 8d1a967a3..0948a1bbd 100644 --- a/libs/video/renderer/vulkan/util.h +++ b/libs/video/renderer/vulkan/util.h @@ -2,8 +2,10 @@ #define __util_h #include -int count_strings (const char **str); -void merge_strings (const char **out, const char **in1, const char **in2); -void prune_strings (const char * const *reference, const char **strings, uint32_t *count); +int count_strings (const char * const *str); +void merge_strings (const char **out, const char * const *in1, + const char * const *in2); +void prune_strings (const char * const *reference, const char **strings, + uint32_t *count); #endif//__util_h diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 96094303a..c7060ef58 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -55,8 +55,7 @@ #include "r_internal.h" #include "vid_vulkan.h" -static VulkanInstance_t *vulkan_instance; -static VulkanDevice_t *vulkan_device; +#include "util.h" void Vulkan_Init_Cvars () @@ -74,6 +73,7 @@ static const char *instance_extensions[] = { }; static const char *device_extensions[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, 0, }; @@ -126,18 +126,61 @@ load_device_funcs (VulkanInstance_t *inst, VulkanDevice_t *dev) #include "QF/Vulkan/funclist.h" } -static VulkanDevice_t * -create_suitable_device (VulkanInstance_t *instance) +void +Vulkan_Init_Common (vulkan_ctx_t *ctx) { - for (uint32_t i = 0; i < instance->numDevices; i++) { - VulkanPhysDevice_t *phys = &instance->devices[i]; + Sys_Printf ("Vulkan_Init_Common\n"); + Vulkan_Init_Cvars (); + + ctx->vtx = Vulkan_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version + ctx->instance = ctx->vtx->instance; +} + +void +Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) +{ + Vulkan_DestroyInstance (ctx->vtx); + ctx->vtx = 0; + ctx->unload_vulkan (ctx); +} + +void +Vulkan_CreateDevice (vulkan_ctx_t *ctx) +{ + VulkanInstance_t *inst = ctx->vtx; + + uint32_t nlay = 1; // ensure alloca doesn't see 0 and terminated + uint32_t next = count_strings (device_extensions) + 1; // ensure terminated + if (vulkan_use_validation->int_val) { + nlay += count_strings (vulkanValidationLayers); + } + const char **lay = alloca (nlay * sizeof (const char *)); + const char **ext = alloca (next * sizeof (const char *)); + // ensure there are null pointers so merge_strings can act as append + // since it does not add a null, but also make sure the counts reflect + // actual numbers + memset (lay, 0, nlay-- * sizeof (const char *)); + memset (ext, 0, next-- * sizeof (const char *)); + merge_strings (ext, device_extensions, 0); + if (vulkan_use_validation->int_val) { + merge_strings (lay, lay, vulkanValidationLayers); + } + + for (uint32_t i = 0; i < inst->numDevices; i++) { + VulkanPhysDevice_t *phys = &inst->devices[i]; + if (!Vulkan_LayersSupported (phys->layers, phys->numLayers, lay)) { + continue; + } if (!Vulkan_ExtensionsSupported (phys->extensions, phys->numExtensions, - device_extensions)) { - return 0; + ext)) { + continue; } int family = find_queue_family (phys, VK_QUEUE_GRAPHICS_BIT); if (family < 0) { - return 0; + continue; + } + if (!ctx->get_presentation_support (ctx, phys->device, family)) { + continue; } float priority = 1; VkDeviceQueueCreateInfo qCreateInfo = { @@ -148,52 +191,20 @@ create_suitable_device (VulkanInstance_t *instance) VkDeviceCreateInfo dCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0, 1, &qCreateInfo, - 0, 0, - 0, device_extensions, + nlay, lay, + next, ext, &features }; memset (&features, 0, sizeof (features)); VulkanDevice_t *device = calloc (1, sizeof (VulkanDevice_t)); - if (instance->vkCreateDevice (phys->device, &dCreateInfo, 0, + if (inst->vkCreateDevice (phys->device, &dCreateInfo, 0, &device->device) == VK_SUCCESS) { - load_device_funcs (instance, device); + load_device_funcs (inst, device); device->vkGetDeviceQueue (device->device, family, 0, &device->queue); - return device; + ctx->dev = device; + ctx->device = device->device; + return; } } - return 0; -} - -int x = 1; - -void -Vulkan_Init_Common (vulkan_ctx_t *ctx) -{ - Sys_Printf ("Vulkan_Init_Common\n"); - Vulkan_Init_Cvars (); - - vulkan_instance = Vulkan_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version - vulkan_device = create_suitable_device (vulkan_instance); - if (!vulkan_device) { - Sys_Error ("no suitable vulkan device found"); - } - // only for now... - Sys_Printf ("%p %p\n", vulkan_device->device, vulkan_device->queue); - Vulkan_Shutdown_Common (ctx); - if (x) - Sys_Quit(); -} - -void -Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) -{ - if (vulkan_device) { - vulkan_device->vkDestroyDevice (vulkan_device->device, 0); - free (vulkan_device); - vulkan_device = 0; - } - Vulkan_DestroyInstance (vulkan_instance); - vulkan_instance = 0; - ctx->unload_vulkan (ctx); } diff --git a/libs/video/targets/vid_x11_vulkan.c b/libs/video/targets/vid_x11_vulkan.c index e472c0c0e..b7b88d1b1 100644 --- a/libs/video/targets/vid_x11_vulkan.c +++ b/libs/video/targets/vid_x11_vulkan.c @@ -110,11 +110,38 @@ unload_vulkan_library (vulkan_ctx_t *ctx) vulkan_library = 0; } +static void +x11_vulkan_init_presentation (vulkan_ctx_t *ctx) +{ + ctx->presentation = calloc (1, sizeof (vulkan_presentation_t)); + vulkan_presentation_t *pres = ctx->presentation; + VkInstance instance = ctx->instance; + +#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) \ + pres->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, #name); \ + if (!pres->name) { \ + Sys_Error ("Couldn't find instance-level function %s", #name); \ + } +#include "QF/Vulkan/funclist.h" + + XVisualInfo template; + Visual *defaultVisual = XDefaultVisual (x_disp, x_screen); + template.visualid = XVisualIDFromVisual (defaultVisual); + int template_mask = VisualIDMask; + pres->display = x_disp; + pres->usable_visuals = set_new (); + pres->visinfo = XGetVisualInfo (x_disp, template_mask, &template, + &pres->num_visuals); +} + static int x11_vulkan_get_presentation_support (vulkan_ctx_t *ctx, VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex) { + if (!ctx->presentation) { + x11_vulkan_init_presentation (ctx); + } vulkan_presentation_t *pres = ctx->presentation; set_empty (pres->usable_visuals); @@ -129,6 +156,25 @@ x11_vulkan_get_presentation_support (vulkan_ctx_t *ctx, return !set_is_empty (pres->usable_visuals); } +static void +x11_vulkan_choose_visual (vulkan_ctx_t *ctx) +{ + vulkan_presentation_t *pres = ctx->presentation; + set_iter_t *first = set_first (pres->usable_visuals); + if (first) { + x_visinfo = pres->visinfo + first->element; + x_vis = x_visinfo->visual; + set_del_iter (first); + } +} + +static void +x11_vulkan_create_window (vulkan_ctx_t *ctx) +{ + vulkan_presentation_t *pres = ctx->presentation; + pres->window = x_win; +} + static VkSurfaceKHR x11_vulkan_create_surface (vulkan_ctx_t *ctx) { @@ -155,6 +201,8 @@ X11_Vulkan_Context (void) ctx->load_vulkan = load_vulkan_library; ctx->unload_vulkan = unload_vulkan_library; ctx->get_presentation_support = x11_vulkan_get_presentation_support; + ctx->choose_visual = x11_vulkan_choose_visual; + ctx->create_window = x11_vulkan_create_window; ctx->create_surface = x11_vulkan_create_surface; ctx->required_extensions = required_extensions; return ctx; From 8a3cd224a36a9bb1c8fba84e5e77113c3d7f3fe3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 20:14:30 +0900 Subject: [PATCH 019/435] Add vulkan developer flag --- include/QF/sys.h | 1 + libs/video/renderer/vulkan/init.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/QF/sys.h b/include/QF/sys.h index f93432d65..4dd61bacd 100644 --- a/include/QF/sys.h +++ b/include/QF/sys.h @@ -97,6 +97,7 @@ void Sys_MaskPrintf (int mask, const char *fmt, ...) __attribute__((format(print #define SYS_GLSL (1|2048) #define SYS_SKIN (1|4096) #define SYS_MODEL (1|8192) +#define SYS_VULKAN (1|16384) int Sys_CheckInput (int idle, int net_socket); const char *Sys_ConsoleInput (void); diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c index eba6fa4be..19091bb8a 100644 --- a/libs/video/renderer/vulkan/init.c +++ b/libs/video/renderer/vulkan/init.c @@ -102,7 +102,7 @@ get_instance_layers_and_extensions (vulkan_ctx_t *ctx) } instanceExtensionNames[i] = 0; - if (developer->int_val & SYS_VID) { + if (developer->int_val & SYS_VULKAN) { for (i = 0; i < numLayers; i++) { Sys_Printf ("%s %x %u %s\n", properties[i].layerName, @@ -154,7 +154,7 @@ init_physdev (VulkanInstance_t *instance, VkPhysicalDevice dev, VulkanPhysDevice &physdev->numQueueFamilies, physdev->queueFamilies); - if (developer->int_val & SYS_VID) { + if (developer->int_val & SYS_VULKAN) { VkPhysicalDeviceProperties *prop = &physdev->properties; Sys_Printf ("dev: %p\n", dev); Sys_Printf (" %x %x\n", prop->apiVersion, prop->driverVersion); From 8c238d3def13ef509272f2f9889d57aa00fe4eaa Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 20:14:57 +0900 Subject: [PATCH 020/435] Parse developer flag names when cvar is set So much easier to remember "vulkan" instead of which power of two it is. --- libs/util/cvar.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/libs/util/cvar.c b/libs/util/cvar.c index 64ef200ab..3b30b00f9 100644 --- a/libs/util/cvar.c +++ b/libs/util/cvar.c @@ -37,6 +37,7 @@ # include #endif +#include #include #include @@ -327,6 +328,82 @@ Cvar_WriteVariables (QFile *f) Qprintf (f, "seta %s \"%s\"\n", var->name, var->string); } +// XXX make sure in sync with SYS_* in sys.h +static const char *developer_flags[] = { + "dev", + "warn", + "vid", + "fs_nf", + "fs_f", + "fs", + "net", + "rua_obj", + "rua_msg", + "snd", + "glt", + "glsl", + "skin", + "model", + "vulkan", + 0 +}; + +static int +parse_developer_flag (const char *flag) +{ + const char **devflag; + char *end; + int val; + + val = strtol (flag, &end, 0); + if (!*end) { + return val; + } + for (devflag = developer_flags; *devflag; devflag++) { + if (!strcmp (*devflag, flag)) { + return 1 << (devflag - developer_flags); + } + } + return 0; +} + +static void +developer_f (cvar_t *var) +{ + char *buf = alloca (strlen (var->string) + 1); + const char *s; + char *b; + char c; + int parse = 0; + + for (s = var->string; *s; s++) { + if (isalpha (*s) || *s == '|') { + parse = 1; + break; + } + } + if (!parse) { + return; + } + var->int_val = 0; + for (s = var->string, b = buf; (c = *s++); ) { + if (isspace (c)) { + continue; + } + if (c == '|') { + *b = 0; + var->int_val |= parse_developer_flag (buf); + b = buf; + continue; + } + *b++ = c; + } + if (b != buf) { + *b = 0; + var->int_val |= parse_developer_flag (buf); + } +} + static void set_cvar (const char *cmd, int orflags) { @@ -587,7 +664,7 @@ Cvar_Init_Hash (void) VISIBLE void Cvar_Init (void) { - developer = Cvar_Get ("developer", "0", CVAR_NONE, NULL, + developer = Cvar_Get ("developer", "0", CVAR_NONE, developer_f, "set to enable extra debugging information"); Cmd_AddCommand ("set", Cvar_Set_f, "Set the selected variable, useful on " From 452eb5a83d85db2d0c38215472fde386f8696aff Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 20:16:08 +0900 Subject: [PATCH 021/435] Preserve parsed cvar values when string is same Fixes parsed developer flags on the command line getting reset. --- libs/util/cvar.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/libs/util/cvar.c b/libs/util/cvar.c index 3b30b00f9..e3e14236f 100644 --- a/libs/util/cvar.c +++ b/libs/util/cvar.c @@ -264,19 +264,21 @@ Cvar_Set (cvar_t *var, const char *value) } changed = !strequal (var->string, value); - free ((char*)var->string); // free the old value string + if (changed) { + free ((char*)var->string); // free the old value string - var->string = strdup (value); - var->value = atof (var->string); - var->int_val = atoi (var->string); - VectorZero (var->vec); - vals = sscanf (var->string, "%f %f %f", - &var->vec[0], &var->vec[1], &var->vec[2]); - if (vals == 1) - var->vec[2] = var->vec[1] = var->vec[0]; + var->string = strdup (value); + var->value = atof (var->string); + var->int_val = atoi (var->string); + VectorZero (var->vec); + vals = sscanf (var->string, "%f %f %f", + &var->vec[0], &var->vec[1], &var->vec[2]); + if (vals == 1) + var->vec[2] = var->vec[1] = var->vec[0]; - if (changed && var->callback) - var->callback (var); + if (var->callback) + var->callback (var); + } } VISIBLE void From 3191604641aba1e4775fabc4c4565c81e6719039 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 21:07:59 +0900 Subject: [PATCH 022/435] Uncomment already implemented functions --- libs/video/renderer/vid_render_vulkan.c | 62 ++++++++++++------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index c09bfe5e4..693a85d14 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -49,29 +49,29 @@ static vulkan_ctx_t *vulkan_ctx; static vid_model_funcs_t model_funcs = { -/* vulkan_Mod_LoadExternalTextures, - vulkan_Mod_LoadLighting, - vulkan_Mod_SubdivideSurface, - vulkan_Mod_ProcessTexture, + 0,//vulkan_Mod_LoadExternalTextures, + 0,//vulkan_Mod_LoadLighting, + 0,//vulkan_Mod_SubdivideSurface, + 0,//vulkan_Mod_ProcessTexture, Mod_LoadIQM, Mod_LoadAliasModel, Mod_LoadSpriteModel, - vulkan_Mod_MakeAliasModelDisplayLists, - vulkan_Mod_LoadSkin, - vulkan_Mod_FinalizeAliasModel, - vulkan_Mod_LoadExternalSkins, - vulkan_Mod_IQMFinish, + 0,//vulkan_Mod_MakeAliasModelDisplayLists, + 0,//vulkan_Mod_LoadSkin, + 0,//vulkan_Mod_FinalizeAliasModel, + 0,//vulkan_Mod_LoadExternalSkins, + 0,//vulkan_Mod_IQMFinish, 0, - vulkan_Mod_SpriteLoadTexture, + 0,//vulkan_Mod_SpriteLoadTexture, Skin_SetColormap, Skin_SetSkin, - vulkan_Skin_SetupSkin, + 0,//vulkan_Skin_SetupSkin, Skin_SetTranslation, - vulkan_Skin_ProcessTranslation, - vulkan_Skin_InitTranslations,*/ + 0,//vulkan_Skin_ProcessTranslation, + 0,//vulkan_Skin_InitTranslations, }; vid_render_funcs_t vulkan_vid_render_funcs = { @@ -97,37 +97,37 @@ vid_render_funcs_t vulkan_vid_render_funcs = { vulkan_Draw_Picf, vulkan_Draw_SubPic, -/* vulkan_SCR_UpdateScreen, + 0,//vulkan_SCR_UpdateScreen, SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, - vulkan_SCR_CaptureBGR, - vulkan_SCR_ScreenShot, + 0,//vulkan_SCR_CaptureBGR, + 0,//vulkan_SCR_ScreenShot, SCR_DrawStringToSnap, - vulkan_Fog_Update, - vulkan_Fog_ParseWorldspawn, + 0,//vulkan_Fog_Update, + 0,//vulkan_Fog_ParseWorldspawn, - vulkan_R_Init, - vulkan_R_ClearState, - vulkan_R_LoadSkys, - vulkan_R_NewMap, + 0,//vulkan_R_Init, + 0,//vulkan_R_ClearState, + 0,//vulkan_R_LoadSkys, + 0,//vulkan_R_NewMap, R_AddEfrags, R_RemoveEfrags, R_EnqueueEntity, - vulkan_R_LineGraph, + 0,//vulkan_R_LineGraph, R_AllocDlight, R_AllocEntity, - vulkan_R_RenderView, + 0,//vulkan_R_RenderView, R_DecayLights, - vulkan_R_ViewChanged, - vulkan_R_ClearParticles, - vulkan_R_InitParticles, - vulkan_SCR_ScreenShot_f, - vulkan_r_easter_eggs_f, - vulkan_r_particles_style_f, + 0,//vulkan_R_ViewChanged, + 0,//vulkan_R_ClearParticles, + 0,//vulkan_R_InitParticles, + 0,//vulkan_SCR_ScreenShot_f, + 0,//vulkan_r_easter_eggs_f, + 0,//vulkan_r_particles_style_f, 0, - &model_funcs*/ + &model_funcs }; static void From 31ead15e9688bde056a91967a200915d10f6f149 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Jul 2019 22:04:48 +0900 Subject: [PATCH 023/435] Add comment about developer flags --- include/QF/sys.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/QF/sys.h b/include/QF/sys.h index 4dd61bacd..7c669563e 100644 --- a/include/QF/sys.h +++ b/include/QF/sys.h @@ -83,6 +83,7 @@ double Sys_DoubleTime (void); void Sys_TimeOfDay(date_t *date); void Sys_MaskPrintf (int mask, const char *fmt, ...) __attribute__((format(printf,2,3))); +// remember to update developer_flags in cvar.c #define SYS_DEV (1|0) #define SYS_WARN (1|2) // bit 0 so developer 1 will pick it up #define SYS_VID (1|4) From ed3c5cb9ec0fc47abd29a597c2d91b73505d7bff Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Jul 2019 13:09:16 +0900 Subject: [PATCH 024/435] Add a strset "class" It's just a wrapper around hashtab, but it makes checking if a string is in a set easy. Way overkill when only a few extensions are enabled, but more might come later. --- libs/video/renderer/vulkan/util.c | 27 +++++++++++++++++++++++++++ libs/video/renderer/vulkan/util.h | 5 +++++ 2 files changed, 32 insertions(+) diff --git a/libs/video/renderer/vulkan/util.c b/libs/video/renderer/vulkan/util.c index 8fa5c2a72..09e1b146a 100644 --- a/libs/video/renderer/vulkan/util.c +++ b/libs/video/renderer/vulkan/util.c @@ -33,8 +33,35 @@ # include #endif +#include "QF/hash.h" + #include "util.h" +static const char * +strset_get_key (const void *_str, void *unused) +{ + return (const char *)_str; +} + +strset_t * +new_strset (const char * const *strings) +{ + hashtab_t *tab = Hash_NewTable (61, strset_get_key, 0, 0); + for ( ; *strings; strings++) { + Hash_Add (tab, (void *) *strings); + } + return (strset_t *) tab; +} +void del_strset (strset_t *strset) +{ + Hash_DelTable ((hashtab_t *) strset); +} + +int strset_contains (strset_t *strset, const char *str) +{ + return Hash_Find ((hashtab_t *) strset, str) != 0; +} + int count_strings (const char * const *str) { diff --git a/libs/video/renderer/vulkan/util.h b/libs/video/renderer/vulkan/util.h index 0948a1bbd..a15aac4c8 100644 --- a/libs/video/renderer/vulkan/util.h +++ b/libs/video/renderer/vulkan/util.h @@ -8,4 +8,9 @@ void merge_strings (const char **out, const char * const *in1, void prune_strings (const char * const *reference, const char **strings, uint32_t *count); +typedef struct strset_s strset_t; +strset_t *new_strset (const char * const *strings); +void del_strset (strset_t *strset); +int strset_contains (strset_t *strset, const char *str); + #endif//__util_h From 2771e9c5736b5e96e313e40a59c0c93a128c8d2d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Jul 2019 13:16:46 +0900 Subject: [PATCH 025/435] Correct extension handling I had missed a critical bit from the cookbook. --- include/QF/Vulkan/funclist.h | 49 ++++++++++++------- include/QF/Vulkan/init.h | 15 +++--- include/vid_vulkan.h | 4 ++ libs/video/renderer/vid_render_vulkan.c | 10 +++- libs/video/renderer/vulkan/init.c | 30 +++++++++--- .../video/renderer/vulkan/vulkan_vid_common.c | 12 +++-- libs/video/targets/vid_x11_vulkan.c | 13 +++-- 7 files changed, 91 insertions(+), 42 deletions(-) diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 79af14277..e54ce6f50 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -21,16 +21,6 @@ GLOBAL_LEVEL_VULKAN_FUNCTION (vkCreateInstance) #define INSTANCE_LEVEL_VULKAN_FUNCTION(function) #endif -#if defined(VK_USE_PLATFORM_XLIB_KHR) -INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceXlibPresentationSupportKHR) -INSTANCE_LEVEL_VULKAN_FUNCTION (vkCreateXlibSurfaceKHR) -#elif defined(VK_USE_PLATFORM_WIN32_KHR) -INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceWin32PresentationSupportKHR) -INSTANCE_LEVEL_VULKAN_FUNCTION (vkCreateWin32SurfaceKHR) -#elif defined(VK_USE_PLATFORM_XCB_KHR) -INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceXcbPresentationSupportKHR) -INSTANCE_LEVEL_VULKAN_FUNCTION (vkCreateXcbSurfaceKHR) -#else INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumeratePhysicalDevices) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceFeatures) @@ -41,17 +31,40 @@ INSTANCE_LEVEL_VULKAN_FUNCTION (vkDestroyInstance) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceLayerProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceExtensionProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceMemoryProperties) -#endif #undef INSTANCE_LEVEL_VULKAN_FUNCTION -#ifndef INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION -#define INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION(function) +#ifndef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(function, extension) #endif -INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION (vkCreateDebugUtilsMessengerEXT) +#if defined(VK_USE_PLATFORM_XLIB_KHR) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceXlibPresentationSupportKHR, + VK_KHR_XLIB_SURFACE_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateXlibSurfaceKHR, + VK_KHR_XLIB_SURFACE_EXTENSION_NAME) +#elif defined(VK_USE_PLATFORM_WIN32_KHR) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceWin32PresentationSupportKHR, + VK_KHR_WIN32_SURFACE_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateWin32SurfaceKHR, + VK_KHR_WIN32_SURFACE_EXTENSION_NAME) +#elif defined(VK_USE_PLATFORM_XCB_KHR) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceXcbPresentationSupportKHR, + VK_KHR_XCB_SURFACE_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateXcbSurfaceKHR, + VK_KHR_XCB_SURFACE_EXTENSION_NAME) +#else +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) +#endif -#undef INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION +#undef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION #ifndef DEVICE_LEVEL_VULKAN_FUNCTION #define DEVICE_LEVEL_VULKAN_FUNCTION(function) @@ -62,8 +75,8 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkGetDeviceQueue) #undef DEVICE_LEVEL_VULKAN_FUNCTION -#ifndef DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION -#define DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION(function) +#ifndef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION +#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(function, extension) #endif -#undef DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION +#undef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION diff --git a/include/QF/Vulkan/init.h b/include/QF/Vulkan/init.h index 3afab0179..961c72d84 100644 --- a/include/QF/Vulkan/init.h +++ b/include/QF/Vulkan/init.h @@ -35,9 +35,9 @@ typedef struct VulkanDevice_s { VkQueue queue; VkSurfaceKHR surface; - #define DEVICE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; - #define DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) PFN_##name name; - #include "QF/Vulkan/funclist.h" +#define DEVICE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; +#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; +#include "QF/Vulkan/funclist.h" } VulkanDevice_t; typedef struct { @@ -55,13 +55,16 @@ typedef struct { typedef struct VulkanInstance_s { VkInstance instance; + struct strset_s *enabled_extensions; + int (*extension_enabled) (struct VulkanInstance_s *inst, + const char *ext); VkDebugUtilsMessengerEXT debug_callback; uint32_t numDevices; VulkanPhysDevice_t *devices; - #define INSTANCE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; - #define INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) PFN_##name name; - #include "QF/Vulkan/funclist.h" +#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; +#include "QF/Vulkan/funclist.h" } VulkanInstance_t; extern const char * const vulkanValidationLayers[]; diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 387a82078..924a3a1d4 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -6,11 +6,14 @@ #endif #include +struct VulkanInstance_s; typedef struct vulkan_ctx_s { void (*load_vulkan) (struct vulkan_ctx_s *ctx); void (*unload_vulkan) (struct vulkan_ctx_s *ctx); const char **required_extensions; + int (*extension_enabled) (struct VulkanInstance_s *inst, + const char *ext); struct vulkan_presentation_s *presentation; int (*get_presentation_support) (struct vulkan_ctx_s *ctx, VkPhysicalDevice physicalDevice, @@ -22,6 +25,7 @@ typedef struct vulkan_ctx_s { struct VulkanInstance_s *vtx; struct VulkanDevice_s *dev; VkInstance instance; + VkPhysicalDevice physDevice; VkDevice device; #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 693a85d14..11fe640f2 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -48,6 +48,13 @@ static vulkan_ctx_t *vulkan_ctx; +static void +vulkan_R_Init (void) +{ + if (vulkan_ctx) + Sys_Quit (); +} + static vid_model_funcs_t model_funcs = { 0,//vulkan_Mod_LoadExternalTextures, 0,//vulkan_Mod_LoadLighting, @@ -108,7 +115,7 @@ vid_render_funcs_t vulkan_vid_render_funcs = { 0,//vulkan_Fog_Update, 0,//vulkan_Fog_ParseWorldspawn, - 0,//vulkan_R_Init, + vulkan_R_Init, 0,//vulkan_R_ClearState, 0,//vulkan_R_LoadSkys, 0,//vulkan_R_NewMap, @@ -151,6 +158,7 @@ vulkan_vid_render_create_context (void) { vulkan_ctx->create_window (vulkan_ctx); vulkan_ctx->dev->surface = vulkan_ctx->create_surface (vulkan_ctx); + Sys_Printf ("%p\n", vulkan_ctx->dev->surface); } static void diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c index 19091bb8a..529969014 100644 --- a/libs/video/renderer/vulkan/init.c +++ b/libs/video/renderer/vulkan/init.c @@ -198,6 +198,12 @@ init_physdev (VulkanInstance_t *instance, VkPhysicalDevice dev, VulkanPhysDevice } } +static int +instance_extension_enabled (VulkanInstance_t *inst, const char *ext) +{ + return strset_contains (inst->enabled_extensions, ext); +} + static int message_severities = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | @@ -242,10 +248,13 @@ load_instance_funcs (vulkan_ctx_t *ctx) Sys_Error ("Couldn't find instance level function %s", #name); \ } -#define INSTANCE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) \ - vtx->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, #name); \ - if (!vtx->name) { \ - Sys_Printf ("Couldn't find instance level function %s", #name); \ +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ + if (vtx->extension_enabled (vtx, ext)) { \ + vtx->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, \ + #name); \ + if (!vtx->name) { \ + Sys_Error ("Couldn't find instance level function %s", #name); \ + } \ } #include "QF/Vulkan/funclist.h" @@ -278,9 +287,9 @@ Vulkan_CreateInstance (vulkan_ctx_t *ctx, get_instance_layers_and_extensions (ctx); } - uint32_t nlay = count_strings (layers); + uint32_t nlay = count_strings (layers) + 1; uint32_t next = count_strings (extensions) - + count_strings (ctx->required_extensions); + + count_strings (ctx->required_extensions) + 1; if (vulkan_use_validation->int_val) { nlay += count_strings (vulkanValidationLayers); next += count_strings (debugExtensions); @@ -289,8 +298,8 @@ Vulkan_CreateInstance (vulkan_ctx_t *ctx, const char **ext = alloca (next * sizeof (const char *)); // ensure there are null pointers so merge_strings can act as append // since it does not add a null - memset (lay, 0, nlay * sizeof (const char *)); - memset (ext, 0, next * sizeof (const char *)); + memset (lay, 0, nlay-- * sizeof (const char *)); + memset (ext, 0, next-- * sizeof (const char *)); merge_strings (lay, layers, 0); merge_strings (ext, extensions, ctx->required_extensions); if (vulkan_use_validation->int_val) { @@ -299,6 +308,8 @@ Vulkan_CreateInstance (vulkan_ctx_t *ctx, } prune_strings (instanceLayerNames, lay, &nlay); prune_strings (instanceExtensionNames, ext, &next); + lay[nlay] = 0; + ext[next] = 0; createInfo.enabledLayerCount = nlay; createInfo.ppEnabledLayerNames = lay; createInfo.enabledExtensionCount = next; @@ -310,6 +321,9 @@ Vulkan_CreateInstance (vulkan_ctx_t *ctx, } inst = malloc (sizeof(VulkanInstance_t)); inst->instance = instance; + inst->enabled_extensions = new_strset (ext); + inst->extension_enabled = instance_extension_enabled; + ctx->extension_enabled = instance_extension_enabled; ctx->vtx = inst; load_instance_funcs (ctx); diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index c7060ef58..561eb64f5 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -117,10 +117,13 @@ load_device_funcs (VulkanInstance_t *inst, VulkanDevice_t *dev) Sys_Error ("Couldn't find device level function %s", #name); \ } -#define DEVICE_LEVEL_VULKAN_FUNCTION_EXTENSION(name) \ - dev->name = (PFN_##name) inst->vkGetDeviceProcAddr (dev->device, #name); \ - if (!dev->name) { \ - Sys_Printf ("Couldn't find device level function %s", #name); \ +#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ + if (inst->extension_enabled (vtx, ext)) { \ + dev->name = (PFN_##name) inst->vkGetDeviceProcAddr (dev->device, \ + #name); \ + if (!dev->name) { \ + Sys_Printf ("Couldn't find device level function %s", #name); \ + } \ } #include "QF/Vulkan/funclist.h" @@ -204,6 +207,7 @@ Vulkan_CreateDevice (vulkan_ctx_t *ctx) 0, &device->queue); ctx->dev = device; ctx->device = device->device; + ctx->physDevice = phys->device; return; } } diff --git a/libs/video/targets/vid_x11_vulkan.c b/libs/video/targets/vid_x11_vulkan.c index b7b88d1b1..812e74dad 100644 --- a/libs/video/targets/vid_x11_vulkan.c +++ b/libs/video/targets/vid_x11_vulkan.c @@ -61,7 +61,7 @@ static cvar_t *vulkan_library_name; typedef struct vulkan_presentation_s { -#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; #include "QF/Vulkan/funclist.h" Display *display; @@ -117,10 +117,13 @@ x11_vulkan_init_presentation (vulkan_ctx_t *ctx) vulkan_presentation_t *pres = ctx->presentation; VkInstance instance = ctx->instance; -#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) \ - pres->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, #name); \ - if (!pres->name) { \ - Sys_Error ("Couldn't find instance-level function %s", #name); \ +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ + if (ctx->extension_enabled (ctx->vtx, ext)) { \ + pres->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, \ + #name); \ + if (!pres->name) { \ + Sys_Error ("Couldn't find instance-level function %s", #name); \ + } \ } #include "QF/Vulkan/funclist.h" From d5cb4329112dcb766bbd337edd6bac4b1bc63e79 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Jul 2019 22:15:39 +0900 Subject: [PATCH 026/435] Add a cvar to block use of x11 vidmode Or really, allow it if the user specifically requests it: the default is blocked. Modern systems (particularly displays) do not really like changing resolution, so doing so by default seems rather wrong. --- libs/video/targets/context_x11.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libs/video/targets/context_x11.c b/libs/video/targets/context_x11.c index 41045fcdf..5c23d1875 100644 --- a/libs/video/targets/context_x11.c +++ b/libs/video/targets/context_x11.c @@ -125,6 +125,8 @@ static int accel_threshold; static Atom x_net_state; static Atom x_net_fullscreen; +static cvar_t *x11_vidmode; + static void set_fullscreen (int full) { @@ -387,6 +389,10 @@ X11_SetVidMode (int width, int height) if (vidmode_active) return; + if (!x11_vidmode->int_val) { + return; + } + if (str && (tolower (*str) == 'f')) { Cvar_Set (vid_fullscreen, "1"); } @@ -506,6 +512,9 @@ X11_Init_Cvars (void) "Toggles fullscreen game mode"); vid_system_gamma = Cvar_Get ("vid_system_gamma", "1", CVAR_ARCHIVE, NULL, "Use system gamma control if available"); + x11_vidmode = Cvar_Get ("x11_vidmode", "0", CVAR_ROM, 0, + "Use x11 vidmode extension to set video mode " + "(not recommended for modern systems)"); } void From 203d981675fe869fc3eb171ce28b6365d189a045 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Jul 2019 22:18:51 +0900 Subject: [PATCH 027/435] Wait for the window to be visible before mouse warping This fixes the hang during fullscreen startup on my system (the motion events weren't being generated because there was no window to see the motion). --- libs/video/targets/context_x11.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/video/targets/context_x11.c b/libs/video/targets/context_x11.c index 5c23d1875..5a6556ce0 100644 --- a/libs/video/targets/context_x11.c +++ b/libs/video/targets/context_x11.c @@ -574,10 +574,11 @@ X11_CreateWindow (int width, int height) X11_WaitForEvent (ConfigureNotify); vid_context_created = true; + XRaiseWindow (x_disp, x_win); + X11_WaitForEvent (VisibilityNotify); if (vid_fullscreen->int_val) { X11_UpdateFullscreen (vid_fullscreen); } - XRaiseWindow (x_disp, x_win); } void From 4eb6cf6f9ebd1633c57edfc2f6f0667fa7a83912 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Jul 2019 22:24:11 +0900 Subject: [PATCH 028/435] Make SetMouse timeout after 2 seconds This makes sure that some unchecked event doesn't cause a lockup. However, blocking input is really not the way to go: need to implement a state machine and use non-blocking event reads. --- libs/video/targets/context_x11.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/video/targets/context_x11.c b/libs/video/targets/context_x11.c index 5a6556ce0..614f83ebd 100644 --- a/libs/video/targets/context_x11.c +++ b/libs/video/targets/context_x11.c @@ -354,7 +354,14 @@ X11_SetMouse (void) XWarpPointer (x_disp, None, x_win, 0, 0, 0, 0, 0, 0); XWarpPointer (x_disp, None, x_win, 0, 0, 0, 0, viddef.width / 2, viddef.height / 2); - XPeekIfEvent (x_disp, &ev, check_mouse_event, 0); + //FIXME this should be done in a state machine that handles events without + //blocking + double start = Sys_DoubleTime (); + while (!XCheckIfEvent (x_disp, &ev, check_mouse_event, 0)) { + if (Sys_DoubleTime () - start > 2) { + break; + } + } x_mouse_time = ev.xmotion.time; } From c0bc5cfad609891e383f0a5c25f4d6dc4230acf6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 11 Jul 2019 00:58:14 +0900 Subject: [PATCH 029/435] Implement swapchain creation --- include/QF/Vulkan/funclist.h | 15 ++ include/QF/Vulkan/init.h | 1 + include/QF/Vulkan/qf_vid.h | 1 + include/vid_vulkan.h | 3 + libs/video/renderer/vid_render_vulkan.c | 7 + .../video/renderer/vulkan/vulkan_vid_common.c | 140 +++++++++++++++++- 6 files changed, 166 insertions(+), 1 deletion(-) diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index e54ce6f50..8418aeb6a 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -62,6 +62,14 @@ INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION #else INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkCreateDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceSurfaceSupportKHR, VK_KHR_SURFACE_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceSurfacePresentModesKHR, VK_KHR_SURFACE_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceSurfaceCapabilitiesKHR, VK_KHR_SURFACE_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceSurfaceFormatsKHR, VK_KHR_SURFACE_EXTENSION_NAME) #endif #undef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION @@ -79,4 +87,11 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkGetDeviceQueue) #define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(function, extension) #endif +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateSwapchainKHR, VK_KHR_SURFACE_EXTENSION_NAME) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkDestroySwapchainKHR, VK_KHR_SURFACE_EXTENSION_NAME) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetSwapchainImagesKHR, VK_KHR_SURFACE_EXTENSION_NAME) + #undef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION diff --git a/include/QF/Vulkan/init.h b/include/QF/Vulkan/init.h index 961c72d84..0988dd25a 100644 --- a/include/QF/Vulkan/init.h +++ b/include/QF/Vulkan/init.h @@ -32,6 +32,7 @@ typedef struct VulkanDevice_s { VkDevice device; + int32_t queueFamily; VkQueue queue; VkSurfaceKHR surface; diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index 877bebaa3..fe04da536 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -31,6 +31,7 @@ #include "QF/Vulkan/cvars.h" struct vulkan_ctx_s; +void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx); void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx); void Vulkan_Init_Common (struct vulkan_ctx_s *ctx); void Vulkan_Shutdown_Common (struct vulkan_ctx_s *ctx); diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 924a3a1d4..fabaa088b 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -27,6 +27,9 @@ typedef struct vulkan_ctx_s { VkInstance instance; VkPhysicalDevice physDevice; VkDevice device; + VkSwapchainKHR swapchain; + int32_t numSwapchainImages; + VkImage *swapchainImages; #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; #include "QF/Vulkan/funclist.h" diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 11fe640f2..46d475917 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -159,6 +159,13 @@ vulkan_vid_render_create_context (void) vulkan_ctx->create_window (vulkan_ctx); vulkan_ctx->dev->surface = vulkan_ctx->create_surface (vulkan_ctx); Sys_Printf ("%p\n", vulkan_ctx->dev->surface); + Vulkan_CreateSwapchain (vulkan_ctx); + Sys_Printf ("%p %d", vulkan_ctx->swapchain, + vulkan_ctx->numSwapchainImages); + for (int32_t i = 0; i < vulkan_ctx->numSwapchainImages; i++) { + Sys_Printf (" %p", vulkan_ctx->swapchainImages[i]); + } + Sys_Printf ("\n"); } static void diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 561eb64f5..22ce1d71e 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -42,6 +42,7 @@ #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/input.h" +#include "QF/mathlib.h" #include "QF/qargs.h" #include "QF/quakefs.h" #include "QF/sys.h" @@ -57,6 +58,25 @@ #include "util.h" +static cvar_t *vulkan_presentation_mode; + +static void +vulkan_presentation_mode_f (cvar_t *var) +{ + if (!strcmp (var->string, "immediate")) { + var->int_val = VK_PRESENT_MODE_IMMEDIATE_KHR; + } else if (!strcmp (var->string, "fifo")) { + var->int_val = VK_PRESENT_MODE_FIFO_KHR; + } else if (!strcmp (var->string, "relaxed")) { + var->int_val = VK_PRESENT_MODE_FIFO_RELAXED_KHR; + } else if (!strcmp (var->string, "mailbox")) { + var->int_val = VK_PRESENT_MODE_MAILBOX_KHR; + } else { + Sys_Printf ("Invalid presentation mode, using fifo\n"); + var->int_val = VK_PRESENT_MODE_FIFO_KHR; + } +} + void Vulkan_Init_Cvars () { @@ -65,6 +85,11 @@ Vulkan_Init_Cvars () "enable LunarG Standard Validation " "Layer if available (requires instance " "restart)."); + // FIXME implement fallback choices (instead of just fifo) + vulkan_presentation_mode = Cvar_Get ("vulkan_presentation_mode", "mailbox", + CVAR_NONE, vulkan_presentation_mode_f, + "desired presentation mode (may fall " + "back to fifo)."); } static const char *instance_extensions[] = { @@ -118,7 +143,7 @@ load_device_funcs (VulkanInstance_t *inst, VulkanDevice_t *dev) } #define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ - if (inst->extension_enabled (vtx, ext)) { \ + if (inst->extension_enabled (inst, ext)) { \ dev->name = (PFN_##name) inst->vkGetDeviceProcAddr (dev->device, \ #name); \ if (!dev->name) { \ @@ -208,7 +233,120 @@ Vulkan_CreateDevice (vulkan_ctx_t *ctx) ctx->dev = device; ctx->device = device->device; ctx->physDevice = phys->device; + device->queueFamily = family; return; } } } + +void +Vulkan_CreateSwapchain (vulkan_ctx_t *ctx) +{ + VkBool32 supported; + ctx->vtx->vkGetPhysicalDeviceSurfaceSupportKHR (ctx->physDevice, + ctx->dev->queueFamily, + ctx->dev->surface, + &supported); + if (!supported) { + Sys_Error ("unsupported surface for swapchain"); + } + uint32_t numModes; + VkPresentModeKHR *modes; + VkPresentModeKHR useMode = VK_PRESENT_MODE_FIFO_KHR;; + ctx->vtx->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->physDevice, + ctx->dev->surface, + &numModes, 0); + modes = alloca (numModes * sizeof (VkPresentModeKHR)); + ctx->vtx->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->physDevice, + ctx->dev->surface, + &numModes, modes); + for (uint32_t i = 0; i < numModes; i++) { + if ((int) modes[i] == vulkan_presentation_mode->int_val) { + useMode = modes[i]; + } + } + Sys_MaskPrintf (SYS_VULKAN, "presentation mode: %d (%d)\n", useMode, + vulkan_presentation_mode->int_val); + + VkSurfaceCapabilitiesKHR surfCaps; + ctx->vtx->vkGetPhysicalDeviceSurfaceCapabilitiesKHR (ctx->physDevice, + ctx->dev->surface, + &surfCaps); + uint32_t numImages = surfCaps.minImageCount + 1; + if (surfCaps.maxImageCount > 0 && numImages > surfCaps.maxImageCount) { + numImages = surfCaps.maxImageCount; + } + + VkExtent2D imageSize = {viddef.width, viddef.height}; + if (surfCaps.currentExtent.width == ~0u) { + imageSize.width = bound (surfCaps.minImageExtent.width, + imageSize.width, + surfCaps.maxImageExtent.width); + imageSize.height = bound (surfCaps.minImageExtent.height, + imageSize.height, + surfCaps.maxImageExtent.height); + } else { + imageSize = surfCaps.currentExtent; + } + Sys_MaskPrintf (SYS_VULKAN, "%d [%d, %d]\n", numImages, + imageSize.width, imageSize.height); + + VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageUsage &= surfCaps.supportedUsageFlags; + + VkSurfaceTransformFlagBitsKHR surfTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + + uint32_t numFormats; + ctx->vtx->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->physDevice, + ctx->dev->surface, + &numFormats, 0); + VkSurfaceFormatKHR *formats = alloca (numFormats * sizeof (*formats)); + ctx->vtx->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->physDevice, + ctx->dev->surface, + &numFormats, formats); + VkSurfaceFormatKHR useFormat = {VK_FORMAT_R8G8B8A8_UNORM, + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}; + if (numFormats > 1) { + uint32_t i; + for (i = 0; i < numFormats; i++) { + if (formats[i].format == useFormat.format + && formats[i].colorSpace == useFormat.colorSpace) { + break; + } + } + if (i == numFormats) { + useFormat = formats[0]; + } + } else if (numFormats == 1 && formats[0].format != VK_FORMAT_UNDEFINED) { + useFormat = formats[0]; + } + + VkSwapchainCreateInfoKHR createInfo = { + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 0, 0, + ctx->dev->surface, + numImages, + useFormat.format, useFormat.colorSpace, + imageSize, + 1, // array layers + imageUsage, + VK_SHARING_MODE_EXCLUSIVE, + 0, 0, + surfTransform, + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + useMode, + VK_TRUE, + ctx->swapchain + }; + VkSwapchainKHR swapchain; + ctx->dev->vkCreateSwapchainKHR (ctx->device, &createInfo, 0, &swapchain); + if (ctx->swapchain != swapchain) { + ctx->dev->vkDestroySwapchainKHR (ctx->device, ctx->swapchain, 0); + } + ctx->swapchain = swapchain; + + ctx->dev->vkGetSwapchainImagesKHR (ctx->device, swapchain, &numImages, 0); + ctx->swapchainImages = malloc (numImages * sizeof (*ctx->swapchainImages)); + ctx->dev->vkGetSwapchainImagesKHR (ctx->device, swapchain, &numImages, + ctx->swapchainImages); + ctx->numSwapchainImages = numImages; +} From b5828bc2cefb98e59f533a0bcd8b7dec2ebfbbde Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 11 Jul 2019 00:58:37 +0900 Subject: [PATCH 030/435] Output validation message severity It's nice knowing if something is an error or otherwise. --- libs/video/renderer/vulkan/init.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c index 529969014..2ba5bfc06 100644 --- a/libs/video/renderer/vulkan/init.c +++ b/libs/video/renderer/vulkan/init.c @@ -219,7 +219,20 @@ debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void *data) { - fprintf (stderr, "validation layer: %s\n", callbackData->pMessage); + const char *msgSev = ""; + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { + msgSev = "verbose: "; + } + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { + msgSev = "info: "; + } + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + msgSev = "warning: "; + } + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + msgSev = "error: "; + } + fprintf (stderr, "validation layer: %s%s\n", msgSev, callbackData->pMessage); return VK_FALSE; } From 75f19f724373afb7e6fa0bc00fdda6815f3eb127 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 12 Jul 2019 13:15:25 +0900 Subject: [PATCH 031/435] Completely rework the vulkan related api Things don't work yet, but this feels much cleaner. --- include/QF/Vulkan/cvars.h | 1 + include/QF/Vulkan/device.h | 26 ++ include/QF/Vulkan/funclist.h | 52 ++- include/QF/Vulkan/init.h | 88 ---- include/QF/Vulkan/instance.h | 55 +++ include/QF/Vulkan/qf_vid.h | 5 + include/QF/Vulkan/swapchain.h | 17 + include/vid_vulkan.h | 15 +- libs/video/renderer/vid_render_vulkan.c | 18 +- libs/video/renderer/vulkan/Makefile.am | 4 +- libs/video/renderer/vulkan/device.c | 211 +++++++++ libs/video/renderer/vulkan/init.c | 420 ------------------ libs/video/renderer/vulkan/instance.c | 266 +++++++++++ libs/video/renderer/vulkan/swapchain.c | 148 ++++++ libs/video/renderer/vulkan/util.c | 32 +- libs/video/renderer/vulkan/util.h | 8 +- .../video/renderer/vulkan/vulkan_vid_common.c | 238 +--------- libs/video/targets/vid_x11_vulkan.c | 17 +- 18 files changed, 817 insertions(+), 804 deletions(-) create mode 100644 include/QF/Vulkan/device.h delete mode 100644 include/QF/Vulkan/init.h create mode 100644 include/QF/Vulkan/instance.h create mode 100644 include/QF/Vulkan/swapchain.h create mode 100644 libs/video/renderer/vulkan/device.c delete mode 100644 libs/video/renderer/vulkan/init.c create mode 100644 libs/video/renderer/vulkan/instance.c create mode 100644 libs/video/renderer/vulkan/swapchain.c diff --git a/include/QF/Vulkan/cvars.h b/include/QF/Vulkan/cvars.h index b6110e353..706bc44de 100644 --- a/include/QF/Vulkan/cvars.h +++ b/include/QF/Vulkan/cvars.h @@ -2,5 +2,6 @@ #define __QF_Vulkan_cvars_h extern struct cvar_s *vulkan_use_validation; +extern struct cvar_s *vulkan_presentation_mode; #endif//__QF_Vulkan_cvars_h diff --git a/include/QF/Vulkan/device.h b/include/QF/Vulkan/device.h new file mode 100644 index 000000000..ae0c26ffc --- /dev/null +++ b/include/QF/Vulkan/device.h @@ -0,0 +1,26 @@ +#ifndef __QF_Vulkan_device_h +#define __QF_Vulkan_device_h + +typedef struct qfv_devfuncs_s { +#define DEVICE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; +#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; +#include "QF/Vulkan/funclist.h" +} qfv_devfuncs_t; + +struct qfv_instance_s; +typedef struct qfv_device_s { + VkDevice dev; + VkPhysicalDevice physDev; + qfv_devfuncs_t *funcs; + int32_t queueFamily; + VkQueue queue; + struct strset_s *enabled_extensions; + int (*extension_enabled) (struct qfv_device_s *inst, + const char *ext); +} qfv_device_t; + +struct vulkan_ctx_s; +qfv_device_t *QFV_CreateDevice(struct vulkan_ctx_s *ctx, + const char **extensions); + +#endif//__QF_Vulkan_swapchain_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 8418aeb6a..719335699 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -38,28 +38,6 @@ INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceMemoryProperties) #define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(function, extension) #endif -#if defined(VK_USE_PLATFORM_XLIB_KHR) -INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION - (vkGetPhysicalDeviceXlibPresentationSupportKHR, - VK_KHR_XLIB_SURFACE_EXTENSION_NAME) -INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION - (vkCreateXlibSurfaceKHR, - VK_KHR_XLIB_SURFACE_EXTENSION_NAME) -#elif defined(VK_USE_PLATFORM_WIN32_KHR) -INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION - (vkGetPhysicalDeviceWin32PresentationSupportKHR, - VK_KHR_WIN32_SURFACE_EXTENSION_NAME) -INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION - (vkCreateWin32SurfaceKHR, - VK_KHR_WIN32_SURFACE_EXTENSION_NAME) -#elif defined(VK_USE_PLATFORM_XCB_KHR) -INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION - (vkGetPhysicalDeviceXcbPresentationSupportKHR, - VK_KHR_XCB_SURFACE_EXTENSION_NAME) -INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION - (vkCreateXcbSurfaceKHR, - VK_KHR_XCB_SURFACE_EXTENSION_NAME) -#else INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkCreateDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION @@ -70,10 +48,38 @@ INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkGetPhysicalDeviceSurfaceCapabilitiesKHR, VK_KHR_SURFACE_EXTENSION_NAME) INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkGetPhysicalDeviceSurfaceFormatsKHR, VK_KHR_SURFACE_EXTENSION_NAME) -#endif #undef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION +#ifndef PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION +#define PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION(function, extension) +#endif + +#if defined(VK_USE_PLATFORM_XLIB_KHR) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceXlibPresentationSupportKHR, + VK_KHR_XLIB_SURFACE_EXTENSION_NAME) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateXlibSurfaceKHR, + VK_KHR_XLIB_SURFACE_EXTENSION_NAME) +#elif defined(VK_USE_PLATFORM_WIN32_KHR) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceWin32PresentationSupportKHR, + VK_KHR_WIN32_SURFACE_EXTENSION_NAME) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateWin32SurfaceKHR, + VK_KHR_WIN32_SURFACE_EXTENSION_NAME) +#elif defined(VK_USE_PLATFORM_XCB_KHR) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkGetPhysicalDeviceXcbPresentationSupportKHR, + VK_KHR_XCB_SURFACE_EXTENSION_NAME) +PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + (vkCreateXcbSurfaceKHR, + VK_KHR_XCB_SURFACE_EXTENSION_NAME) +#endif + +#undef PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION + #ifndef DEVICE_LEVEL_VULKAN_FUNCTION #define DEVICE_LEVEL_VULKAN_FUNCTION(function) #endif diff --git a/include/QF/Vulkan/init.h b/include/QF/Vulkan/init.h deleted file mode 100644 index 0988dd25a..000000000 --- a/include/QF/Vulkan/init.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - Copyright (C) 2019 Bill Currie - - Author: Bill Currie - Date: 2019/6/29 - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ -#ifndef __QF_Vulkan_init_h -#define __QF_Vulkan_init_h - -#include - -#include "QF/qtypes.h" - -typedef struct VulkanDevice_s { - VkDevice device; - int32_t queueFamily; - VkQueue queue; - VkSurfaceKHR surface; - -#define DEVICE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; -#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; -#include "QF/Vulkan/funclist.h" -} VulkanDevice_t; - -typedef struct { - VkPhysicalDevice device; - VkPhysicalDeviceFeatures features; - VkPhysicalDeviceProperties properties; - uint32_t numLayers; - VkLayerProperties *layers; - uint32_t numExtensions; - VkExtensionProperties *extensions; - VkPhysicalDeviceMemoryProperties memory; - uint32_t numQueueFamilies; - VkQueueFamilyProperties *queueFamilies; -} VulkanPhysDevice_t; - -typedef struct VulkanInstance_s { - VkInstance instance; - struct strset_s *enabled_extensions; - int (*extension_enabled) (struct VulkanInstance_s *inst, - const char *ext); - VkDebugUtilsMessengerEXT debug_callback; - uint32_t numDevices; - VulkanPhysDevice_t *devices; - -#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; -#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; -#include "QF/Vulkan/funclist.h" -} VulkanInstance_t; - -extern const char * const vulkanValidationLayers[]; - -void Vulkan_Init_Cvars (void); -struct vulkan_ctx_s; -VulkanInstance_t *Vulkan_CreateInstance (struct vulkan_ctx_s *ctx, - const char *appName, - uint32_t appVersion, - const char **layers, - const char **extensions); -void Vulkan_DestroyInstance (VulkanInstance_t *instance); -int Vulkan_ExtensionsSupported (const VkExtensionProperties *extensions, - int numExtensions, - const char * const *requested); -int Vulkan_LayersSupported (const VkLayerProperties *extensions, - int numLayers, - const char * const *requested); - -#endif // __QF_Vulkan_init_h diff --git a/include/QF/Vulkan/instance.h b/include/QF/Vulkan/instance.h new file mode 100644 index 000000000..1cc05d6cf --- /dev/null +++ b/include/QF/Vulkan/instance.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2019 Bill Currie + + Author: Bill Currie + Date: 2019/6/29 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_instance_h +#define __QF_Vulkan_instance_h + +#include + +#include "QF/qtypes.h" + +typedef struct qfv_instfuncs_s { +#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) PFN_##name name; +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; +#include "QF/Vulkan/funclist.h" +} qfv_instfuncs_t; + +typedef struct qfv_instance_s { + VkInstance instance; + qfv_instfuncs_t *funcs; + struct strset_s *enabled_extensions; + int (*extension_enabled) (struct qfv_instance_s *inst, + const char *ext); +} qfv_instance_t; + +struct vulkan_ctx_s; +qfv_instance_t *QFV_CreateInstance (struct vulkan_ctx_s *ctx, + const char *appName, + uint32_t appVersion, + const char **layers, + const char **extensions); +void QFV_DestroyInstance (qfv_instance_t *instance); + +#endif // __QF_Vulkan_instance_h diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index fe04da536..bfa543c46 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -30,6 +30,11 @@ #include "QF/Vulkan/cvars.h" +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + struct vulkan_ctx_s; void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx); void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx); diff --git a/include/QF/Vulkan/swapchain.h b/include/QF/Vulkan/swapchain.h new file mode 100644 index 000000000..71d0b6d75 --- /dev/null +++ b/include/QF/Vulkan/swapchain.h @@ -0,0 +1,17 @@ +#ifndef __QF_Vulkan_swapchain_h +#define __QF_Vulkan_swapchain_h + +typedef struct qfv_swapchain_s { + VkDevice dev; + struct qfv_devfuncs_s *funcs; + VkSurfaceKHR surface; + VkSwapchainKHR swapchain; + int32_t numImages; + VkImage *images; +} qfv_swapchain_t; + +struct vulkan_ctx_s; +qfv_swapchain_t *QFV_CreateSwapchain (struct vulkan_ctx_s *ctx, + VkSwapchainKHR old_swapchain); + +#endif//__QF_Vulkan_swapchain_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index fabaa088b..9cfb3ad8a 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -6,14 +6,11 @@ #endif #include -struct VulkanInstance_s; typedef struct vulkan_ctx_s { void (*load_vulkan) (struct vulkan_ctx_s *ctx); void (*unload_vulkan) (struct vulkan_ctx_s *ctx); const char **required_extensions; - int (*extension_enabled) (struct VulkanInstance_s *inst, - const char *ext); struct vulkan_presentation_s *presentation; int (*get_presentation_support) (struct vulkan_ctx_s *ctx, VkPhysicalDevice physicalDevice, @@ -22,14 +19,10 @@ typedef struct vulkan_ctx_s { void (*create_window) (struct vulkan_ctx_s *ctx); VkSurfaceKHR (*create_surface) (struct vulkan_ctx_s *ctx); - struct VulkanInstance_s *vtx; - struct VulkanDevice_s *dev; - VkInstance instance; - VkPhysicalDevice physDevice; - VkDevice device; - VkSwapchainKHR swapchain; - int32_t numSwapchainImages; - VkImage *swapchainImages; + struct qfv_instance_s *instance; + struct qfv_device_s *device; + struct qfv_swapchain_s *swapchain; + VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; #include "QF/Vulkan/funclist.h" diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 46d475917..506406394 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -37,7 +37,9 @@ #include "QF/plugin/vid_render.h" #include "QF/Vulkan/qf_vid.h" -#include "QF/Vulkan/init.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/swapchain.h" #include "mod_internal.h" #include "r_internal.h" @@ -150,20 +152,20 @@ vulkan_vid_render_choose_visual (void) { Vulkan_CreateDevice (vulkan_ctx); vulkan_ctx->choose_visual (vulkan_ctx); - Sys_Printf ("%p %p\n", vulkan_ctx->dev->device, vulkan_ctx->dev->queue); + Sys_Printf ("%p %p\n", vulkan_ctx->device->dev, vulkan_ctx->device->queue); } static void vulkan_vid_render_create_context (void) { vulkan_ctx->create_window (vulkan_ctx); - vulkan_ctx->dev->surface = vulkan_ctx->create_surface (vulkan_ctx); - Sys_Printf ("%p\n", vulkan_ctx->dev->surface); + vulkan_ctx->surface = vulkan_ctx->create_surface (vulkan_ctx); + Sys_Printf ("%p\n", vulkan_ctx->surface); Vulkan_CreateSwapchain (vulkan_ctx); - Sys_Printf ("%p %d", vulkan_ctx->swapchain, - vulkan_ctx->numSwapchainImages); - for (int32_t i = 0; i < vulkan_ctx->numSwapchainImages; i++) { - Sys_Printf (" %p", vulkan_ctx->swapchainImages[i]); + Sys_Printf ("%p %d", vulkan_ctx->swapchain->swapchain, + vulkan_ctx->swapchain->numImages); + for (int32_t i = 0; i < vulkan_ctx->swapchain->numImages; i++) { + Sys_Printf (" %p", vulkan_ctx->swapchain->images[i]); } Sys_Printf ("\n"); } diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index b134d1f91..e59e29551 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -4,7 +4,9 @@ AM_CFLAGS= @PREFER_PIC@ AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES vulkan_src = \ - init.c \ + device.c \ + instance.c \ + swapchain.c \ util.c \ vulkan_draw.c \ vulkan_vid_common.c diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c new file mode 100644 index 000000000..1579c0633 --- /dev/null +++ b/libs/video/renderer/vulkan/device.c @@ -0,0 +1,211 @@ +/* + vid_common_vulkan.c + + Common Vulkan video driver functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2019 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +static int +count_bits (uint32_t val) +{ + int bits = 0; + while (val) { + bits += val & 1; + val >>= 1; + } + return bits; +} + +static int +find_queue_family (qfv_instance_t *instance, VkPhysicalDevice dev, + uint32_t flags) +{ + qfv_instfuncs_t *funcs = instance->funcs; + uint32_t numFamilies; + VkQueueFamilyProperties *queueFamilies; + int best_diff = 32; + uint32_t family = -1; + + funcs->vkGetPhysicalDeviceQueueFamilyProperties (dev, &numFamilies, 0); + queueFamilies = alloca (numFamilies * sizeof (*queueFamilies)); + funcs->vkGetPhysicalDeviceQueueFamilyProperties (dev, &numFamilies, + queueFamilies); + + for (uint32_t i = 0; i < numFamilies; i++) { + VkQueueFamilyProperties *queue = &queueFamilies[i]; + + if ((queue->queueFlags & flags) == flags) { + int diff = count_bits (queue->queueFlags & ~flags); + if (diff < best_diff) { + best_diff = diff; + family = i; + } + } + } + return family; +} + +static void +load_device_funcs (qfv_instance_t *inst, qfv_device_t *dev) +{ + qfv_instfuncs_t *ifunc = inst->funcs; + qfv_devfuncs_t *dfunc = dev->funcs; + VkDevice device = dev->dev; +#define DEVICE_LEVEL_VULKAN_FUNCTION(name) \ + dfunc->name = (PFN_##name) ifunc->vkGetDeviceProcAddr (device, #name); \ + if (!dfunc->name) { \ + Sys_Error ("Couldn't find device level function %s", #name); \ + } + +#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ + if (dev->extension_enabled (dev, ext)) { \ + dfunc->name = (PFN_##name) ifunc->vkGetDeviceProcAddr (device, #name); \ + if (!dfunc->name) { \ + Sys_Printf ("Couldn't find device level function %s", #name); \ + } \ + } + +#include "QF/Vulkan/funclist.h" +} + +static int +device_extension_enabled (qfv_device_t *device, const char *ext) +{ + return strset_contains (device->enabled_extensions, ext); +} + +qfv_device_t * +QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) +{ + uint32_t nlay = 1; // ensure alloca doesn't see 0 and terminated + uint32_t next = count_strings (extensions) + 1; // ensure terminated + //if (vulkan_use_validation->int_val) { + // nlay += count_strings (vulkanValidationLayers); + //} + const char **lay = alloca (nlay * sizeof (const char *)); + const char **ext = alloca (next * sizeof (const char *)); + // ensure there are null pointers so merge_strings can act as append + // since it does not add a null, but also make sure the counts reflect + // actual numbers + memset (lay, 0, nlay-- * sizeof (const char *)); + memset (ext, 0, next-- * sizeof (const char *)); + merge_strings (ext, extensions, 0); + //if (vulkan_use_validation->int_val) { + // merge_strings (lay, lay, vulkanValidationLayers); + //} + + qfv_instance_t *inst = ctx->instance; + VkInstance instance = inst->instance; + qfv_instfuncs_t *ifunc = inst->funcs; + + uint32_t numDevices; + ifunc->vkEnumeratePhysicalDevices (instance, &numDevices, 0); + VkPhysicalDevice *devices = alloca (numDevices * sizeof (*devices)); + ifunc->vkEnumeratePhysicalDevices (instance, &numDevices, devices); + + for (uint32_t i = 0; i < numDevices; i++) { + VkPhysicalDevice physdev = devices[i]; + /* + if (!Vulkan_LayersSupported (phys->layers, phys->numLayers, lay)) { + continue; + } + if (!Vulkan_ExtensionsSupported (phys->extensions, phys->numExtensions, + ext)) { + continue; + } + */ + int family = find_queue_family (inst, physdev, VK_QUEUE_GRAPHICS_BIT); + if (family < 0) { + continue; + } + if (!ctx->get_presentation_support (ctx, physdev, family)) { + continue; + } + float priority = 1; + VkDeviceQueueCreateInfo qCreateInfo = { + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0, + family, 1, &priority + }; + VkPhysicalDeviceFeatures features; + VkDeviceCreateInfo dCreateInfo = { + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0, + 1, &qCreateInfo, + nlay, lay, + next, ext, + &features + }; + memset (&features, 0, sizeof (features)); + qfv_device_t *device = calloc (1, sizeof (qfv_device_t) + + sizeof (qfv_devfuncs_t)); + device->funcs = (qfv_devfuncs_t *) (device + 1); + if (ifunc->vkCreateDevice (physdev, &dCreateInfo, 0, + &device->dev) == VK_SUCCESS) { + qfv_devfuncs_t *dfunc = device->funcs; + + device->physDev = physdev; + load_device_funcs (inst, device); + device->queueFamily = family; + dfunc->vkGetDeviceQueue (device->dev, family, 0, &device->queue); + device->enabled_extensions = new_strset (ext); + device->extension_enabled = device_extension_enabled; + ctx->device = device; + return device; + } + free (device); + } + return 0; +} diff --git a/libs/video/renderer/vulkan/init.c b/libs/video/renderer/vulkan/init.c deleted file mode 100644 index 2ba5bfc06..000000000 --- a/libs/video/renderer/vulkan/init.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - init.c - - Copyright (C) 2019 Bill Currie - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif - -#include "QF/cvar.h" -#include "QF/dstring.h" -#include "QF/input.h" -#include "QF/qargs.h" -#include "QF/quakefs.h" -#include "QF/sys.h" -#include "QF/va.h" -#include "QF/vid.h" -#include "QF/Vulkan/init.h" - -#include "vid_vulkan.h" - -#include "util.h" - -cvar_t *vulkan_use_validation; - -static uint32_t numLayers; -static VkLayerProperties *instanceLayerProperties; -static const char **instanceLayerNames; -static uint32_t numExtensions; -static VkExtensionProperties *instanceExtensionProperties; -static const char **instanceExtensionNames; - -const char * const vulkanValidationLayers[] = { - "VK_LAYER_LUNARG_standard_validation", - 0, -}; - -static const char * const debugExtensions[] = { - VK_EXT_DEBUG_UTILS_EXTENSION_NAME, - 0, -}; - -static const char * const device_types[] = { - "other", - "integrated gpu", - "discrete gpu", - "virtual gpu", - "cpu", -}; - -static void -get_instance_layers_and_extensions (vulkan_ctx_t *ctx) -{ - uint32_t i; - VkLayerProperties *properties; - VkExtensionProperties *extensions; - - ctx->vkEnumerateInstanceLayerProperties (&numLayers, 0); - properties = malloc (numLayers * sizeof (VkLayerProperties)); - ctx->vkEnumerateInstanceLayerProperties (&numLayers, properties); - instanceLayerNames = (const char **) malloc ((numLayers + 1) - * sizeof (const char **)); - for (i = 0; i < numLayers; i++) { - instanceLayerNames[i] = properties[i].layerName; - } - instanceLayerNames[i] = 0; - - ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, 0); - extensions = malloc (numExtensions * sizeof (VkLayerProperties)); - ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, - extensions); - instanceExtensionNames = (const char **) malloc ((numExtensions + 1) - * sizeof (const char **)); - for (i = 0; i < numExtensions; i++) { - instanceExtensionNames[i] = extensions[i].extensionName; - } - instanceExtensionNames[i] = 0; - - if (developer->int_val & SYS_VULKAN) { - for (i = 0; i < numLayers; i++) { - Sys_Printf ("%s %x %u %s\n", - properties[i].layerName, - properties[i].specVersion, - properties[i].implementationVersion, - properties[i].description); - } - for (i = 0; i < numExtensions; i++) { - Sys_Printf ("%d %s\n", - extensions[i].specVersion, - extensions[i].extensionName); - } - } - instanceLayerProperties = properties; - instanceExtensionProperties = extensions; -} - -static void -init_physdev (VulkanInstance_t *instance, VkPhysicalDevice dev, VulkanPhysDevice_t *physdev) -{ - physdev->device = dev; - - instance->vkGetPhysicalDeviceProperties (dev, &physdev->properties); - - instance->vkEnumerateDeviceLayerProperties (dev, &physdev->numLayers, 0); - physdev->layers = malloc (physdev->numLayers * sizeof (VkLayerProperties)); - instance->vkEnumerateDeviceLayerProperties (dev, &physdev->numLayers, - physdev->layers); - - instance->vkEnumerateDeviceExtensionProperties (dev, 0, - &physdev->numExtensions, - 0); - physdev->extensions = malloc (physdev->numExtensions - * sizeof (VkExtensionProperties)); - instance->vkEnumerateDeviceExtensionProperties (dev, 0, - &physdev->numExtensions, - physdev->extensions); - - instance->vkGetPhysicalDeviceFeatures (dev, &physdev->features); - - instance->vkGetPhysicalDeviceMemoryProperties (dev, &physdev->memory); - - instance->vkGetPhysicalDeviceQueueFamilyProperties (dev, - &physdev->numQueueFamilies, - 0); - physdev->queueFamilies = malloc (physdev->numQueueFamilies - * sizeof (VkQueueFamilyProperties)); - instance->vkGetPhysicalDeviceQueueFamilyProperties (dev, - &physdev->numQueueFamilies, - physdev->queueFamilies); - - if (developer->int_val & SYS_VULKAN) { - VkPhysicalDeviceProperties *prop = &physdev->properties; - Sys_Printf ("dev: %p\n", dev); - Sys_Printf (" %x %x\n", prop->apiVersion, prop->driverVersion); - Sys_Printf (" %x %x\n", prop->vendorID, prop->deviceID); - Sys_Printf (" %s: %s\n", device_types[prop->deviceType], - prop->deviceName); - for (uint32_t i = 0; i < physdev->numLayers; i++) { - Sys_Printf (" %s %x %u %s\n", - physdev->layers[i].layerName, - physdev->layers[i].specVersion, - physdev->layers[i].implementationVersion, - physdev->layers[i].description); - } - for (uint32_t i = 0; i < physdev->numExtensions; i++) { - Sys_Printf (" %u %s\n", - physdev->extensions[i].specVersion, - physdev->extensions[i].extensionName); - } - Sys_Printf (" memory types:\n"); - for (uint32_t i = 0; i < physdev->memory.memoryTypeCount; i++) { - Sys_Printf (" %x %d\n", - physdev->memory.memoryTypes[i].propertyFlags, - physdev->memory.memoryTypes[i].heapIndex); - } - Sys_Printf (" memory heaps:\n"); - for (uint32_t i = 0; i < physdev->memory.memoryHeapCount; i++) { - Sys_Printf (" %x %ld\n", - physdev->memory.memoryHeaps[i].flags, - physdev->memory.memoryHeaps[i].size); - } - Sys_Printf (" queue families:\n"); - for (uint32_t i = 0; i < physdev->numQueueFamilies; i++) { - VkQueueFamilyProperties *queue = &physdev->queueFamilies[i]; - VkExtent3D gran = queue->minImageTransferGranularity; - Sys_Printf (" %x %3d %3d [%d %d %d]\n", - queue->queueFlags, - queue->queueCount, - queue->timestampValidBits, - gran.width, gran.height, gran.depth); - } - } -} - -static int -instance_extension_enabled (VulkanInstance_t *inst, const char *ext) -{ - return strset_contains (inst->enabled_extensions, ext); -} - -static int message_severities = - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; -static int message_types = - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - -static VKAPI_ATTR VkBool32 VKAPI_CALL -debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* callbackData, - void *data) -{ - const char *msgSev = ""; - if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { - msgSev = "verbose: "; - } - if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { - msgSev = "info: "; - } - if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { - msgSev = "warning: "; - } - if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { - msgSev = "error: "; - } - fprintf (stderr, "validation layer: %s%s\n", msgSev, callbackData->pMessage); - return VK_FALSE; -} - -static void -setup_debug_callback (VulkanInstance_t *instance) -{ - VkDebugUtilsMessengerCreateInfoEXT createInfo = { - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .messageSeverity = message_severities, - .messageType = message_types, - .pfnUserCallback = debug_callback, - .pUserData = instance, - }; - instance->vkCreateDebugUtilsMessengerEXT(instance->instance, &createInfo, - 0, &instance->debug_callback); -} - -static void -load_instance_funcs (vulkan_ctx_t *ctx) -{ - VulkanInstance_t *vtx = ctx->vtx; - VkInstance instance = vtx->instance; -#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) \ - vtx->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, #name); \ - if (!vtx->name) { \ - Sys_Error ("Couldn't find instance level function %s", #name); \ - } - -#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ - if (vtx->extension_enabled (vtx, ext)) { \ - vtx->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, \ - #name); \ - if (!vtx->name) { \ - Sys_Error ("Couldn't find instance level function %s", #name); \ - } \ - } - -#include "QF/Vulkan/funclist.h" -} - -VulkanInstance_t * -Vulkan_CreateInstance (vulkan_ctx_t *ctx, - const char *appName, uint32_t appVersion, - const char **layers, const char **extensions) -{ - VkApplicationInfo appInfo = { - VK_STRUCTURE_TYPE_APPLICATION_INFO, 0, - appName, appVersion, - PACKAGE_STRING, 0x000702ff, //FIXME version - VK_API_VERSION_1_0, - }; - VkInstanceCreateInfo createInfo = { - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0, - &appInfo, - 0, 0, - 0, 0, - }; - VkResult res; - VkInstance instance; - uint32_t numDev, i; - VkPhysicalDevice *devices; - VulkanInstance_t *inst; - - if (!instanceLayerProperties) { - get_instance_layers_and_extensions (ctx); - } - - uint32_t nlay = count_strings (layers) + 1; - uint32_t next = count_strings (extensions) - + count_strings (ctx->required_extensions) + 1; - if (vulkan_use_validation->int_val) { - nlay += count_strings (vulkanValidationLayers); - next += count_strings (debugExtensions); - } - const char **lay = alloca (nlay * sizeof (const char *)); - const char **ext = alloca (next * sizeof (const char *)); - // ensure there are null pointers so merge_strings can act as append - // since it does not add a null - memset (lay, 0, nlay-- * sizeof (const char *)); - memset (ext, 0, next-- * sizeof (const char *)); - merge_strings (lay, layers, 0); - merge_strings (ext, extensions, ctx->required_extensions); - if (vulkan_use_validation->int_val) { - merge_strings (lay, lay, vulkanValidationLayers); - merge_strings (ext, ext, debugExtensions); - } - prune_strings (instanceLayerNames, lay, &nlay); - prune_strings (instanceExtensionNames, ext, &next); - lay[nlay] = 0; - ext[next] = 0; - createInfo.enabledLayerCount = nlay; - createInfo.ppEnabledLayerNames = lay; - createInfo.enabledExtensionCount = next; - createInfo.ppEnabledExtensionNames = ext; - - res = ctx->vkCreateInstance (&createInfo, 0, &instance); - if (res != VK_SUCCESS) { - Sys_Error ("unable to create vulkan instance\n"); - } - inst = malloc (sizeof(VulkanInstance_t)); - inst->instance = instance; - inst->enabled_extensions = new_strset (ext); - inst->extension_enabled = instance_extension_enabled; - ctx->extension_enabled = instance_extension_enabled; - ctx->vtx = inst; - load_instance_funcs (ctx); - - if (vulkan_use_validation->int_val) { - setup_debug_callback (inst); - } - - res = inst->vkEnumeratePhysicalDevices (instance, &numDev, 0); - if (res != VK_SUCCESS) { - Sys_Error ("unable to query vulkan device count: %d\n", res); - } - devices = malloc(numDev * sizeof (VkPhysicalDevice)); - res = inst->vkEnumeratePhysicalDevices (instance, &numDev, devices); - if (res != VK_SUCCESS) { - Sys_Error ("unable to query vulkan device properties: %d\n", res); - } - - inst->numDevices = numDev; - inst->devices = malloc (numDev * sizeof (VulkanPhysDevice_t)); - - for (i = 0; i < numDev; i++) { - init_physdev (inst, devices[i], &inst->devices[i]); - } - - return inst; -} - -void -Vulkan_DestroyInstance (VulkanInstance_t *instance) -{ - for (uint32_t i = 0; i < instance->numDevices; i++) { - free (instance->devices[i].queueFamilies); - free (instance->devices[i].extensions); - free (instance->devices[i].layers); - } - free (instance->devices); - instance->vkDestroyInstance (instance->instance, 0); - free (instance); -} - -int -Vulkan_LayersSupported (const VkLayerProperties *layers, - int numLayers, - const char * const *requested) -{ - while (*requested) { - int i; - for (i = 0; i < numLayers; i++) { - if (!strcmp (*requested, layers[i].layerName)) { - break; - } - } - if (i == numLayers) { - // requested layer not found - break; - } - requested++; - } - return !*requested; -} - -int -Vulkan_ExtensionsSupported (const VkExtensionProperties *extensions, - int numExtensions, - const char * const *requested) -{ - while (*requested) { - int i; - for (i = 0; i < numExtensions; i++) { - if (!strcmp (*requested, extensions[i].extensionName)) { - break; - } - } - if (i == numExtensions) { - // requested extension not found - break; - } - requested++; - } - return !*requested; -} diff --git a/libs/video/renderer/vulkan/instance.c b/libs/video/renderer/vulkan/instance.c new file mode 100644 index 000000000..74b0ea756 --- /dev/null +++ b/libs/video/renderer/vulkan/instance.c @@ -0,0 +1,266 @@ +/* + init.c + + Copyright (C) 2019 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/instance.h" + +#include "vid_vulkan.h" + +#include "util.h" + +cvar_t *vulkan_use_validation; + +static uint32_t numLayers; +static VkLayerProperties *instanceLayerProperties; +static strset_t *instanceLayers; + +static uint32_t numExtensions; +static VkExtensionProperties *instanceExtensionProperties; +static strset_t *instanceExtensions; + +const char * const vulkanValidationLayers[] = { + "VK_LAYER_LUNARG_standard_validation", + 0, +}; + +static const char * const debugExtensions[] = { + VK_EXT_DEBUG_UTILS_EXTENSION_NAME, + 0, +}; + +static void +get_instance_layers_and_extensions (vulkan_ctx_t *ctx) +{ + uint32_t i; + VkLayerProperties *layers; + VkExtensionProperties *extensions; + + ctx->vkEnumerateInstanceLayerProperties (&numLayers, 0); + layers = malloc (numLayers * sizeof (VkLayerProperties)); + ctx->vkEnumerateInstanceLayerProperties (&numLayers, layers); + instanceLayers = new_strset (0); + for (i = 0; i < numLayers; i++) { + strset_add (instanceLayers, layers[i].layerName); + } + + ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, 0); + extensions = malloc (numExtensions * sizeof (VkLayerProperties)); + ctx->vkEnumerateInstanceExtensionProperties (0, &numExtensions, + extensions); + instanceExtensions = new_strset (0); + for (i = 0; i < numExtensions; i++) { + strset_add (instanceExtensions, extensions[i].extensionName); + } + + if (developer->int_val & SYS_VULKAN) { + for (i = 0; i < numLayers; i++) { + Sys_Printf ("%s %x %u %s\n", + layers[i].layerName, + layers[i].specVersion, + layers[i].implementationVersion, + layers[i].description); + } + for (i = 0; i < numExtensions; i++) { + Sys_Printf ("%d %s\n", + extensions[i].specVersion, + extensions[i].extensionName); + } + } + instanceLayerProperties = layers; + instanceExtensionProperties = extensions; +} + +static int +instance_extension_enabled (qfv_instance_t *inst, const char *ext) +{ + return strset_contains (inst->enabled_extensions, ext); +} + +static int message_severities = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; +static int message_types = + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + +static VKAPI_ATTR VkBool32 VKAPI_CALL +debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* callbackData, + void *data) +{ + const char *msgSev = ""; + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { + msgSev = "verbose: "; + } + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { + msgSev = "info: "; + } + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + msgSev = "warning: "; + } + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + msgSev = "error: "; + } + fprintf (stderr, "validation layer: %s%s\n", msgSev, callbackData->pMessage); + return VK_FALSE; +} + +static void +setup_debug_callback (qfv_instance_t *instance) +{ + VkDebugUtilsMessengerEXT debug_callback_handle; + VkDebugUtilsMessengerCreateInfoEXT createInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .messageSeverity = message_severities, + .messageType = message_types, + .pfnUserCallback = debug_callback, + .pUserData = instance, + }; + instance->funcs->vkCreateDebugUtilsMessengerEXT(instance->instance, + &createInfo, 0, + &debug_callback_handle); +} + +static void +load_instance_funcs (vulkan_ctx_t *ctx) +{ + qfv_instance_t *instance = ctx->instance; + qfv_instfuncs_t *funcs = instance->funcs; + VkInstance inst = instance->instance; +#define INSTANCE_LEVEL_VULKAN_FUNCTION(name) \ + funcs->name = (PFN_##name) ctx->vkGetInstanceProcAddr (inst, #name); \ + if (!funcs->name) { \ + Sys_Error ("Couldn't find instance level function %s", #name); \ + } + +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ + if (instance->extension_enabled (instance, ext)) { \ + funcs->name = (PFN_##name) ctx->vkGetInstanceProcAddr (inst, #name); \ + if (!funcs->name) { \ + Sys_Error ("Couldn't find instance level function %s", #name); \ + } \ + } + +#include "QF/Vulkan/funclist.h" +} + +qfv_instance_t * +QFV_CreateInstance (vulkan_ctx_t *ctx, + const char *appName, uint32_t appVersion, + const char **layers, const char **extensions) +{ + VkApplicationInfo appInfo = { + VK_STRUCTURE_TYPE_APPLICATION_INFO, 0, + appName, appVersion, + PACKAGE_STRING, 0x000702ff, //FIXME version + VK_API_VERSION_1_0, + }; + VkInstanceCreateInfo createInfo = { + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0, + &appInfo, + 0, 0, + 0, 0, + }; + VkResult res; + VkInstance instance; + + if (!instanceLayerProperties) { + get_instance_layers_and_extensions (ctx); + } + + uint32_t nlay = count_strings (layers) + 1; + uint32_t next = count_strings (extensions) + + count_strings (ctx->required_extensions) + 1; + if (vulkan_use_validation->int_val) { + nlay += count_strings (vulkanValidationLayers); + next += count_strings (debugExtensions); + } + const char **lay = alloca (nlay * sizeof (const char *)); + const char **ext = alloca (next * sizeof (const char *)); + // ensure there are null pointers so merge_strings can act as append + // since it does not add a null + memset (lay, 0, nlay-- * sizeof (const char *)); + memset (ext, 0, next-- * sizeof (const char *)); + merge_strings (lay, layers, 0); + merge_strings (ext, extensions, ctx->required_extensions); + if (vulkan_use_validation->int_val) { + merge_strings (lay, lay, vulkanValidationLayers); + merge_strings (ext, ext, debugExtensions); + } + prune_strings (instanceLayers, lay, &nlay); + prune_strings (instanceExtensions, ext, &next); + lay[nlay] = 0; + ext[next] = 0; + createInfo.enabledLayerCount = nlay; + createInfo.ppEnabledLayerNames = lay; + createInfo.enabledExtensionCount = next; + createInfo.ppEnabledExtensionNames = ext; + + res = ctx->vkCreateInstance (&createInfo, 0, &instance); + if (res != VK_SUCCESS) { + Sys_Error ("unable to create vulkan instance\n"); + } + qfv_instance_t *inst = malloc (sizeof(qfv_instance_t) + + sizeof (qfv_instfuncs_t)); + inst->instance = instance; + inst->funcs = (qfv_instfuncs_t *)(inst + 1); + inst->enabled_extensions = new_strset (ext); + inst->extension_enabled = instance_extension_enabled; + ctx->instance = inst; + load_instance_funcs (ctx); + + if (vulkan_use_validation->int_val) { + setup_debug_callback (inst); + } + + return inst; +} + +void +QFV_DestroyInstance (qfv_instance_t *instance) +{ + instance->funcs->vkDestroyInstance (instance->instance, 0); + free (instance); +} diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c new file mode 100644 index 000000000..91f8280c9 --- /dev/null +++ b/libs/video/renderer/vulkan/swapchain.c @@ -0,0 +1,148 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/cvars.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/swapchain.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +qfv_swapchain_t * +QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) +{ + qfv_instfuncs_t *ifuncs = ctx->instance->funcs; + qfv_devfuncs_t *dfuncs = ctx->device->funcs; + + VkBool32 supported; + ifuncs->vkGetPhysicalDeviceSurfaceSupportKHR (ctx->device->physDev, + ctx->device->queueFamily, + ctx->surface, + &supported); + if (!supported) { + Sys_Error ("unsupported surface for swapchain"); + } + + uint32_t numModes; + VkPresentModeKHR *modes; + VkPresentModeKHR useMode = VK_PRESENT_MODE_FIFO_KHR;; + ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->device->physDev, + ctx->surface, + &numModes, 0); + modes = alloca (numModes * sizeof (VkPresentModeKHR)); + ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->device->physDev, + ctx->surface, + &numModes, modes); + for (uint32_t i = 0; i < numModes; i++) { + if ((int) modes[i] == vulkan_presentation_mode->int_val) { + useMode = modes[i]; + } + } + Sys_MaskPrintf (SYS_VULKAN, "presentation mode: %d (%d)\n", useMode, + vulkan_presentation_mode->int_val); + + VkSurfaceCapabilitiesKHR surfCaps; + ifuncs->vkGetPhysicalDeviceSurfaceCapabilitiesKHR (ctx->device->physDev, + ctx->surface, + &surfCaps); + uint32_t numImages = surfCaps.minImageCount + 1; + if (surfCaps.maxImageCount > 0 && numImages > surfCaps.maxImageCount) { + numImages = surfCaps.maxImageCount; + } + + VkExtent2D imageSize = {viddef.width, viddef.height}; + if (surfCaps.currentExtent.width == ~0u) { + imageSize.width = bound (surfCaps.minImageExtent.width, + imageSize.width, + surfCaps.maxImageExtent.width); + imageSize.height = bound (surfCaps.minImageExtent.height, + imageSize.height, + surfCaps.maxImageExtent.height); + } else { + imageSize = surfCaps.currentExtent; + } + Sys_MaskPrintf (SYS_VULKAN, "%d [%d, %d]\n", numImages, + imageSize.width, imageSize.height); + + VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageUsage &= surfCaps.supportedUsageFlags; + + VkSurfaceTransformFlagBitsKHR surfTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + + uint32_t numFormats; + ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->device->physDev, + ctx->surface, + &numFormats, 0); + VkSurfaceFormatKHR *formats = alloca (numFormats * sizeof (*formats)); + ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->device->physDev, + ctx->surface, + &numFormats, formats); + VkSurfaceFormatKHR useFormat = {VK_FORMAT_R8G8B8A8_UNORM, + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}; + if (numFormats > 1) { + uint32_t i; + for (i = 0; i < numFormats; i++) { + if (formats[i].format == useFormat.format + && formats[i].colorSpace == useFormat.colorSpace) { + break; + } + } + if (i == numFormats) { + useFormat = formats[0]; + } + } else if (numFormats == 1 && formats[0].format != VK_FORMAT_UNDEFINED) { + useFormat = formats[0]; + } + + VkSwapchainCreateInfoKHR createInfo = { + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 0, 0, + ctx->surface, + numImages, + useFormat.format, useFormat.colorSpace, + imageSize, + 1, // array layers + imageUsage, + VK_SHARING_MODE_EXCLUSIVE, + 0, 0, + surfTransform, + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + useMode, + VK_TRUE, + old_swapchain + }; + + VkDevice device = ctx->device->dev; + VkSwapchainKHR swapchain; + dfuncs->vkCreateSwapchainKHR (device, &createInfo, 0, &swapchain); + + if (old_swapchain != swapchain) { + dfuncs->vkDestroySwapchainKHR (device, old_swapchain, 0); + } + + dfuncs->vkGetSwapchainImagesKHR (device, swapchain, &numImages, 0); + qfv_swapchain_t *sc = malloc (sizeof (qfv_swapchain_t) + + numImages * sizeof (VkImage)); + sc->dev = device; + sc->funcs = ctx->device->funcs; + sc->surface = ctx->surface; + sc->swapchain = swapchain; + sc->numImages = numImages; + sc->images = (VkImage *) (sc + 1); + dfuncs->vkGetSwapchainImagesKHR (device, swapchain, &numImages, + sc->images); + return sc; +} diff --git a/libs/video/renderer/vulkan/util.c b/libs/video/renderer/vulkan/util.c index 09e1b146a..854557e95 100644 --- a/libs/video/renderer/vulkan/util.c +++ b/libs/video/renderer/vulkan/util.c @@ -47,17 +47,27 @@ strset_t * new_strset (const char * const *strings) { hashtab_t *tab = Hash_NewTable (61, strset_get_key, 0, 0); - for ( ; *strings; strings++) { + for ( ; strings && *strings; strings++) { Hash_Add (tab, (void *) *strings); } return (strset_t *) tab; } -void del_strset (strset_t *strset) + +void +del_strset (strset_t *strset) { Hash_DelTable ((hashtab_t *) strset); } -int strset_contains (strset_t *strset, const char *str) +void +strset_add (strset_t *strset, const char *str) +{ + hashtab_t *tab = (hashtab_t *) strset; + Hash_Add (tab, (void *) str); +} + +int +strset_contains (strset_t *strset, const char *str) { return Hash_Find ((hashtab_t *) strset, str) != 0; } @@ -92,18 +102,12 @@ merge_strings (const char **out, const char * const *in1, } void -prune_strings (const char * const *reference, const char **strings, - uint32_t *count) +prune_strings (strset_t *strset, const char **strings, uint32_t *count) { - for (int i = *count; i-- > 0; ) { - const char *str = strings[i]; - const char * const *ref; - for (ref = reference; *ref; ref++) { - if (!strcmp (*ref, str)) { - break; - } - } - if (!*ref) { + hashtab_t *tab = (hashtab_t *) strset; + + for (uint32_t i = *count; i-- > 0; ) { + if (!Hash_Find (tab, strings[i])) { memmove (strings + i, strings + i + 1, (--(*count) - i) * sizeof (const char **)); } diff --git a/libs/video/renderer/vulkan/util.h b/libs/video/renderer/vulkan/util.h index a15aac4c8..ae87b8096 100644 --- a/libs/video/renderer/vulkan/util.h +++ b/libs/video/renderer/vulkan/util.h @@ -2,15 +2,17 @@ #define __util_h #include + +typedef struct strset_s strset_t; + int count_strings (const char * const *str); void merge_strings (const char **out, const char * const *in1, const char * const *in2); -void prune_strings (const char * const *reference, const char **strings, - uint32_t *count); +void prune_strings (strset_t *strset, const char **strings, uint32_t *count); -typedef struct strset_s strset_t; strset_t *new_strset (const char * const *strings); void del_strset (strset_t *strset); +void strset_add (strset_t *strset, const char *str); int strset_contains (strset_t *strset, const char *str); #endif//__util_h diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 22ce1d71e..f7988c26c 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -49,7 +49,8 @@ #include "QF/va.h" #include "QF/vid.h" #include "QF/Vulkan/qf_vid.h" -#include "QF/Vulkan/init.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" #include "compat.h" #include "d_iface.h" @@ -58,7 +59,7 @@ #include "util.h" -static cvar_t *vulkan_presentation_mode; +cvar_t *vulkan_presentation_mode; static void vulkan_presentation_mode_f (cvar_t *var) @@ -77,8 +78,8 @@ vulkan_presentation_mode_f (cvar_t *var) } } -void -Vulkan_Init_Cvars () +static void +Vulkan_Init_Cvars (void) { vulkan_use_validation = Cvar_Get ("vulkan_use_validation", "1", CVAR_NONE, 0, @@ -102,251 +103,30 @@ static const char *device_extensions[] = { 0, }; -static int -count_bits (uint32_t val) -{ - int bits = 0; - while (val) { - bits += val & 1; - val >>= 1; - } - return bits; -} - -static int -find_queue_family (VulkanPhysDevice_t *dev, uint32_t flags) -{ - int best_diff = 32; - uint32_t family = -1; - - for (uint32_t i = 0; i < dev->numQueueFamilies; i++) { - VkQueueFamilyProperties *queue = &dev->queueFamilies[i]; - - if ((queue->queueFlags & flags) == flags) { - int diff = count_bits (queue->queueFlags & ~flags); - if (diff < best_diff) { - best_diff = diff; - family = i; - } - } - } - return family; -} - -static void -load_device_funcs (VulkanInstance_t *inst, VulkanDevice_t *dev) -{ -#define DEVICE_LEVEL_VULKAN_FUNCTION(name) \ - dev->name = (PFN_##name) inst->vkGetDeviceProcAddr (dev->device, #name); \ - if (!dev->name) { \ - Sys_Error ("Couldn't find device level function %s", #name); \ - } - -#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ - if (inst->extension_enabled (inst, ext)) { \ - dev->name = (PFN_##name) inst->vkGetDeviceProcAddr (dev->device, \ - #name); \ - if (!dev->name) { \ - Sys_Printf ("Couldn't find device level function %s", #name); \ - } \ - } - -#include "QF/Vulkan/funclist.h" -} - void Vulkan_Init_Common (vulkan_ctx_t *ctx) { Sys_Printf ("Vulkan_Init_Common\n"); Vulkan_Init_Cvars (); - ctx->vtx = Vulkan_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version - ctx->instance = ctx->vtx->instance; + ctx->instance = QFV_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version } void Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) { - Vulkan_DestroyInstance (ctx->vtx); - ctx->vtx = 0; + QFV_DestroyInstance (ctx->instance); + ctx->instance = 0; ctx->unload_vulkan (ctx); } void Vulkan_CreateDevice (vulkan_ctx_t *ctx) { - VulkanInstance_t *inst = ctx->vtx; - - uint32_t nlay = 1; // ensure alloca doesn't see 0 and terminated - uint32_t next = count_strings (device_extensions) + 1; // ensure terminated - if (vulkan_use_validation->int_val) { - nlay += count_strings (vulkanValidationLayers); - } - const char **lay = alloca (nlay * sizeof (const char *)); - const char **ext = alloca (next * sizeof (const char *)); - // ensure there are null pointers so merge_strings can act as append - // since it does not add a null, but also make sure the counts reflect - // actual numbers - memset (lay, 0, nlay-- * sizeof (const char *)); - memset (ext, 0, next-- * sizeof (const char *)); - merge_strings (ext, device_extensions, 0); - if (vulkan_use_validation->int_val) { - merge_strings (lay, lay, vulkanValidationLayers); - } - - for (uint32_t i = 0; i < inst->numDevices; i++) { - VulkanPhysDevice_t *phys = &inst->devices[i]; - if (!Vulkan_LayersSupported (phys->layers, phys->numLayers, lay)) { - continue; - } - if (!Vulkan_ExtensionsSupported (phys->extensions, phys->numExtensions, - ext)) { - continue; - } - int family = find_queue_family (phys, VK_QUEUE_GRAPHICS_BIT); - if (family < 0) { - continue; - } - if (!ctx->get_presentation_support (ctx, phys->device, family)) { - continue; - } - float priority = 1; - VkDeviceQueueCreateInfo qCreateInfo = { - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0, - family, 1, &priority - }; - VkPhysicalDeviceFeatures features; - VkDeviceCreateInfo dCreateInfo = { - VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0, - 1, &qCreateInfo, - nlay, lay, - next, ext, - &features - }; - memset (&features, 0, sizeof (features)); - VulkanDevice_t *device = calloc (1, sizeof (VulkanDevice_t)); - if (inst->vkCreateDevice (phys->device, &dCreateInfo, 0, - &device->device) == VK_SUCCESS) { - load_device_funcs (inst, device); - device->vkGetDeviceQueue (device->device, family, - 0, &device->queue); - ctx->dev = device; - ctx->device = device->device; - ctx->physDevice = phys->device; - device->queueFamily = family; - return; - } - } + ctx->device = QFV_CreateDevice (ctx, device_extensions); } void Vulkan_CreateSwapchain (vulkan_ctx_t *ctx) { - VkBool32 supported; - ctx->vtx->vkGetPhysicalDeviceSurfaceSupportKHR (ctx->physDevice, - ctx->dev->queueFamily, - ctx->dev->surface, - &supported); - if (!supported) { - Sys_Error ("unsupported surface for swapchain"); - } - uint32_t numModes; - VkPresentModeKHR *modes; - VkPresentModeKHR useMode = VK_PRESENT_MODE_FIFO_KHR;; - ctx->vtx->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->physDevice, - ctx->dev->surface, - &numModes, 0); - modes = alloca (numModes * sizeof (VkPresentModeKHR)); - ctx->vtx->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->physDevice, - ctx->dev->surface, - &numModes, modes); - for (uint32_t i = 0; i < numModes; i++) { - if ((int) modes[i] == vulkan_presentation_mode->int_val) { - useMode = modes[i]; - } - } - Sys_MaskPrintf (SYS_VULKAN, "presentation mode: %d (%d)\n", useMode, - vulkan_presentation_mode->int_val); - - VkSurfaceCapabilitiesKHR surfCaps; - ctx->vtx->vkGetPhysicalDeviceSurfaceCapabilitiesKHR (ctx->physDevice, - ctx->dev->surface, - &surfCaps); - uint32_t numImages = surfCaps.minImageCount + 1; - if (surfCaps.maxImageCount > 0 && numImages > surfCaps.maxImageCount) { - numImages = surfCaps.maxImageCount; - } - - VkExtent2D imageSize = {viddef.width, viddef.height}; - if (surfCaps.currentExtent.width == ~0u) { - imageSize.width = bound (surfCaps.minImageExtent.width, - imageSize.width, - surfCaps.maxImageExtent.width); - imageSize.height = bound (surfCaps.minImageExtent.height, - imageSize.height, - surfCaps.maxImageExtent.height); - } else { - imageSize = surfCaps.currentExtent; - } - Sys_MaskPrintf (SYS_VULKAN, "%d [%d, %d]\n", numImages, - imageSize.width, imageSize.height); - - VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - imageUsage &= surfCaps.supportedUsageFlags; - - VkSurfaceTransformFlagBitsKHR surfTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - - uint32_t numFormats; - ctx->vtx->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->physDevice, - ctx->dev->surface, - &numFormats, 0); - VkSurfaceFormatKHR *formats = alloca (numFormats * sizeof (*formats)); - ctx->vtx->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->physDevice, - ctx->dev->surface, - &numFormats, formats); - VkSurfaceFormatKHR useFormat = {VK_FORMAT_R8G8B8A8_UNORM, - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}; - if (numFormats > 1) { - uint32_t i; - for (i = 0; i < numFormats; i++) { - if (formats[i].format == useFormat.format - && formats[i].colorSpace == useFormat.colorSpace) { - break; - } - } - if (i == numFormats) { - useFormat = formats[0]; - } - } else if (numFormats == 1 && formats[0].format != VK_FORMAT_UNDEFINED) { - useFormat = formats[0]; - } - - VkSwapchainCreateInfoKHR createInfo = { - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, 0, 0, - ctx->dev->surface, - numImages, - useFormat.format, useFormat.colorSpace, - imageSize, - 1, // array layers - imageUsage, - VK_SHARING_MODE_EXCLUSIVE, - 0, 0, - surfTransform, - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - useMode, - VK_TRUE, - ctx->swapchain - }; - VkSwapchainKHR swapchain; - ctx->dev->vkCreateSwapchainKHR (ctx->device, &createInfo, 0, &swapchain); - if (ctx->swapchain != swapchain) { - ctx->dev->vkDestroySwapchainKHR (ctx->device, ctx->swapchain, 0); - } - ctx->swapchain = swapchain; - - ctx->dev->vkGetSwapchainImagesKHR (ctx->device, swapchain, &numImages, 0); - ctx->swapchainImages = malloc (numImages * sizeof (*ctx->swapchainImages)); - ctx->dev->vkGetSwapchainImagesKHR (ctx->device, swapchain, &numImages, - ctx->swapchainImages); - ctx->numSwapchainImages = numImages; } diff --git a/libs/video/targets/vid_x11_vulkan.c b/libs/video/targets/vid_x11_vulkan.c index 812e74dad..cd228b051 100644 --- a/libs/video/targets/vid_x11_vulkan.c +++ b/libs/video/targets/vid_x11_vulkan.c @@ -54,6 +54,8 @@ #include "QF/set.h" #include "QF/sys.h" +#include "QF/Vulkan/instance.h" + #include "context_x11.h" #include "vid_internal.h" #include "vid_vulkan.h" @@ -61,7 +63,7 @@ static cvar_t *vulkan_library_name; typedef struct vulkan_presentation_s { -#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; +#define PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION(name,ext) PFN_##name name; #include "QF/Vulkan/funclist.h" Display *display; @@ -115,12 +117,12 @@ x11_vulkan_init_presentation (vulkan_ctx_t *ctx) { ctx->presentation = calloc (1, sizeof (vulkan_presentation_t)); vulkan_presentation_t *pres = ctx->presentation; - VkInstance instance = ctx->instance; + qfv_instance_t *instance = ctx->instance; + VkInstance inst = instance->instance; -#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ - if (ctx->extension_enabled (ctx->vtx, ext)) { \ - pres->name = (PFN_##name) ctx->vkGetInstanceProcAddr (instance, \ - #name); \ +#define PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ + if (instance->extension_enabled (instance, ext)) { \ + pres->name = (PFN_##name) ctx->vkGetInstanceProcAddr (inst, #name); \ if (!pres->name) { \ Sys_Error ("Couldn't find instance-level function %s", #name); \ } \ @@ -182,6 +184,7 @@ static VkSurfaceKHR x11_vulkan_create_surface (vulkan_ctx_t *ctx) { vulkan_presentation_t *pres = ctx->presentation; + VkInstance inst = ctx->instance->instance; VkSurfaceKHR surface; VkXlibSurfaceCreateInfoKHR createInfo = { .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, @@ -190,7 +193,7 @@ x11_vulkan_create_surface (vulkan_ctx_t *ctx) .window = pres->window }; - if (pres->vkCreateXlibSurfaceKHR (ctx->instance, &createInfo, 0, &surface) + if (pres->vkCreateXlibSurfaceKHR (inst, &createInfo, 0, &surface) != VK_SUCCESS) { return 0; } From 66e7336b624015ae8590eeed16fcbb0da1c36f9b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 12 Jul 2019 13:37:30 +0900 Subject: [PATCH 032/435] Initialize device extension checks early They need to be initialized before attempting to load the function pointers. --- libs/video/renderer/vulkan/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index 1579c0633..36b81b025 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -195,13 +195,13 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) if (ifunc->vkCreateDevice (physdev, &dCreateInfo, 0, &device->dev) == VK_SUCCESS) { qfv_devfuncs_t *dfunc = device->funcs; + device->enabled_extensions = new_strset (ext); + device->extension_enabled = device_extension_enabled; device->physDev = physdev; load_device_funcs (inst, device); device->queueFamily = family; dfunc->vkGetDeviceQueue (device->dev, family, 0, &device->queue); - device->enabled_extensions = new_strset (ext); - device->extension_enabled = device_extension_enabled; ctx->device = device; return device; } From b2e12d701bc151e7ec284b340e122e83fd1decd8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 12 Jul 2019 14:09:12 +0900 Subject: [PATCH 033/435] Fix up swapchain creation Things are working again. --- include/QF/Vulkan/funclist.h | 6 +++--- libs/video/renderer/vulkan/vulkan_vid_common.c | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 719335699..1419aebd4 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -94,10 +94,10 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkGetDeviceQueue) #endif DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION - (vkCreateSwapchainKHR, VK_KHR_SURFACE_EXTENSION_NAME) + (vkCreateSwapchainKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION - (vkDestroySwapchainKHR, VK_KHR_SURFACE_EXTENSION_NAME) + (vkDestroySwapchainKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION - (vkGetSwapchainImagesKHR, VK_KHR_SURFACE_EXTENSION_NAME) + (vkGetSwapchainImagesKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) #undef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index f7988c26c..70890ab7a 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -51,6 +51,7 @@ #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" +#include "QF/Vulkan/swapchain.h" #include "compat.h" #include "d_iface.h" @@ -129,4 +130,14 @@ Vulkan_CreateDevice (vulkan_ctx_t *ctx) void Vulkan_CreateSwapchain (vulkan_ctx_t *ctx) { + VkSwapchainKHR old_swapchain = 0; + if (ctx->swapchain) { + old_swapchain = ctx->swapchain->swapchain; + free (ctx->swapchain); + } + ctx->swapchain = QFV_CreateSwapchain (ctx, old_swapchain); + if (ctx->swapchain->swapchain == old_swapchain) { + ctx->device->funcs->vkDestroySwapchainKHR (ctx->device->dev, + old_swapchain, 0); + } } From 4e4d1b99b48b06d67b271c92d7095b0c55d3970c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 12 Jul 2019 23:15:26 +0900 Subject: [PATCH 034/435] Clean up all the system shutdown calls I added Sys_RegisterShutdown years ago and never really did anything with it: now any system that needs to be shutdown can ensure it gets shutdown on program exit, and in the correct order (ie, reverse to init order). --- hw/source/master.c | 3 -- include/QF/cdaudio.h | 1 - include/QF/console.h | 1 - include/QF/input.h | 2 -- include/QF/sound.h | 4 --- include/QF/vid.h | 1 - include/netchan.h | 4 --- include/netmain.h | 4 --- libs/audio/cd.c | 6 ++-- libs/audio/snd.c | 29 ++++++++-------- libs/audio/targets/snd_alsa.c | 4 +-- libs/audio/targets/snd_disk.c | 4 +-- libs/audio/targets/snd_dx.c | 13 +++---- libs/audio/targets/snd_oss.c | 4 +-- libs/audio/targets/snd_sdl.c | 4 +-- libs/audio/targets/snd_sgi.c | 4 +-- libs/audio/targets/snd_sun.c | 4 +-- libs/audio/targets/snd_win.c | 9 ++--- libs/console/client.c | 4 +-- libs/console/console.c | 20 ++++++----- libs/console/server.c | 4 +-- libs/net/nc/net_udp.c | 23 +++++++------ libs/net/nc/net_udp6.c | 4 +-- libs/net/net_main.c | 56 ++++++++++++++++--------------- libs/video/targets/context_sdl.c | 6 ---- libs/video/targets/in_common.c | 6 ++-- libs/video/targets/vid_3dfxsvga.c | 6 ++-- libs/video/targets/vid_fbdev.c | 6 ++-- libs/video/targets/vid_sdl.c | 8 +++++ libs/video/targets/vid_svgalib.c | 6 ++-- libs/video/targets/vid_wgl.c | 6 ++-- libs/video/targets/vid_x11.c | 21 +++++------- nq/include/client.h | 1 - nq/source/cl_main.c | 8 ++--- nq/source/host.c | 7 ---- nq/source/sv_ded.c | 5 --- qtv/source/qtv.c | 2 -- qw/source/cl_main.c | 5 --- qw/source/sv_main.c | 3 -- tools/qwaq/qwaq-bi.c | 3 -- 40 files changed, 135 insertions(+), 176 deletions(-) diff --git a/hw/source/master.c b/hw/source/master.c index 6e744c4ac..31f457f5a 100644 --- a/hw/source/master.c +++ b/hw/source/master.c @@ -471,11 +471,8 @@ SV_WriteFilterList (void) static void SV_Shutdown (void) { - NET_Shutdown (); - // write filter list SV_WriteFilterList (); - Con_Shutdown (); } static void diff --git a/include/QF/cdaudio.h b/include/QF/cdaudio.h index e7596ad78..12d3aa2a9 100644 --- a/include/QF/cdaudio.h +++ b/include/QF/cdaudio.h @@ -35,7 +35,6 @@ void CDAudio_Play(int track, qboolean looping); void CDAudio_Stop(void); void CDAudio_Pause(void); void CDAudio_Resume(void); -void CDAudio_Shutdown(void); void CDAudio_Update(void); #endif // _CDAUDIO_H diff --git a/include/QF/console.h b/include/QF/console.h index 4f3bcb3c8..b18e66401 100644 --- a/include/QF/console.h +++ b/include/QF/console.h @@ -119,7 +119,6 @@ void Con_BufferAddText (con_buffer_t *buf, const char *text); // init/shutdown functions void Con_Init (const char *plugin_name); -void Con_Shutdown (void); void Con_ExecLine (const char *line); void Con_ProcessInput (void); diff --git a/include/QF/input.h b/include/QF/input.h index 8f0438071..ab808386f 100644 --- a/include/QF/input.h +++ b/include/QF/input.h @@ -44,8 +44,6 @@ struct cvar_s; void IN_Init (struct cbuf_s *cbuf); void IN_Init_Cvars (void); -void IN_Shutdown (void); - void IN_ProcessEvents (void); void IN_UpdateGrab (struct cvar_s *); diff --git a/include/QF/sound.h b/include/QF/sound.h index 874469ea4..3e37a5871 100644 --- a/include/QF/sound.h +++ b/include/QF/sound.h @@ -81,10 +81,6 @@ void S_Init (int *viewentity, double *host_frametime); */ void S_Init_Cvars (void); -/** Shutdown the sound engine. Allows audio output modules to shutdown - gracefully. -*/ -void S_Shutdown (void); //@} /** \defgroup sound_stuff Unclassified diff --git a/include/QF/vid.h b/include/QF/vid.h index 93975ced6..e1228fcd7 100644 --- a/include/QF/vid.h +++ b/include/QF/vid.h @@ -76,7 +76,6 @@ void VID_Init_Cvars (void); // the palette data will go away after the call, so it must be copied off if // the video driver will need it again void VID_Init (byte *palette, byte *colormap); -void VID_Shutdown (void); void VID_SetCaption (const char *text); void VID_ClearMemory (void); diff --git a/include/netchan.h b/include/netchan.h index 556732ba2..4aa266fc8 100644 --- a/include/netchan.h +++ b/include/netchan.h @@ -90,10 +90,6 @@ extern struct cvar_s *net_packetlog; */ void NET_Init (int port); -/** Shutdown the UDP network interface. -*/ -void NET_Shutdown (void); - /** Read a single packet from the network into net_message. \return True if successfully read, otherwise false. diff --git a/include/netmain.h b/include/netmain.h index a35171415..fdb870628 100644 --- a/include/netmain.h +++ b/include/netmain.h @@ -273,10 +273,6 @@ extern int net_activeconnections; */ void NET_Init (void); -/** Shutdown the networking sub-system. -*/ -void NET_Shutdown (void); - /** Check for new connections. \return Pointer to the qsocket for the new connection if there diff --git a/libs/audio/cd.c b/libs/audio/cd.c index bf4245ba6..e025abbe2 100644 --- a/libs/audio/cd.c +++ b/libs/audio/cd.c @@ -69,8 +69,8 @@ CDAudio_Resume (void) cdmodule->functions->cd->pCDAudio_Resume (); } -VISIBLE void -CDAudio_Shutdown (void) +static void +CDAudio_shutdown (void) { if (cdmodule) cdmodule->functions->general->p_Shutdown (); @@ -93,6 +93,8 @@ CD_f (void) VISIBLE int CDAudio_Init (void) { + Sys_RegisterShutdown (CDAudio_shutdown); + PI_RegisterPlugins (cd_plugin_list); cd_plugin = Cvar_Get ("cd_plugin", CD_DEFAULT, CVAR_ROM, NULL, "CD Plugin to use"); diff --git a/libs/audio/snd.c b/libs/audio/snd.c index 6f4ecba05..e76c548e0 100644 --- a/libs/audio/snd.c +++ b/libs/audio/snd.c @@ -53,6 +53,19 @@ static plugin_list_t snd_render_list[] = { SND_RENDER_PLUGIN_LIST }; +static void +S_shutdown (void) +{ + if (snd_render_module) { + PI_UnloadPlugin (snd_render_module); + snd_render_module = NULL; + snd_render_funcs = NULL; + } + if (snd_output_module) { + PI_UnloadPlugin (snd_output_module); + snd_output_module = NULL; + } +} VISIBLE void S_Init (int *viewentity, double *host_frametime) @@ -65,6 +78,8 @@ S_Init (int *viewentity, double *host_frametime) return; } + Sys_RegisterShutdown (S_shutdown); + PI_RegisterPlugins (snd_output_list); PI_RegisterPlugins (snd_render_list); snd_output_module = PI_LoadPlugin ("snd_output", snd_output->string); @@ -120,20 +135,6 @@ S_AmbientOn (void) snd_render_funcs->pS_AmbientOn (); } -VISIBLE void -S_Shutdown (void) -{ - if (snd_render_module) { - PI_UnloadPlugin (snd_render_module); - snd_render_module = NULL; - snd_render_funcs = NULL; - } - if (snd_output_module) { - PI_UnloadPlugin (snd_output_module); - snd_output_module = NULL; - } -} - VISIBLE void S_StaticSound (sfx_t *sfx, const vec3_t origin, float vol, float attenuation) { diff --git a/libs/audio/targets/snd_alsa.c b/libs/audio/targets/snd_alsa.c index 76450bcc9..205153752 100644 --- a/libs/audio/targets/snd_alsa.c +++ b/libs/audio/targets/snd_alsa.c @@ -463,7 +463,7 @@ SNDDMA_GetDMAPos (void) } static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { qfsnd_pcm_close (pcm); @@ -549,7 +549,7 @@ PLUGIN_INFO(snd_output, alsa) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_disk.c b/libs/audio/targets/snd_disk.c index e24bc0e9f..878ca90ca 100644 --- a/libs/audio/targets/snd_disk.c +++ b/libs/audio/targets/snd_disk.c @@ -108,7 +108,7 @@ SNDDMA_GetDMAPos (void) } static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { Qclose (snd_file); @@ -174,7 +174,7 @@ PLUGIN_INFO(snd_output, disk) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_dx.c b/libs/audio/targets/snd_dx.c index 1bae2c3d0..3852a17a5 100644 --- a/libs/audio/targets/snd_dx.c +++ b/libs/audio/targets/snd_dx.c @@ -417,13 +417,8 @@ SNDDMA_Submit (void) DSOUND_LockBuffer (false); } -/* - SNDDMA_Shutdown - - Reset the sound device for exiting -*/ static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { FreeSound (); } @@ -450,7 +445,7 @@ DSOUND_LockBuffer (qboolean lockit) if (hresult != DSERR_BUFFERLOST) { Sys_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n"); - SNDDMA_Shutdown (); + SNDDMA_shutdown (); SNDDMA_Init (); return NULL; } @@ -458,7 +453,7 @@ DSOUND_LockBuffer (qboolean lockit) if (++reps > 10000) { Sys_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n"); - SNDDMA_Shutdown (); + SNDDMA_shutdown (); SNDDMA_Init (); return NULL; } @@ -529,7 +524,7 @@ PLUGIN_INFO(snd_output, dx) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_oss.c b/libs/audio/targets/snd_oss.c index 33349dc98..97383ff82 100644 --- a/libs/audio/targets/snd_oss.c +++ b/libs/audio/targets/snd_oss.c @@ -331,7 +331,7 @@ SNDDMA_GetDMAPos (void) } static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { if (mmaped_io) @@ -413,7 +413,7 @@ PLUGIN_INFO(snd_output, oss) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_sdl.c b/libs/audio/targets/snd_sdl.c index 91d5500f5..5e8dfc409 100644 --- a/libs/audio/targets/snd_sdl.c +++ b/libs/audio/targets/snd_sdl.c @@ -206,7 +206,7 @@ SNDDMA_GetDMAPos (void) } static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { SDL_CloseAudio (); @@ -297,7 +297,7 @@ PLUGIN_INFO(snd_output, sdl) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_sgi.c b/libs/audio/targets/snd_sgi.c index 4b431dbaf..27ae12d64 100644 --- a/libs/audio/targets/snd_sgi.c +++ b/libs/audio/targets/snd_sgi.c @@ -269,7 +269,7 @@ SNDDMA_GetDMAPos (void) } static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { free (write_buffer); @@ -357,7 +357,7 @@ PLUGIN_INFO(snd_output, sgi) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_sun.c b/libs/audio/targets/snd_sun.c index 89c649416..702757a34 100644 --- a/libs/audio/targets/snd_sun.c +++ b/libs/audio/targets/snd_sun.c @@ -189,7 +189,7 @@ SNDDMA_GetSamples (void) } #endif static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { if (snd_inited) { close (audio_fd); @@ -281,7 +281,7 @@ PLUGIN_INFO(snd_output, sun) plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_sound_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_sound_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_sound_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_sound_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_sound_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_sound_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/audio/targets/snd_win.c b/libs/audio/targets/snd_win.c index 91d4ce298..84465516c 100644 --- a/libs/audio/targets/snd_win.c +++ b/libs/audio/targets/snd_win.c @@ -344,13 +344,8 @@ SNDDMA_Submit (void) } } -/* - SNDDMA_Shutdown - - Reset the sound device for exiting -*/ static void -SNDDMA_Shutdown (void) +SNDDMA_shutdown (void) { FreeSound (); } @@ -379,7 +374,7 @@ PLUGIN_INFO(snd_output, win) plugin_info_general_funcs.p_Init = SNDDMA_Init_Cvars; plugin_info_general_funcs.p_Shutdown = NULL; plugin_info_snd_output_funcs.pS_O_Init = SNDDMA_Init; - plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_Shutdown; + plugin_info_snd_output_funcs.pS_O_Shutdown = SNDDMA_shutdown; plugin_info_snd_output_funcs.pS_O_GetDMAPos = SNDDMA_GetDMAPos; plugin_info_snd_output_funcs.pS_O_Submit = SNDDMA_Submit; plugin_info_snd_output_funcs.pS_O_BlockSound = SNDDMA_BlockSound; diff --git a/libs/console/client.c b/libs/console/client.c index ad31462a0..582113703 100644 --- a/libs/console/client.c +++ b/libs/console/client.c @@ -931,13 +931,13 @@ C_Init (void) } static void -C_Shutdown (void) +C_shutdown (void) { } static general_funcs_t plugin_info_general_funcs = { C_Init, - C_Shutdown, + C_shutdown, }; static console_funcs_t plugin_info_console_funcs = { diff --git a/libs/console/console.c b/libs/console/console.c index fbfdbd608..4801c0fdb 100644 --- a/libs/console/console.c +++ b/libs/console/console.c @@ -84,9 +84,20 @@ Con_Interp_f (cvar_t *var) } } +static void +Con_shutdown (void) +{ + if (con_module) { + con_module->functions->general->p_Shutdown (); + PI_UnloadPlugin (con_module); + } +} + VISIBLE void Con_Init (const char *plugin_name) { + Sys_RegisterShutdown (Con_shutdown); + con_module = PI_LoadPlugin ("console", plugin_name); if (con_module) { con_module->functions->general->p_Init (); @@ -123,15 +134,6 @@ Con_ExecLine (const char *line) Sys_Printf ("%s\n", line); } -VISIBLE void -Con_Shutdown (void) -{ - if (con_module) { - con_module->functions->general->p_Shutdown (); - PI_UnloadPlugin (con_module); - } -} - VISIBLE void Con_Printf (const char *fmt, ...) { diff --git a/libs/console/server.c b/libs/console/server.c index 83cce7f3d..5edd2a669 100644 --- a/libs/console/server.c +++ b/libs/console/server.c @@ -696,7 +696,7 @@ C_Init (void) } static void -C_Shutdown (void) +C_shutdown (void) { if (log_file) { Qclose (log_file); @@ -780,7 +780,7 @@ C_NewMap (void) static general_funcs_t plugin_info_general_funcs = { C_Init, - C_Shutdown, + C_shutdown, }; static general_data_t plugin_info_general_data; diff --git a/libs/net/nc/net_udp.c b/libs/net/nc/net_udp.c index 051785c5e..e349d5cd6 100644 --- a/libs/net/nc/net_udp.c +++ b/libs/net/nc/net_udp.c @@ -403,6 +403,17 @@ NET_GetLocalAddress (void) Sys_Printf ("IP address %s\n", NET_AdrToString (net_local_adr)); } +static void +NET_shutdown (void) +{ +#ifdef _WIN32 + closesocket (net_socket); + WSACleanup (); +#else + close (net_socket); +#endif +} + void NET_Init (int port) { @@ -416,6 +427,7 @@ NET_Init (int port) if (r) Sys_Error ("Winsock initialization failed."); #endif /* _WIN32 */ + Sys_RegisterShutdown (NET_shutdown); net_socket = UDP_OpenSocket (port); @@ -431,14 +443,3 @@ NET_Init (int port) Sys_Printf ("UDP (IPv4) Initialized\n"); } - -void -NET_Shutdown (void) -{ -#ifdef _WIN32 - closesocket (net_socket); - WSACleanup (); -#else - close (net_socket); -#endif -} diff --git a/libs/net/nc/net_udp6.c b/libs/net/nc/net_udp6.c index bad834082..c04092a83 100644 --- a/libs/net/nc/net_udp6.c +++ b/libs/net/nc/net_udp6.c @@ -600,8 +600,8 @@ NET_Init (int port) Sys_Printf ("UDP (IPv6) Initialized\n"); } -void -NET_Shutdown (void) +static void +NET_shutdown (void) { #ifdef _WIN32 closesocket (net_socket); diff --git a/libs/net/net_main.c b/libs/net/net_main.c index 7c235f4a9..051598003 100644 --- a/libs/net/net_main.c +++ b/libs/net/net_main.c @@ -718,6 +718,33 @@ NET_SendToAll (sizebuf_t *data, double blocktime) //============================================================================= +static void +NET_shutdown (void) +{ + qsocket_t *sock; + + SetNetTime (); + + for (sock = net_activeSockets; sock; sock = sock->next) + NET_Close (sock); + +// +// shutdown the drivers +// + for (net_driverlevel = 0; net_driverlevel < net_numdrivers; + net_driverlevel++) { + if (net_drivers[net_driverlevel].initialized == true) { + net_drivers[net_driverlevel].Shutdown (); + net_drivers[net_driverlevel].initialized = false; + } + } + + if (vcrFile) { + Sys_Printf ("Closing vcrfile.\n"); + Qclose (vcrFile); + } +} + void NET_Init (void) { @@ -725,6 +752,8 @@ NET_Init (void) int controlSocket; qsocket_t *s; + Sys_RegisterShutdown (NET_shutdown); + if (COM_CheckParm ("-playback")) { net_numdrivers = 1; net_drivers[0].Init = VCR_Init; @@ -790,33 +819,6 @@ NET_Init (void) Sys_MaskPrintf (SYS_NET, "TCP/IP address %s\n", my_tcpip_address); } -void -NET_Shutdown (void) -{ - qsocket_t *sock; - - SetNetTime (); - - for (sock = net_activeSockets; sock; sock = sock->next) - NET_Close (sock); - -// -// shutdown the drivers -// - for (net_driverlevel = 0; net_driverlevel < net_numdrivers; - net_driverlevel++) { - if (net_drivers[net_driverlevel].initialized == true) { - net_drivers[net_driverlevel].Shutdown (); - net_drivers[net_driverlevel].initialized = false; - } - } - - if (vcrFile) { - Sys_Printf ("Closing vcrfile.\n"); - Qclose (vcrFile); - } -} - static PollProcedure *pollProcedureList = NULL; diff --git a/libs/video/targets/context_sdl.c b/libs/video/targets/context_sdl.c index 7426ea8f8..7a764553a 100644 --- a/libs/video/targets/context_sdl.c +++ b/libs/video/targets/context_sdl.c @@ -53,12 +53,6 @@ VID_SetGamma (double gamma) return SDL_SetGamma((float) gamma, (float) gamma, (float) gamma); } -void -VID_Shutdown (void) -{ - SDL_Quit (); -} - static void VID_UpdateFullscreen (cvar_t *vid_fullscreen) { diff --git a/libs/video/targets/in_common.c b/libs/video/targets/in_common.c index d5bdf8bda..4b37f23d1 100644 --- a/libs/video/targets/in_common.c +++ b/libs/video/targets/in_common.c @@ -128,8 +128,8 @@ IN_Move (void) } /* Called at shutdown */ -void -IN_Shutdown (void) +static void +IN_shutdown (void) { JOY_Shutdown (); @@ -142,6 +142,8 @@ IN_Shutdown (void) void IN_Init (cbuf_t *cbuf) { + Sys_RegisterShutdown (IN_shutdown); + IE_Init (); IN_LL_Init (); Key_Init (cbuf); diff --git a/libs/video/targets/vid_3dfxsvga.c b/libs/video/targets/vid_3dfxsvga.c index e7df1f342..68078703f 100644 --- a/libs/video/targets/vid_3dfxsvga.c +++ b/libs/video/targets/vid_3dfxsvga.c @@ -150,8 +150,8 @@ QFGL_LoadLibrary (void) #endif // HAVE_DLOPEN -void -VID_Shutdown (void) +static void +VID_shutdown (void) { if (!fc) return; @@ -271,6 +271,8 @@ VID_Init (byte *palette, byte *colormap) { GLint attribs[32]; + Sys_RegisterShutdown (VID_shutdown); + GLF_Init (); qf_fxMesaCreateContext = QFGL_ProcAddress (libgl_handle, diff --git a/libs/video/targets/vid_fbdev.c b/libs/video/targets/vid_fbdev.c index 5cd81cc47..84e3db80a 100644 --- a/libs/video/targets/vid_fbdev.c +++ b/libs/video/targets/vid_fbdev.c @@ -209,8 +209,8 @@ static unsigned long fb_map_length = 0; static struct fb_var_screeninfo orig_var; -void -VID_Shutdown (void) +static void +VID_shutdown (void) { Sys_MaskPrintf (SYS_VID, "VID_Shutdown\n"); @@ -406,6 +406,8 @@ VID_Init (byte *palette, byte *colormap) if (fbdev_inited) return; + Sys_RegisterShutdown (VID_shutdown); + R_LoadModule (0, VID_SetPalette); if (COM_CheckParm ("-novideo")) { diff --git a/libs/video/targets/vid_sdl.c b/libs/video/targets/vid_sdl.c index 9b1938d30..80f005328 100644 --- a/libs/video/targets/vid_sdl.c +++ b/libs/video/targets/vid_sdl.c @@ -64,9 +64,17 @@ static vid_internal_t vid_internal; uint32_t sdl_flags; +static void +VID_shutdown (void) +{ + SDL_Quit (); +} + void VID_Init (byte *palette, byte *colormap) { + Sys_RegisterShutdown (VID_shutdown); + vid_internal.gl_context = SDL_GL_Context; vid_internal.sw_context = SDL_SW_Context; // Load the SDL library diff --git a/libs/video/targets/vid_svgalib.c b/libs/video/targets/vid_svgalib.c index 8849a4eb5..91e0414b8 100644 --- a/libs/video/targets/vid_svgalib.c +++ b/libs/video/targets/vid_svgalib.c @@ -239,8 +239,8 @@ get_mode (int width, int height, int depth) return i; } -void -VID_Shutdown (void) +static void +VID_shutdown (void) { Sys_MaskPrintf (SYS_VID, "VID_Shutdown\n"); @@ -358,6 +358,8 @@ VID_Init (byte *palette, byte *colormap) if (svgalib_inited) return; + Sys_RegisterShutdown (VID_shutdown); + err = vga_init (); if (err) Sys_Error ("SVGALib failed to allocate a new VC"); diff --git a/libs/video/targets/vid_wgl.c b/libs/video/targets/vid_wgl.c index bec07fe19..a9054510b 100644 --- a/libs/video/targets/vid_wgl.c +++ b/libs/video/targets/vid_wgl.c @@ -372,8 +372,8 @@ GL_EndRendering (void) } } -void -VID_Shutdown (void) +static void +VID_shutdown (void) { HGLRC hRC; HDC hDC; @@ -454,6 +454,8 @@ VID_Init (byte *palette, byte *colormap) DWORD lasterror; WNDCLASS wc; + Sys_RegisterShutdown (VID_shutdown); + vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ROM | CVAR_ARCHIVE, NULL, "Run WGL client at fullscreen"); GLF_Init (); diff --git a/libs/video/targets/vid_x11.c b/libs/video/targets/vid_x11.c index 946824547..18f56c305 100644 --- a/libs/video/targets/vid_x11.c +++ b/libs/video/targets/vid_x11.c @@ -83,6 +83,13 @@ D_EndDirectRect (int x, int y, int width, int height) // direct drawing of the "accessing disk" icon isn't supported } +static void +VID_shutdown (void) +{ + Sys_MaskPrintf (SYS_VID, "VID_shutdown\n"); + X11_CloseDisplay (); +} + /* Set up color translation tables and the window. Takes a 256-color 8-bit palette. Palette data will go away after the call, so copy it if you'll @@ -91,6 +98,8 @@ D_EndDirectRect (int x, int y, int width, int height) void VID_Init (byte *palette, byte *colormap) { + Sys_RegisterShutdown (VID_shutdown); + vid_internal.gl_context = X11_GL_Context; vid_internal.sw_context = X11_SW_Context; #ifdef HAVE_VULKAN @@ -133,18 +142,6 @@ VID_Init_Cvars () X11_GL_Init_Cvars (); } -/* - VID_Shutdown - - Restore video mode -*/ -void -VID_Shutdown (void) -{ - Sys_MaskPrintf (SYS_VID, "VID_Shutdown\n"); - X11_CloseDisplay (); -} - #if 0 static int config_notify = 0; static int config_notify_width; diff --git a/nq/include/client.h b/nq/include/client.h index 54477f7b4..817bebaf6 100644 --- a/nq/include/client.h +++ b/nq/include/client.h @@ -286,7 +286,6 @@ extern void (*write_angles) (sizebuf_t *sb, const vec3_t angles); struct cbuf_s; void CL_Init (struct cbuf_s *cbuf); void CL_InitCvars (void); -void CL_Shutdown (void); void CL_ClearMemory (void); void CL_EstablishConnection (const char *host); diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index 3f8e7bde6..672269c9f 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -120,14 +120,10 @@ CL_WriteConfiguration (void) } } -void +static void CL_Shutdown (void) { CL_WriteConfiguration (); - CDAudio_Shutdown (); - S_Shutdown (); - IN_Shutdown (); - VID_Shutdown (); } void @@ -537,6 +533,8 @@ CL_Init (cbuf_t *cbuf) { byte *basepal, *colormap; + Sys_RegisterShutdown (CL_Shutdown); + basepal = (byte *) QFS_LoadHunkFile (QFS_FOpenFile ("gfx/palette.lmp")); if (!basepal) Sys_Error ("Couldn't load gfx/palette.lmp"); diff --git a/nq/source/host.c b/nq/source/host.c index d15dd0431..0d85b9a1a 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -968,11 +968,4 @@ Host_Shutdown (void) return; } isdown = true; - - - NET_Shutdown (); - if (cls.state != ca_dedicated) { - CL_Shutdown (); - } - Con_Shutdown (); } diff --git a/nq/source/sv_ded.c b/nq/source/sv_ded.c index 44dd57408..7db231bd2 100644 --- a/nq/source/sv_ded.c +++ b/nq/source/sv_ded.c @@ -98,11 +98,6 @@ CL_EstablishConnection (const char *host) { } -void -CL_Shutdown () -{ -} - void CL_Init (struct cbuf_s *cbuf) { diff --git a/qtv/source/qtv.c b/qtv/source/qtv.c index 4980dea9b..2f9f826ad 100644 --- a/qtv/source/qtv.c +++ b/qtv/source/qtv.c @@ -222,8 +222,6 @@ qtv_memory_init (void) static void qtv_shutdown (void) { - NET_Shutdown (); - Con_Shutdown (); Cbuf_Delete (qtv_cbuf); Cbuf_ArgsDelete (qtv_args); } diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index c2b3c3a35..3cb0e1432 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -1882,10 +1882,5 @@ Host_Shutdown (void) Host_WriteConfiguration (); - CDAudio_Shutdown (); CL_HTTP_Shutdown (); - NET_Shutdown (); - S_Shutdown (); - IN_Shutdown (); - VID_Shutdown (); } diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index c69e23594..a121ba5ce 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -246,9 +246,6 @@ SV_Shutdown (void) } if (sv.recording_demo) SV_Stop (0); - - NET_Shutdown (); - Con_Shutdown (); } /* diff --git a/tools/qwaq/qwaq-bi.c b/tools/qwaq/qwaq-bi.c index 7e21a9259..cad5108f3 100644 --- a/tools/qwaq/qwaq-bi.c +++ b/tools/qwaq/qwaq-bi.c @@ -161,9 +161,6 @@ static builtin_t builtins[] = { static void bi_shutdown (void) { - S_Shutdown (); - IN_Shutdown (); - VID_Shutdown (); } void From 1eafc330527ae738dd2e088ca4837cded151c067 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 13 Jul 2019 00:36:21 +0900 Subject: [PATCH 035/435] Ensure vulkan gets shut down --- include/QF/Vulkan/device.h | 5 +++-- include/QF/Vulkan/funclist.h | 6 ++++++ include/QF/Vulkan/swapchain.h | 1 + libs/video/renderer/r_init.c | 9 +++++++++ libs/video/renderer/vulkan/device.c | 17 ++++++++--------- libs/video/renderer/vulkan/swapchain.c | 8 ++++++++ libs/video/renderer/vulkan/vulkan_vid_common.c | 2 ++ 7 files changed, 37 insertions(+), 11 deletions(-) diff --git a/include/QF/Vulkan/device.h b/include/QF/Vulkan/device.h index ae0c26ffc..8dc4df371 100644 --- a/include/QF/Vulkan/device.h +++ b/include/QF/Vulkan/device.h @@ -20,7 +20,8 @@ typedef struct qfv_device_s { } qfv_device_t; struct vulkan_ctx_s; -qfv_device_t *QFV_CreateDevice(struct vulkan_ctx_s *ctx, - const char **extensions); +qfv_device_t *QFV_CreateDevice (struct vulkan_ctx_s *ctx, + const char **extensions); +void QFV_DestroyDevice (qfv_device_t *device); #endif//__QF_Vulkan_swapchain_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 1419aebd4..43bad39c7 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -48,6 +48,8 @@ INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkGetPhysicalDeviceSurfaceCapabilitiesKHR, VK_KHR_SURFACE_EXTENSION_NAME) INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkGetPhysicalDeviceSurfaceFormatsKHR, VK_KHR_SURFACE_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkDestroySurfaceKHR, VK_KHR_SURFACE_EXTENSION_NAME) #undef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION @@ -99,5 +101,9 @@ DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkDestroySwapchainKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkGetSwapchainImagesKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkAcquireNextImageKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkQueuePresentKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) #undef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION diff --git a/include/QF/Vulkan/swapchain.h b/include/QF/Vulkan/swapchain.h index 71d0b6d75..91d158c89 100644 --- a/include/QF/Vulkan/swapchain.h +++ b/include/QF/Vulkan/swapchain.h @@ -13,5 +13,6 @@ typedef struct qfv_swapchain_s { struct vulkan_ctx_s; qfv_swapchain_t *QFV_CreateSwapchain (struct vulkan_ctx_s *ctx, VkSwapchainKHR old_swapchain); +void QFV_DestroySwapchain (qfv_swapchain_t *swapchain); #endif//__QF_Vulkan_swapchain_h diff --git a/libs/video/renderer/r_init.c b/libs/video/renderer/r_init.c index 330d0d76d..df2392a6b 100644 --- a/libs/video/renderer/r_init.c +++ b/libs/video/renderer/r_init.c @@ -63,6 +63,14 @@ vid_render_funcs_t *r_funcs; static U void (*const r_progs_init)(struct progs_s *) = R_Progs_Init; #undef U +static void +R_shutdown (void) +{ + if (vidrendmodule->functions->general->p_Shutdown) { + vidrendmodule->functions->general->p_Shutdown (); + } +} + VISIBLE void R_LoadModule (vid_internal_t *vid_internal) { @@ -80,6 +88,7 @@ R_LoadModule (vid_internal_t *vid_internal) r_data->vid->vid_internal = vid_internal; vidrendmodule->functions->general->p_Init (); + Sys_RegisterShutdown (R_shutdown); } VISIBLE void diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index 36b81b025..736b5e915 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -133,9 +133,6 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) { uint32_t nlay = 1; // ensure alloca doesn't see 0 and terminated uint32_t next = count_strings (extensions) + 1; // ensure terminated - //if (vulkan_use_validation->int_val) { - // nlay += count_strings (vulkanValidationLayers); - //} const char **lay = alloca (nlay * sizeof (const char *)); const char **ext = alloca (next * sizeof (const char *)); // ensure there are null pointers so merge_strings can act as append @@ -144,9 +141,6 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) memset (lay, 0, nlay-- * sizeof (const char *)); memset (ext, 0, next-- * sizeof (const char *)); merge_strings (ext, extensions, 0); - //if (vulkan_use_validation->int_val) { - // merge_strings (lay, lay, vulkanValidationLayers); - //} qfv_instance_t *inst = ctx->instance; VkInstance instance = inst->instance; @@ -160,9 +154,6 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) for (uint32_t i = 0; i < numDevices; i++) { VkPhysicalDevice physdev = devices[i]; /* - if (!Vulkan_LayersSupported (phys->layers, phys->numLayers, lay)) { - continue; - } if (!Vulkan_ExtensionsSupported (phys->extensions, phys->numExtensions, ext)) { continue; @@ -209,3 +200,11 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) } return 0; } + +void +QFV_DestroyDevice (qfv_device_t *device) +{ + device->funcs->vkDestroyDevice (device->dev, 0); + del_strset (device->enabled_extensions); + free (device); +} diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c index 91f8280c9..2707676d6 100644 --- a/libs/video/renderer/vulkan/swapchain.c +++ b/libs/video/renderer/vulkan/swapchain.c @@ -146,3 +146,11 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) sc->images); return sc; } + +void +QFV_DestroySwapchain (qfv_swapchain_t *swapchain) +{ + swapchain->funcs->vkDestroySwapchainKHR (swapchain->dev, + swapchain->swapchain, 0); + free (swapchain); +} diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 70890ab7a..ed5369c9c 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -116,6 +116,8 @@ Vulkan_Init_Common (vulkan_ctx_t *ctx) void Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) { + Sys_Printf ("are we here?\n"); + QFV_DestroyDevice (ctx->device); QFV_DestroyInstance (ctx->instance); ctx->instance = 0; ctx->unload_vulkan (ctx); From b4dc746a66886319e1a2a607fd53ee2ba6e12cc8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 13 Jul 2019 01:11:34 +0900 Subject: [PATCH 036/435] Clean up the debug callback --- include/QF/Vulkan/funclist.h | 2 ++ include/QF/Vulkan/instance.h | 1 + libs/video/renderer/vulkan/instance.c | 12 +++++++++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 43bad39c7..5fe467937 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -40,6 +40,8 @@ INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceMemoryProperties) INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkCreateDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkDestroyDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkGetPhysicalDeviceSurfaceSupportKHR, VK_KHR_SURFACE_EXTENSION_NAME) INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION diff --git a/include/QF/Vulkan/instance.h b/include/QF/Vulkan/instance.h index 1cc05d6cf..0a677c945 100644 --- a/include/QF/Vulkan/instance.h +++ b/include/QF/Vulkan/instance.h @@ -42,6 +42,7 @@ typedef struct qfv_instance_s { struct strset_s *enabled_extensions; int (*extension_enabled) (struct qfv_instance_s *inst, const char *ext); + VkDebugUtilsMessengerEXT debug_handle; } qfv_instance_t; struct vulkan_ctx_s; diff --git a/libs/video/renderer/vulkan/instance.c b/libs/video/renderer/vulkan/instance.c index 74b0ea756..25ccdb306 100644 --- a/libs/video/renderer/vulkan/instance.c +++ b/libs/video/renderer/vulkan/instance.c @@ -150,7 +150,7 @@ debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, static void setup_debug_callback (qfv_instance_t *instance) { - VkDebugUtilsMessengerEXT debug_callback_handle; + VkDebugUtilsMessengerEXT debug_handle; VkDebugUtilsMessengerCreateInfoEXT createInfo = { .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, .messageSeverity = message_severities, @@ -160,7 +160,8 @@ setup_debug_callback (qfv_instance_t *instance) }; instance->funcs->vkCreateDebugUtilsMessengerEXT(instance->instance, &createInfo, 0, - &debug_callback_handle); + &debug_handle); + instance->debug_handle = debug_handle; } static void @@ -242,7 +243,7 @@ QFV_CreateInstance (vulkan_ctx_t *ctx, if (res != VK_SUCCESS) { Sys_Error ("unable to create vulkan instance\n"); } - qfv_instance_t *inst = malloc (sizeof(qfv_instance_t) + qfv_instance_t *inst = calloc (1, sizeof(qfv_instance_t) + sizeof (qfv_instfuncs_t)); inst->instance = instance; inst->funcs = (qfv_instfuncs_t *)(inst + 1); @@ -261,6 +262,11 @@ QFV_CreateInstance (vulkan_ctx_t *ctx, void QFV_DestroyInstance (qfv_instance_t *instance) { + qfv_instfuncs_t *ifunc = instance->funcs; + if (instance->debug_handle) { + ifunc->vkDestroyDebugUtilsMessengerEXT (instance->instance, + instance->debug_handle, 0); + } instance->funcs->vkDestroyInstance (instance->instance, 0); free (instance); } From dd1c2db2496ad55eb7cbc9fe1251ec4dff8c3e4f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 13 Jul 2019 01:14:21 +0900 Subject: [PATCH 037/435] Clean up the swapchain And be a little safer about it --- libs/video/renderer/vulkan/vulkan_vid_common.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index ed5369c9c..6d8c32505 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -116,9 +116,15 @@ Vulkan_Init_Common (vulkan_ctx_t *ctx) void Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) { - Sys_Printf ("are we here?\n"); - QFV_DestroyDevice (ctx->device); - QFV_DestroyInstance (ctx->instance); + if (ctx->swapchain) { + QFV_DestroySwapchain (ctx->swapchain); + } + if (ctx->device) { + QFV_DestroyDevice (ctx->device); + } + if (ctx->instance) { + QFV_DestroyInstance (ctx->instance); + } ctx->instance = 0; ctx->unload_vulkan (ctx); } From 1f24a1408acdcc48be2010cc38d5e936fb2ee0b7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 13 Jul 2019 01:20:02 +0900 Subject: [PATCH 038/435] Destroy the surface --- libs/video/renderer/vulkan/vulkan_vid_common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 6d8c32505..37fe9c564 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -119,6 +119,8 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) if (ctx->swapchain) { QFV_DestroySwapchain (ctx->swapchain); } + ctx->instance->funcs->vkDestroySurfaceKHR (ctx->instance->instance, + ctx->surface, 0); if (ctx->device) { QFV_DestroyDevice (ctx->device); } From e16400205027956978fec72c895264b93251d41d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Jul 2019 08:52:15 +0900 Subject: [PATCH 039/435] Make QuatToMat faster and more accurate The better accuracy is for specific cases (90 degree rotations around a main axis: the matrix element for that axis is now 1 instead of 0.99999994). The speedup comes from doing fewer additions (multiply seems to be faster than add for fp, at least in this situation). --- libs/util/mathlib.c | 34 ++++++++++---------- libs/util/test/test-quat.c | 64 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/libs/util/mathlib.c b/libs/util/mathlib.c index db68455f3..3e6540636 100644 --- a/libs/util/mathlib.c +++ b/libs/util/mathlib.c @@ -303,7 +303,7 @@ QuatExp (const quat_t a, quat_t b) VISIBLE void QuatToMatrix (const quat_t q, vec_t *m, int homogenous, int vertical) { - vec_t xx, xy, xz, xw, yy, yz, yw, zz, zw, ww; + vec_t xx, xy, xz, xw, yy, yz, yw, zz, zw; vec_t *_m[4] = { m + (homogenous ? 0 : 0), m + (homogenous ? 4 : 3), @@ -311,28 +311,26 @@ QuatToMatrix (const quat_t q, vec_t *m, int homogenous, int vertical) m + (homogenous ? 12 : 9), }; - xx = q[0] * q[0]; - xy = q[0] * q[1]; - xz = q[0] * q[2]; - xw = q[0] * q[3]; + xx = 2 * q[0] * q[0]; + xy = 2 * q[0] * q[1]; + xz = 2 * q[0] * q[2]; + xw = 2 * q[0] * q[3]; - yy = q[1] * q[1]; - yz = q[1] * q[2]; - yw = q[1] * q[3]; + yy = 2 * q[1] * q[1]; + yz = 2 * q[1] * q[2]; + yw = 2 * q[1] * q[3]; - zz = q[2] * q[2]; - zw = q[2] * q[3]; - - ww = q[3] * q[3]; + zz = 2 * q[2] * q[2]; + zw = 2 * q[2] * q[3]; if (vertical) { - VectorSet (ww + xx - yy - zz, 2 * (xy + zw), 2 * (xz - yw), _m[0]); - VectorSet (2 * (xy - zw), ww - xx + yy - zz, 2 * (yz + xw), _m[1]); - VectorSet (2 * (xz + yw), 2 * (yz - xw), ww - xx - yy + zz, _m[2]); + VectorSet (1.0f - yy - zz, xy + zw, xz - yw, _m[0]); + VectorSet (xy - zw, 1.0f - xx - zz, yz + xw, _m[1]); + VectorSet (xz + yw, yz - xw, 1.0f - xx - yy, _m[2]); } else { - VectorSet (ww + xx - yy - zz, 2 * (xy - zw), 2 * (xz + yw), _m[0]); - VectorSet (2 * (xy + zw), ww - xx + yy - zz, 2 * (yz - xw), _m[1]); - VectorSet (2 * (xz - yw), 2 * (yz + xw), ww - xx - yy + zz, _m[2]); + VectorSet (1.0f - yy - zz, xy - zw, xz + yw, _m[0]); + VectorSet (xy + zw, 1.0f - xx - zz, yz - xw, _m[1]); + VectorSet (xz - yw, yz + xw, 1.0f - xx - yy, _m[2]); } if (homogenous) { _m[0][3] = 0; diff --git a/libs/util/test/test-quat.c b/libs/util/test/test-quat.c index 47539d144..44c8923b3 100644 --- a/libs/util/test/test-quat.c +++ b/libs/util/test/test-quat.c @@ -200,6 +200,62 @@ fail: return 0; } +#define s05 0.70710678118654757 + +static struct { + quat_t q; + vec_t expect[9]; +} quat_mat_tests[] = { + {{0, 0, 0, 1}, + {1, 0, 0, + 0, 1, 0, + 0, 0, 1}}, + {{1, 0, 0, 0}, + {1, 0, 0, + 0, -1, 0, + 0, 0, -1}}, + {{0, 1, 0, 0}, + {-1, 0, 0, + 0, 1, 0, + 0, 0, -1}}, + {{0, 0, 1, 0}, + {-1, 0, 0, + 0, -1, 0, + 0, 0, 1}}, + {{0.5, 0.5, 0.5, 0.5}, + {0, 0, 1, + 1, 0, 0, + 0, 1, 0}}, + {{s05, 0.0, 0.0, s05}, + {1, 0, 0, + 0, 5.96046448e-8, -0.99999994, + 0, 0.99999994, 5.96046448e-8}}, +}; +#define num_quat_mat_tests (sizeof (quat_mat_tests) / sizeof (quat_mat_tests[0])) + +static int +test_quat_mat(const quat_t q, const quat_t expect) +{ + int i; + vec_t m[9]; + + QuatToMatrix (q, m, 0, 0); + + for (i = 0; i < 9; i++) + if (m[i] != expect[i]) // exact tests here + goto fail; + return 1; +fail: + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (q)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 0), VectorExpand (expect + 0)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 3), VectorExpand (expect + 3)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 6), VectorExpand (expect + 6)); + return 0; +} + int main (int argc, const char **argv) { @@ -228,5 +284,13 @@ main (int argc, const char **argv) if (!test_rotation3 (test_angles[i])) res = 1; } + + for (i = 0; i < num_quat_mat_tests; i ++) { + vec_t *q = quat_mat_tests[i].q; + vec_t *expect = quat_mat_tests[i].expect; + if (!test_quat_mat (q, expect)) + res = 1; + } + return res; } From ae11a70147c05ba5e15ff29c213d49b362bdc039 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Jul 2019 12:27:57 +0900 Subject: [PATCH 040/435] Correct a comment --- include/QF/Vulkan/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/Vulkan/device.h b/include/QF/Vulkan/device.h index 8dc4df371..0a90ea539 100644 --- a/include/QF/Vulkan/device.h +++ b/include/QF/Vulkan/device.h @@ -24,4 +24,4 @@ qfv_device_t *QFV_CreateDevice (struct vulkan_ctx_s *ctx, const char **extensions); void QFV_DestroyDevice (qfv_device_t *device); -#endif//__QF_Vulkan_swapchain_h +#endif//__QF_Vulkan_device_h From 411b897f09f8d89c19c361cf86ffef044dce5441 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Jul 2019 12:28:57 +0900 Subject: [PATCH 041/435] Implement most of the stuff for command submission --- include/QF/Vulkan/command.h | 79 +++++++ include/QF/Vulkan/funclist.h | 11 + libs/video/renderer/vulkan/Makefile.am | 1 + libs/video/renderer/vulkan/command.c | 316 +++++++++++++++++++++++++ 4 files changed, 407 insertions(+) create mode 100644 include/QF/Vulkan/command.h create mode 100644 libs/video/renderer/vulkan/command.c diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h new file mode 100644 index 000000000..1fe12df6d --- /dev/null +++ b/include/QF/Vulkan/command.h @@ -0,0 +1,79 @@ +#ifndef __QF_Vulkan_command_h +#define __QF_Vulkan_command_h + +typedef struct qfv_cmdpool_s { + VkDevice dev; + struct qfv_devfuncs_s *funcs; + VkCommandPool cmdpool; +} qfv_cmdpool_t; + +typedef struct qfv_cmdbuffer_s { + VkDevice dev; + struct qfv_devfuncs_s *funcs; + VkCommandBuffer buffer; +} qfv_cmdbuffer_t; + +typedef struct qfv_cmdbufferset_s { + VkDevice dev; + struct qfv_devfuncs_s *funcs; + VkCommandBuffer *buffers; + int numBuffers; +} qfv_cmdbufferset_t; + +typedef struct qfv_semaphore_s { + VkDevice dev; + struct qfv_devfuncs_s *funcs; + VkSemaphore semaphore; +} qfv_semaphore_t; + +typedef struct qfv_semaphoreset_s { + VkDevice dev; + struct qfv_devfuncs_s *funcs; + VkSemaphore *semaphores; + VkPipelineStageFlags *stages; + int numSemaphores; +} qfv_semaphoreset_t; + +typedef struct qfv_fence_s { + VkDevice dev; + struct qfv_devfuncs_s *funcs; + VkFence fence; +} qfv_fence_t; + +typedef struct qfv_fenceset_s { + VkDevice dev; + struct qfv_devfuncs_s *funcs; + VkFence *fences; + int numFences; +} qfv_fenceset_t; + +struct qfv_device_s; +qfv_cmdpool_t *QFV_CreateCommandPool (struct qfv_device_s *device, + uint32_t queueFamily, + int transient, int reset); +int QFV_ResetCommandPool (qfv_cmdpool_t *pool, int release); +qfv_cmdbuffer_t *QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, + int secondary, int count); +qfv_cmdbufferset_t *QFV_CreateCommandBufferSet (qfv_cmdbuffer_t **buffers, + int numBuffers); +int QFV_BeginCommandBuffer (qfv_cmdbuffer_t *buffer, int oneTime, + int rpContinue, int simultaneous, + VkCommandBufferInheritanceInfo *inheritanceInfo); +int QFV_EndCommandBuffer (qfv_cmdbuffer_t *buffer); +int QFV_ResetCommandBuffer (qfv_cmdbuffer_t *buffer, int release); + +qfv_semaphore_t *QFV_CreateSemaphore (struct qfv_device_s *device); +qfv_semaphoreset_t *QFV_CreateSemaphoreSet (qfv_semaphore_t **semaphores, + int numSemaphores); + +qfv_fence_t *QFV_CreateFence (struct qfv_device_s *device, int signaled); +qfv_fenceset_t *QFV_CreateFenceSet (qfv_fence_t **fences, int numFences); +int QFV_WaitForFences (qfv_fenceset_t *fences, int all, uint64_t timeout); +int QFV_ResetFences (qfv_fenceset_t *fences); +int QFV_QueueSubmit (struct qfv_device_s *device, + qfv_semaphoreset_t *waitSemaphores, + qfv_cmdbufferset_t *buffers, + qfv_semaphoreset_t *signalSemaphores, qfv_fence_t *fence); + + +#endif//__QF_Vulkan_command_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 5fe467937..20ccbe275 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -90,6 +90,17 @@ PRESENTATION_VULKAN_FUNCTION_FROM_EXTENSION DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyDevice) DEVICE_LEVEL_VULKAN_FUNCTION (vkGetDeviceQueue) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateCommandPool) +DEVICE_LEVEL_VULKAN_FUNCTION (vkResetCommandPool) +DEVICE_LEVEL_VULKAN_FUNCTION (vkAllocateCommandBuffers) +DEVICE_LEVEL_VULKAN_FUNCTION (vkBeginCommandBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkEndCommandBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkResetCommandBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateSemaphore) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateFence) +DEVICE_LEVEL_VULKAN_FUNCTION (vkWaitForFences) +DEVICE_LEVEL_VULKAN_FUNCTION (vkResetFences) +DEVICE_LEVEL_VULKAN_FUNCTION (vkQueueSubmit) #undef DEVICE_LEVEL_VULKAN_FUNCTION diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index e59e29551..f754853f2 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -4,6 +4,7 @@ AM_CFLAGS= @PREFER_PIC@ AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES vulkan_src = \ + command.c \ device.c \ instance.c \ swapchain.c \ diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c new file mode 100644 index 000000000..13dbde1a6 --- /dev/null +++ b/libs/video/renderer/vulkan/command.c @@ -0,0 +1,316 @@ +/* + vid_common_vulkan.c + + Common Vulkan video driver functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2019 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +qfv_cmdpool_t * +QFV_CreateCommandPool (qfv_device_t *device, uint32_t queueFamily, + int transient, int reset) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + uint32_t flags = 0; + if (transient) { + flags |= VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; + } + if (reset) { + flags |= VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + } + VkCommandPoolCreateInfo createInfo = { + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 0, + flags, + queueFamily + }; + qfv_cmdpool_t *cmdpool = malloc (sizeof (*cmdpool)); + dfunc->vkCreateCommandPool (dev, &createInfo, 0, &cmdpool->cmdpool); + cmdpool->dev = dev; + cmdpool->funcs = dfunc; + return cmdpool; +} + +int +QFV_ResetCommandPool (qfv_cmdpool_t *pool, int release) +{ + VkDevice dev = pool->dev; + VkCommandPool cmdpool = pool->cmdpool; + qfv_devfuncs_t *dfunc = pool->funcs; + VkCommandPoolResetFlags release_flag = 0; + + if (release) { + release_flag = VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT; + } + + return dfunc->vkResetCommandPool (dev, cmdpool, release_flag) == VK_SUCCESS; +} + +qfv_cmdbuffer_t * +QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count) +{ + VkDevice dev = pool->dev; + qfv_devfuncs_t *dfunc = pool->funcs; + uint32_t level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + if (secondary) { + level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + } + VkCommandBufferAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, + pool->cmdpool, level, count + }; + qfv_cmdbuffer_t *cmdbuffers = malloc (count * sizeof (*cmdbuffers)); + VkCommandBuffer *buffers = alloca (count * sizeof (*buffers)); + dfunc->vkAllocateCommandBuffers (dev, &allocInfo, buffers); + for (int i = 0; i < count; i++) { + cmdbuffers[i].dev = dev; + cmdbuffers[i].funcs = dfunc; + cmdbuffers[i].buffer = buffers[i]; + } + return cmdbuffers; +} + +qfv_cmdbufferset_t * +QFV_CreateCommandBufferSet (qfv_cmdbuffer_t **buffers, int numBuffers) +{ + VkDevice dev = buffers[0]->dev; + qfv_devfuncs_t *dfunc = buffers[0]->funcs; + qfv_cmdbufferset_t *bufferset = malloc (sizeof (*bufferset) + + sizeof (VkCommandBuffer) + * numBuffers); + + bufferset->dev = dev; + bufferset->funcs = dfunc; + bufferset->buffers = (VkCommandBuffer *) (bufferset + 1); + bufferset->numBuffers = numBuffers; + + for (int i = 0; i < numBuffers; i++) { + bufferset->buffers[i] = buffers[i]->buffer; + } + return bufferset; +} + +int +QFV_BeginCommandBuffer (qfv_cmdbuffer_t *buffer, int oneTime, int rpContinue, + int simultaneous, + VkCommandBufferInheritanceInfo *inheritanceInfo) +{ + VkCommandBuffer buff = buffer->buffer; + qfv_devfuncs_t *dfunc = buffer->funcs; + VkCommandBufferUsageFlags usage = 0; + + if (oneTime) { + usage |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + } + if (rpContinue) { + usage |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; + } + if (simultaneous) { + usage |= VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + } + + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + usage, + 0 + }; + + return dfunc->vkBeginCommandBuffer (buff, &beginInfo) == VK_SUCCESS; +} + +int +QFV_EndCommandBuffer (qfv_cmdbuffer_t *buffer) +{ + VkCommandBuffer buff = buffer->buffer; + qfv_devfuncs_t *dfunc = buffer->funcs; + + return dfunc->vkEndCommandBuffer (buff) == VK_SUCCESS; +} + +int +QFV_ResetCommandBuffer (qfv_cmdbuffer_t *buffer, int release) +{ + VkCommandBuffer buff = buffer->buffer; + qfv_devfuncs_t *dfunc = buffer->funcs; + VkCommandBufferResetFlags release_flag = 0; + + if (release) { + release_flag = VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT; + } + + return dfunc->vkResetCommandBuffer (buff, release_flag) == VK_SUCCESS; +} + +qfv_semaphore_t * +QFV_CreateSemaphore (qfv_device_t *device) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkSemaphoreCreateInfo createInfo = { + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 0, + 0 + }; + + qfv_semaphore_t *semaphore = malloc (sizeof (*semaphore)); + semaphore->dev = dev; + semaphore->funcs = dfunc; + + dfunc->vkCreateSemaphore (dev, &createInfo, 0, &semaphore->semaphore); + return semaphore; +} + +qfv_semaphoreset_t * +QFV_CreateSemaphoreSet (qfv_semaphore_t **semaphores, int numSemaphores) +{ + VkDevice dev = semaphores[0]->dev; + qfv_devfuncs_t *dfunc = semaphores[0]->funcs; + qfv_semaphoreset_t *semaphoreset; + semaphoreset = calloc (1, sizeof (*semaphoreset) + + sizeof (VkSemaphore) * numSemaphores + + sizeof (VkPipelineStageFlags) * numSemaphores); + + semaphoreset->dev = dev; + semaphoreset->funcs = dfunc; + semaphoreset->semaphores = (VkSemaphore *) (semaphoreset + 1); + semaphoreset->stages = (VkPipelineStageFlags *) + &semaphoreset->semaphores[numSemaphores]; + semaphoreset->numSemaphores = numSemaphores; + + for (int i = 0; i < numSemaphores; i++) { + semaphoreset->semaphores[i] = semaphores[i]->semaphore; + } + return semaphoreset; +} + +qfv_fence_t * +QFV_CreateFence (qfv_device_t *device, int signaled) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkFenceCreateInfo createInfo = { + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 0, + signaled ? VK_FENCE_CREATE_SIGNALED_BIT : 0, + }; + + qfv_fence_t *fence = malloc (sizeof (*fence)); + fence->dev = dev; + fence->funcs = dfunc; + + dfunc->vkCreateFence (dev, &createInfo, 0, &fence->fence); + return fence; +} + +qfv_fenceset_t * +QFV_CreateFenceSet (qfv_fence_t **fences, int numFences) +{ + VkDevice dev = fences[0]->dev; + qfv_devfuncs_t *dfunc = fences[0]->funcs; + qfv_fenceset_t *fenceset = malloc (sizeof (*fenceset) + + sizeof (VkFence) * numFences); + + fenceset->dev = dev; + fenceset->funcs = dfunc; + fenceset->fences = (VkFence *) (fenceset + 1); + fenceset->numFences = numFences; + + for (int i = 0; i < numFences; i++) { + fenceset->fences[i] = fences[i]->fence; + } + return fenceset; +} + +int +QFV_WaitForFences (qfv_fenceset_t *fences, int all, uint64_t timeout) +{ + VkDevice dev = fences->dev; + qfv_devfuncs_t *dfunc = fences->funcs; + + VkResult res = dfunc->vkWaitForFences (dev, fences->numFences, + fences->fences, all, timeout); + return res == VK_SUCCESS; +} + +int +QFV_ResetFences (qfv_fenceset_t *fences) +{ + VkDevice dev = fences->dev; + qfv_devfuncs_t *dfunc = fences->funcs; + + return dfunc->vkResetFences (dev, fences->numFences, + fences->fences) == VK_SUCCESS; +} + +int +QFV_QueueSubmit (qfv_device_t *device, qfv_semaphoreset_t *waitSemaphores, + qfv_cmdbufferset_t *buffers, + qfv_semaphoreset_t *signalSemaphores, qfv_fence_t *fence) +{ + qfv_devfuncs_t *dfunc = device->funcs; + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, + waitSemaphores->numSemaphores, + waitSemaphores->semaphores, waitSemaphores->stages, + buffers->numBuffers, buffers->buffers, + signalSemaphores->numSemaphores, + signalSemaphores->semaphores + }; + //FIXME multi-batch + return dfunc->vkQueueSubmit (device->queue, 1, &submitInfo, + fence->fence) == VK_SUCCESS; +} From a165d67dfa324bad91b94b1ecaeb5c621742edfe Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Jul 2019 12:37:47 +0900 Subject: [PATCH 042/435] Add a queue type --- include/QF/Vulkan/command.h | 3 ++- include/QF/Vulkan/device.h | 12 ++++++++++-- libs/video/renderer/vulkan/command.c | 6 +++--- libs/video/renderer/vulkan/device.c | 7 +++++-- libs/video/renderer/vulkan/swapchain.c | 3 ++- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index 1fe12df6d..3ad1164ff 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -48,6 +48,7 @@ typedef struct qfv_fenceset_s { } qfv_fenceset_t; struct qfv_device_s; +struct qfv_queue_s; qfv_cmdpool_t *QFV_CreateCommandPool (struct qfv_device_s *device, uint32_t queueFamily, int transient, int reset); @@ -70,7 +71,7 @@ qfv_fence_t *QFV_CreateFence (struct qfv_device_s *device, int signaled); qfv_fenceset_t *QFV_CreateFenceSet (qfv_fence_t **fences, int numFences); int QFV_WaitForFences (qfv_fenceset_t *fences, int all, uint64_t timeout); int QFV_ResetFences (qfv_fenceset_t *fences); -int QFV_QueueSubmit (struct qfv_device_s *device, +int QFV_QueueSubmit (struct qfv_queue_s *queue, qfv_semaphoreset_t *waitSemaphores, qfv_cmdbufferset_t *buffers, qfv_semaphoreset_t *signalSemaphores, qfv_fence_t *fence); diff --git a/include/QF/Vulkan/device.h b/include/QF/Vulkan/device.h index 0a90ea539..959b3d956 100644 --- a/include/QF/Vulkan/device.h +++ b/include/QF/Vulkan/device.h @@ -7,13 +7,21 @@ typedef struct qfv_devfuncs_s { #include "QF/Vulkan/funclist.h" } qfv_devfuncs_t; +struct qfv_device_s; +typedef struct qfv_queue_s { + VkDevice dev; + qfv_devfuncs_t *funcs; + + int32_t queueFamily; + VkQueue queue; +} qfv_queue_t; + struct qfv_instance_s; typedef struct qfv_device_s { VkDevice dev; VkPhysicalDevice physDev; qfv_devfuncs_t *funcs; - int32_t queueFamily; - VkQueue queue; + qfv_queue_t queue; struct strset_s *enabled_extensions; int (*extension_enabled) (struct qfv_device_s *inst, const char *ext); diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index 13dbde1a6..fab0a1966 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -297,11 +297,11 @@ QFV_ResetFences (qfv_fenceset_t *fences) } int -QFV_QueueSubmit (qfv_device_t *device, qfv_semaphoreset_t *waitSemaphores, +QFV_QueueSubmit (qfv_queue_t *queue, qfv_semaphoreset_t *waitSemaphores, qfv_cmdbufferset_t *buffers, qfv_semaphoreset_t *signalSemaphores, qfv_fence_t *fence) { - qfv_devfuncs_t *dfunc = device->funcs; + qfv_devfuncs_t *dfunc = queue->funcs; VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, waitSemaphores->numSemaphores, @@ -311,6 +311,6 @@ QFV_QueueSubmit (qfv_device_t *device, qfv_semaphoreset_t *waitSemaphores, signalSemaphores->semaphores }; //FIXME multi-batch - return dfunc->vkQueueSubmit (device->queue, 1, &submitInfo, + return dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, fence->fence) == VK_SUCCESS; } diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index 736b5e915..a90b58744 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -191,8 +191,11 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) device->physDev = physdev; load_device_funcs (inst, device); - device->queueFamily = family; - dfunc->vkGetDeviceQueue (device->dev, family, 0, &device->queue); + device->queue.dev = device->dev; + device->queue.funcs = dfunc; + device->queue.queueFamily = family; + dfunc->vkGetDeviceQueue (device->dev, family, 0, + &device->queue.queue); ctx->device = device; return device; } diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c index 2707676d6..c9487a913 100644 --- a/libs/video/renderer/vulkan/swapchain.c +++ b/libs/video/renderer/vulkan/swapchain.c @@ -27,10 +27,11 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) { qfv_instfuncs_t *ifuncs = ctx->instance->funcs; qfv_devfuncs_t *dfuncs = ctx->device->funcs; + qfv_queue_t *queue = &ctx->device->queue; VkBool32 supported; ifuncs->vkGetPhysicalDeviceSurfaceSupportKHR (ctx->device->physDev, - ctx->device->queueFamily, + queue->queueFamily, ctx->surface, &supported); if (!supported) { From 4957c4f31adc2e50b176ea112b074d348e839f30 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Jul 2019 13:05:32 +0900 Subject: [PATCH 043/435] Implement the rest of the command stuff --- include/QF/Vulkan/command.h | 13 +++++- include/QF/Vulkan/device.h | 1 + include/QF/Vulkan/funclist.h | 6 +++ libs/video/renderer/vulkan/command.c | 70 ++++++++++++++++++++++++++++ libs/video/renderer/vulkan/device.c | 7 +++ 5 files changed, 96 insertions(+), 1 deletion(-) diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index 3ad1164ff..2af925f29 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -10,6 +10,7 @@ typedef struct qfv_cmdpool_s { typedef struct qfv_cmdbuffer_s { VkDevice dev; struct qfv_devfuncs_s *funcs; + VkCommandPool cmdpool; VkCommandBuffer buffer; } qfv_cmdbuffer_t; @@ -53,10 +54,14 @@ qfv_cmdpool_t *QFV_CreateCommandPool (struct qfv_device_s *device, uint32_t queueFamily, int transient, int reset); int QFV_ResetCommandPool (qfv_cmdpool_t *pool, int release); +void QFV_DestroyCommandPool (qfv_cmdpool_t *pool); qfv_cmdbuffer_t *QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count); qfv_cmdbufferset_t *QFV_CreateCommandBufferSet (qfv_cmdbuffer_t **buffers, int numBuffers); +void QFV_FreeCommandBuffers (qfv_cmdbuffer_t *buffer, int count); +// NOTE: does not destroy buffers +void QFV_DestroyCommandBufferSet (qfv_cmdbufferset_t *buffers); int QFV_BeginCommandBuffer (qfv_cmdbuffer_t *buffer, int oneTime, int rpContinue, int simultaneous, VkCommandBufferInheritanceInfo *inheritanceInfo); @@ -66,15 +71,21 @@ int QFV_ResetCommandBuffer (qfv_cmdbuffer_t *buffer, int release); qfv_semaphore_t *QFV_CreateSemaphore (struct qfv_device_s *device); qfv_semaphoreset_t *QFV_CreateSemaphoreSet (qfv_semaphore_t **semaphores, int numSemaphores); - +void QFV_DestroySemaphore (qfv_semaphore_t *semaphore); +// NOTE: does not destroy semaphores +void QFV_DestroySemaphoreSet (qfv_semaphoreset_t *semaphores); qfv_fence_t *QFV_CreateFence (struct qfv_device_s *device, int signaled); qfv_fenceset_t *QFV_CreateFenceSet (qfv_fence_t **fences, int numFences); +void QFV_DestroyFence (qfv_fence_t *fence); +// NOTE: does not destroy fences +void QFV_DestroyFenceSet (qfv_fenceset_t *fences); int QFV_WaitForFences (qfv_fenceset_t *fences, int all, uint64_t timeout); int QFV_ResetFences (qfv_fenceset_t *fences); int QFV_QueueSubmit (struct qfv_queue_s *queue, qfv_semaphoreset_t *waitSemaphores, qfv_cmdbufferset_t *buffers, qfv_semaphoreset_t *signalSemaphores, qfv_fence_t *fence); +int QFV_QueueWaitIdle (struct qfv_queue_s *queue); #endif//__QF_Vulkan_command_h diff --git a/include/QF/Vulkan/device.h b/include/QF/Vulkan/device.h index 959b3d956..6f6907148 100644 --- a/include/QF/Vulkan/device.h +++ b/include/QF/Vulkan/device.h @@ -31,5 +31,6 @@ struct vulkan_ctx_s; qfv_device_t *QFV_CreateDevice (struct vulkan_ctx_s *ctx, const char **extensions); void QFV_DestroyDevice (qfv_device_t *device); +int QFV_DeviceWaitIdle (qfv_device_t *device); #endif//__QF_Vulkan_device_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 20ccbe275..5d649d5c2 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -101,6 +101,12 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateFence) DEVICE_LEVEL_VULKAN_FUNCTION (vkWaitForFences) DEVICE_LEVEL_VULKAN_FUNCTION (vkResetFences) DEVICE_LEVEL_VULKAN_FUNCTION (vkQueueSubmit) +DEVICE_LEVEL_VULKAN_FUNCTION (vkQueueWaitIdle) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDeviceWaitIdle) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyFence) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroySemaphore) +DEVICE_LEVEL_VULKAN_FUNCTION (vkFreeCommandBuffers) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyCommandPool) #undef DEVICE_LEVEL_VULKAN_FUNCTION diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index fab0a1966..4031f0be4 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -100,6 +100,16 @@ QFV_ResetCommandPool (qfv_cmdpool_t *pool, int release) return dfunc->vkResetCommandPool (dev, cmdpool, release_flag) == VK_SUCCESS; } +void +QFV_DestroyCommandPool (qfv_cmdpool_t *pool) +{ + VkDevice dev = pool->dev; + qfv_devfuncs_t *dfunc = pool->funcs; + + dfunc->vkDestroyCommandPool (dev, pool->cmdpool, 0); + free (pool); +} + qfv_cmdbuffer_t * QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count) { @@ -119,6 +129,7 @@ QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count) for (int i = 0; i < count; i++) { cmdbuffers[i].dev = dev; cmdbuffers[i].funcs = dfunc; + cmdbuffers[i].cmdpool = pool->cmdpool; cmdbuffers[i].buffer = buffers[i]; } return cmdbuffers; @@ -144,6 +155,26 @@ QFV_CreateCommandBufferSet (qfv_cmdbuffer_t **buffers, int numBuffers) return bufferset; } +void QFV_FreeCommandBuffers (qfv_cmdbuffer_t *buffer, int count) +{ + VkDevice dev = buffer->dev; + qfv_devfuncs_t *dfunc = buffer->funcs; + VkCommandBuffer *buffers = alloca (sizeof (*buffers) * count); + + for (int i = 0; i < count; i++) { + buffers[i] = buffer[i].buffer; + } + + dfunc->vkFreeCommandBuffers (dev, buffer->cmdpool, count, buffers); + free (buffer); +} + +void +QFV_DestroyCommandBufferSet (qfv_cmdbufferset_t *buffers) +{ + free (buffers); +} + int QFV_BeginCommandBuffer (qfv_cmdbuffer_t *buffer, int oneTime, int rpContinue, int simultaneous, @@ -237,6 +268,22 @@ QFV_CreateSemaphoreSet (qfv_semaphore_t **semaphores, int numSemaphores) return semaphoreset; } +void +QFV_DestroySemaphore (qfv_semaphore_t *semaphore) +{ + VkDevice dev = semaphore->dev; + qfv_devfuncs_t *dfunc = semaphore->funcs; + + dfunc->vkDestroySemaphore (dev, semaphore->semaphore, 0); + free (semaphore); +} + +void +QFV_DestroySemaphoreSet (qfv_semaphoreset_t *semaphores) +{ + free (semaphores); +} + qfv_fence_t * QFV_CreateFence (qfv_device_t *device, int signaled) { @@ -275,6 +322,22 @@ QFV_CreateFenceSet (qfv_fence_t **fences, int numFences) return fenceset; } +void +QFV_DestroyFence (qfv_fence_t *fence) +{ + VkDevice dev = fence->dev; + qfv_devfuncs_t *dfunc = fence->funcs; + + dfunc->vkDestroyFence (dev, fence->fence, 0); + free (fence); +} + +void +QFV_DestroyFenceSet (qfv_fenceset_t *fences) +{ + free (fences); +} + int QFV_WaitForFences (qfv_fenceset_t *fences, int all, uint64_t timeout) { @@ -314,3 +377,10 @@ QFV_QueueSubmit (qfv_queue_t *queue, qfv_semaphoreset_t *waitSemaphores, return dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, fence->fence) == VK_SUCCESS; } + +int +QFV_QueueWaitIdle (qfv_queue_t *queue) +{ + qfv_devfuncs_t *dfunc = queue->funcs; + return dfunc->vkQueueWaitIdle (queue->queue) == VK_SUCCESS; +} diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index a90b58744..85f200956 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -211,3 +211,10 @@ QFV_DestroyDevice (qfv_device_t *device) del_strset (device->enabled_extensions); free (device); } + +int +QFV_DeviceWaitIdle (qfv_device_t *device) +{ + qfv_devfuncs_t *dfunc = device->funcs; + return dfunc->vkDeviceWaitIdle (device->dev) == VK_SUCCESS; +} From 8819d26c95870b7d3b4e6d9018d8068a080e8d63 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 16 Oct 2019 20:57:39 +0900 Subject: [PATCH 044/435] Fix a compile error not sure how that one got through --- libs/video/renderer/vid_render_vulkan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 506406394..7fce05272 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -152,7 +152,8 @@ vulkan_vid_render_choose_visual (void) { Vulkan_CreateDevice (vulkan_ctx); vulkan_ctx->choose_visual (vulkan_ctx); - Sys_Printf ("%p %p\n", vulkan_ctx->device->dev, vulkan_ctx->device->queue); + Sys_Printf ("vk choose visual %p %p\n", vulkan_ctx->device->dev, + vulkan_ctx->device->queue.queue); } static void @@ -160,7 +161,7 @@ vulkan_vid_render_create_context (void) { vulkan_ctx->create_window (vulkan_ctx); vulkan_ctx->surface = vulkan_ctx->create_surface (vulkan_ctx); - Sys_Printf ("%p\n", vulkan_ctx->surface); + Sys_Printf ("vk create context %p\n", vulkan_ctx->surface); Vulkan_CreateSwapchain (vulkan_ctx); Sys_Printf ("%p %d", vulkan_ctx->swapchain->swapchain, vulkan_ctx->swapchain->numImages); From 494f673def819dca44e9ac9dd10fea31b84d0e7c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 6 Feb 2020 17:38:51 +0900 Subject: [PATCH 045/435] Fix a potential buffer overflow Highly unlikely to have that many sub models, but it does keep gcc quiet. --- libs/models/brush/model_brush.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index 33e67b952..c81fbabe9 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -962,7 +962,7 @@ Mod_LoadBrushModel (model_t *mod, void *buffer) if (i < mod->numsubmodels - 1) { // duplicate the basic information - char name[10]; + char name[12]; snprintf (name, sizeof (name), "*%i", i + 1); loadmodel = Mod_FindName (name); From d3b4e4653e30ffb5d789095e5806cdcb0e7def45 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 6 Feb 2020 19:04:28 +0900 Subject: [PATCH 046/435] Cache physical devices in the instance --- include/QF/Vulkan/device.h | 2 +- include/QF/Vulkan/instance.h | 7 +++++++ libs/video/renderer/vulkan/device.c | 12 +++--------- libs/video/renderer/vulkan/instance.c | 12 ++++++++++++ libs/video/renderer/vulkan/swapchain.c | 13 +++++++------ 5 files changed, 30 insertions(+), 16 deletions(-) diff --git a/include/QF/Vulkan/device.h b/include/QF/Vulkan/device.h index 6f6907148..28a8fe229 100644 --- a/include/QF/Vulkan/device.h +++ b/include/QF/Vulkan/device.h @@ -19,7 +19,7 @@ typedef struct qfv_queue_s { struct qfv_instance_s; typedef struct qfv_device_s { VkDevice dev; - VkPhysicalDevice physDev; + struct qfv_physdev_s *physDev; qfv_devfuncs_t *funcs; qfv_queue_t queue; struct strset_s *enabled_extensions; diff --git a/include/QF/Vulkan/instance.h b/include/QF/Vulkan/instance.h index 0a677c945..6c393d140 100644 --- a/include/QF/Vulkan/instance.h +++ b/include/QF/Vulkan/instance.h @@ -36,6 +36,11 @@ typedef struct qfv_instfuncs_s { #include "QF/Vulkan/funclist.h" } qfv_instfuncs_t; +typedef struct qfv_physdev_s { + VkPhysicalDevice dev; + VkPhysicalDeviceMemoryProperties memory_properties; +} qfv_physdev_t; + typedef struct qfv_instance_s { VkInstance instance; qfv_instfuncs_t *funcs; @@ -43,6 +48,8 @@ typedef struct qfv_instance_s { int (*extension_enabled) (struct qfv_instance_s *inst, const char *ext); VkDebugUtilsMessengerEXT debug_handle; + uint32_t numDevices; + qfv_physdev_t *devices; } qfv_instance_t; struct vulkan_ctx_s; diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index 85f200956..1c838fdfa 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -143,16 +143,10 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) merge_strings (ext, extensions, 0); qfv_instance_t *inst = ctx->instance; - VkInstance instance = inst->instance; qfv_instfuncs_t *ifunc = inst->funcs; - uint32_t numDevices; - ifunc->vkEnumeratePhysicalDevices (instance, &numDevices, 0); - VkPhysicalDevice *devices = alloca (numDevices * sizeof (*devices)); - ifunc->vkEnumeratePhysicalDevices (instance, &numDevices, devices); - - for (uint32_t i = 0; i < numDevices; i++) { - VkPhysicalDevice physdev = devices[i]; + for (uint32_t i = 0; i < inst->numDevices; i++) { + VkPhysicalDevice physdev = inst->devices[i].dev; /* if (!Vulkan_ExtensionsSupported (phys->extensions, phys->numExtensions, ext)) { @@ -189,7 +183,7 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) device->enabled_extensions = new_strset (ext); device->extension_enabled = device_extension_enabled; - device->physDev = physdev; + device->physDev = &inst->devices[i]; load_device_funcs (inst, device); device->queue.dev = device->dev; device->queue.funcs = dfunc; diff --git a/libs/video/renderer/vulkan/instance.c b/libs/video/renderer/vulkan/instance.c index 25ccdb306..a744c2608 100644 --- a/libs/video/renderer/vulkan/instance.c +++ b/libs/video/renderer/vulkan/instance.c @@ -256,6 +256,18 @@ QFV_CreateInstance (vulkan_ctx_t *ctx, setup_debug_callback (inst); } + qfv_instfuncs_t *ifunc = inst->funcs; + ifunc->vkEnumeratePhysicalDevices (instance, &inst->numDevices, 0); + inst->devices = malloc (inst->numDevices * sizeof (*inst->devices)); + VkPhysicalDevice *devices = alloca (inst->numDevices * sizeof (*devices)); + ifunc->vkEnumeratePhysicalDevices (instance, &inst->numDevices, devices); + for (uint32_t i = 0; i < inst->numDevices; i++) { + VkPhysicalDevice physDev = devices[i]; + qfv_physdev_t *dev = &inst->devices[i]; + dev->dev = physDev; + ifunc->vkGetPhysicalDeviceMemoryProperties (physDev, + &dev->memory_properties); + } return inst; } diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c index c9487a913..5a7a2ecac 100644 --- a/libs/video/renderer/vulkan/swapchain.c +++ b/libs/video/renderer/vulkan/swapchain.c @@ -28,9 +28,10 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) qfv_instfuncs_t *ifuncs = ctx->instance->funcs; qfv_devfuncs_t *dfuncs = ctx->device->funcs; qfv_queue_t *queue = &ctx->device->queue; + VkPhysicalDevice physDev = ctx->device->physDev->dev; VkBool32 supported; - ifuncs->vkGetPhysicalDeviceSurfaceSupportKHR (ctx->device->physDev, + ifuncs->vkGetPhysicalDeviceSurfaceSupportKHR (physDev, queue->queueFamily, ctx->surface, &supported); @@ -41,11 +42,11 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) uint32_t numModes; VkPresentModeKHR *modes; VkPresentModeKHR useMode = VK_PRESENT_MODE_FIFO_KHR;; - ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->device->physDev, + ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (physDev, ctx->surface, &numModes, 0); modes = alloca (numModes * sizeof (VkPresentModeKHR)); - ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (ctx->device->physDev, + ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (physDev, ctx->surface, &numModes, modes); for (uint32_t i = 0; i < numModes; i++) { @@ -57,7 +58,7 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) vulkan_presentation_mode->int_val); VkSurfaceCapabilitiesKHR surfCaps; - ifuncs->vkGetPhysicalDeviceSurfaceCapabilitiesKHR (ctx->device->physDev, + ifuncs->vkGetPhysicalDeviceSurfaceCapabilitiesKHR (physDev, ctx->surface, &surfCaps); uint32_t numImages = surfCaps.minImageCount + 1; @@ -85,11 +86,11 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) VkSurfaceTransformFlagBitsKHR surfTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; uint32_t numFormats; - ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->device->physDev, + ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (physDev, ctx->surface, &numFormats, 0); VkSurfaceFormatKHR *formats = alloca (numFormats * sizeof (*formats)); - ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (ctx->device->physDev, + ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (physDev, ctx->surface, &numFormats, formats); VkSurfaceFormatKHR useFormat = {VK_FORMAT_R8G8B8A8_UNORM, From 8148f256f5653a3902dc43ec07a1c25a3a76d79e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 7 Feb 2020 11:45:05 +0900 Subject: [PATCH 047/435] Rework object device caching It turned out I needed access to the physical device from a buffer object, so rather than storing the vulkan logical device directly in buffer (and other) objects, store the qfv logical device. --- include/QF/Vulkan/command.h | 22 +++---- include/QF/Vulkan/device.h | 4 +- include/QF/Vulkan/swapchain.h | 3 +- libs/video/renderer/vulkan/command.c | 85 +++++++++++++------------- libs/video/renderer/vulkan/device.c | 3 +- libs/video/renderer/vulkan/swapchain.c | 9 +-- 6 files changed, 59 insertions(+), 67 deletions(-) diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index 2af925f29..94165ce13 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -2,53 +2,45 @@ #define __QF_Vulkan_command_h typedef struct qfv_cmdpool_s { - VkDevice dev; - struct qfv_devfuncs_s *funcs; + struct qfv_device_s *device; VkCommandPool cmdpool; } qfv_cmdpool_t; typedef struct qfv_cmdbuffer_s { - VkDevice dev; - struct qfv_devfuncs_s *funcs; + struct qfv_device_s *device; VkCommandPool cmdpool; VkCommandBuffer buffer; } qfv_cmdbuffer_t; typedef struct qfv_cmdbufferset_s { - VkDevice dev; - struct qfv_devfuncs_s *funcs; + struct qfv_device_s *device; VkCommandBuffer *buffers; int numBuffers; } qfv_cmdbufferset_t; typedef struct qfv_semaphore_s { - VkDevice dev; - struct qfv_devfuncs_s *funcs; + struct qfv_device_s *device; VkSemaphore semaphore; } qfv_semaphore_t; typedef struct qfv_semaphoreset_s { - VkDevice dev; - struct qfv_devfuncs_s *funcs; + struct qfv_device_s *device; VkSemaphore *semaphores; VkPipelineStageFlags *stages; int numSemaphores; } qfv_semaphoreset_t; typedef struct qfv_fence_s { - VkDevice dev; - struct qfv_devfuncs_s *funcs; + struct qfv_device_s *device; VkFence fence; } qfv_fence_t; typedef struct qfv_fenceset_s { - VkDevice dev; - struct qfv_devfuncs_s *funcs; + struct qfv_device_s *device; VkFence *fences; int numFences; } qfv_fenceset_t; -struct qfv_device_s; struct qfv_queue_s; qfv_cmdpool_t *QFV_CreateCommandPool (struct qfv_device_s *device, uint32_t queueFamily, diff --git a/include/QF/Vulkan/device.h b/include/QF/Vulkan/device.h index 28a8fe229..c05b2ba7e 100644 --- a/include/QF/Vulkan/device.h +++ b/include/QF/Vulkan/device.h @@ -7,10 +7,8 @@ typedef struct qfv_devfuncs_s { #include "QF/Vulkan/funclist.h" } qfv_devfuncs_t; -struct qfv_device_s; typedef struct qfv_queue_s { - VkDevice dev; - qfv_devfuncs_t *funcs; + struct qfv_device_s *device; int32_t queueFamily; VkQueue queue; diff --git a/include/QF/Vulkan/swapchain.h b/include/QF/Vulkan/swapchain.h index 91d158c89..cd9323009 100644 --- a/include/QF/Vulkan/swapchain.h +++ b/include/QF/Vulkan/swapchain.h @@ -2,8 +2,7 @@ #define __QF_Vulkan_swapchain_h typedef struct qfv_swapchain_s { - VkDevice dev; - struct qfv_devfuncs_s *funcs; + struct qfv_device_s *device; VkSurfaceKHR surface; VkSwapchainKHR swapchain; int32_t numImages; diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index 4031f0be4..d3f3d4082 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -80,17 +80,17 @@ QFV_CreateCommandPool (qfv_device_t *device, uint32_t queueFamily, }; qfv_cmdpool_t *cmdpool = malloc (sizeof (*cmdpool)); dfunc->vkCreateCommandPool (dev, &createInfo, 0, &cmdpool->cmdpool); - cmdpool->dev = dev; - cmdpool->funcs = dfunc; + cmdpool->device = device; return cmdpool; } int QFV_ResetCommandPool (qfv_cmdpool_t *pool, int release) { - VkDevice dev = pool->dev; + qfv_device_t *device = pool->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; VkCommandPool cmdpool = pool->cmdpool; - qfv_devfuncs_t *dfunc = pool->funcs; VkCommandPoolResetFlags release_flag = 0; if (release) { @@ -103,8 +103,9 @@ QFV_ResetCommandPool (qfv_cmdpool_t *pool, int release) void QFV_DestroyCommandPool (qfv_cmdpool_t *pool) { - VkDevice dev = pool->dev; - qfv_devfuncs_t *dfunc = pool->funcs; + qfv_device_t *device = pool->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; dfunc->vkDestroyCommandPool (dev, pool->cmdpool, 0); free (pool); @@ -113,8 +114,9 @@ QFV_DestroyCommandPool (qfv_cmdpool_t *pool) qfv_cmdbuffer_t * QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count) { - VkDevice dev = pool->dev; - qfv_devfuncs_t *dfunc = pool->funcs; + qfv_device_t *device = pool->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; uint32_t level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; if (secondary) { level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; @@ -127,8 +129,7 @@ QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count) VkCommandBuffer *buffers = alloca (count * sizeof (*buffers)); dfunc->vkAllocateCommandBuffers (dev, &allocInfo, buffers); for (int i = 0; i < count; i++) { - cmdbuffers[i].dev = dev; - cmdbuffers[i].funcs = dfunc; + cmdbuffers[i].device = device; cmdbuffers[i].cmdpool = pool->cmdpool; cmdbuffers[i].buffer = buffers[i]; } @@ -138,14 +139,12 @@ QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count) qfv_cmdbufferset_t * QFV_CreateCommandBufferSet (qfv_cmdbuffer_t **buffers, int numBuffers) { - VkDevice dev = buffers[0]->dev; - qfv_devfuncs_t *dfunc = buffers[0]->funcs; + qfv_device_t *device = buffers[0]->device; qfv_cmdbufferset_t *bufferset = malloc (sizeof (*bufferset) + sizeof (VkCommandBuffer) * numBuffers); - bufferset->dev = dev; - bufferset->funcs = dfunc; + bufferset->device = device; bufferset->buffers = (VkCommandBuffer *) (bufferset + 1); bufferset->numBuffers = numBuffers; @@ -157,8 +156,9 @@ QFV_CreateCommandBufferSet (qfv_cmdbuffer_t **buffers, int numBuffers) void QFV_FreeCommandBuffers (qfv_cmdbuffer_t *buffer, int count) { - VkDevice dev = buffer->dev; - qfv_devfuncs_t *dfunc = buffer->funcs; + qfv_device_t *device = buffer->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; VkCommandBuffer *buffers = alloca (sizeof (*buffers) * count); for (int i = 0; i < count; i++) { @@ -180,8 +180,9 @@ QFV_BeginCommandBuffer (qfv_cmdbuffer_t *buffer, int oneTime, int rpContinue, int simultaneous, VkCommandBufferInheritanceInfo *inheritanceInfo) { + qfv_device_t *device = buffer->device; + qfv_devfuncs_t *dfunc = device->funcs; VkCommandBuffer buff = buffer->buffer; - qfv_devfuncs_t *dfunc = buffer->funcs; VkCommandBufferUsageFlags usage = 0; if (oneTime) { @@ -206,8 +207,9 @@ QFV_BeginCommandBuffer (qfv_cmdbuffer_t *buffer, int oneTime, int rpContinue, int QFV_EndCommandBuffer (qfv_cmdbuffer_t *buffer) { + qfv_device_t *device = buffer->device; + qfv_devfuncs_t *dfunc = device->funcs; VkCommandBuffer buff = buffer->buffer; - qfv_devfuncs_t *dfunc = buffer->funcs; return dfunc->vkEndCommandBuffer (buff) == VK_SUCCESS; } @@ -215,8 +217,9 @@ QFV_EndCommandBuffer (qfv_cmdbuffer_t *buffer) int QFV_ResetCommandBuffer (qfv_cmdbuffer_t *buffer, int release) { + qfv_device_t *device = buffer->device; + qfv_devfuncs_t *dfunc = device->funcs; VkCommandBuffer buff = buffer->buffer; - qfv_devfuncs_t *dfunc = buffer->funcs; VkCommandBufferResetFlags release_flag = 0; if (release) { @@ -238,8 +241,7 @@ QFV_CreateSemaphore (qfv_device_t *device) }; qfv_semaphore_t *semaphore = malloc (sizeof (*semaphore)); - semaphore->dev = dev; - semaphore->funcs = dfunc; + semaphore->device = device; dfunc->vkCreateSemaphore (dev, &createInfo, 0, &semaphore->semaphore); return semaphore; @@ -248,15 +250,13 @@ QFV_CreateSemaphore (qfv_device_t *device) qfv_semaphoreset_t * QFV_CreateSemaphoreSet (qfv_semaphore_t **semaphores, int numSemaphores) { - VkDevice dev = semaphores[0]->dev; - qfv_devfuncs_t *dfunc = semaphores[0]->funcs; + qfv_device_t *device = semaphores[0]->device; qfv_semaphoreset_t *semaphoreset; semaphoreset = calloc (1, sizeof (*semaphoreset) + sizeof (VkSemaphore) * numSemaphores + sizeof (VkPipelineStageFlags) * numSemaphores); - semaphoreset->dev = dev; - semaphoreset->funcs = dfunc; + semaphoreset->device = device; semaphoreset->semaphores = (VkSemaphore *) (semaphoreset + 1); semaphoreset->stages = (VkPipelineStageFlags *) &semaphoreset->semaphores[numSemaphores]; @@ -271,8 +271,9 @@ QFV_CreateSemaphoreSet (qfv_semaphore_t **semaphores, int numSemaphores) void QFV_DestroySemaphore (qfv_semaphore_t *semaphore) { - VkDevice dev = semaphore->dev; - qfv_devfuncs_t *dfunc = semaphore->funcs; + qfv_device_t *device = semaphore->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; dfunc->vkDestroySemaphore (dev, semaphore->semaphore, 0); free (semaphore); @@ -296,8 +297,7 @@ QFV_CreateFence (qfv_device_t *device, int signaled) }; qfv_fence_t *fence = malloc (sizeof (*fence)); - fence->dev = dev; - fence->funcs = dfunc; + fence->device = device; dfunc->vkCreateFence (dev, &createInfo, 0, &fence->fence); return fence; @@ -306,13 +306,11 @@ QFV_CreateFence (qfv_device_t *device, int signaled) qfv_fenceset_t * QFV_CreateFenceSet (qfv_fence_t **fences, int numFences) { - VkDevice dev = fences[0]->dev; - qfv_devfuncs_t *dfunc = fences[0]->funcs; + qfv_device_t *device = fences[0]->device; qfv_fenceset_t *fenceset = malloc (sizeof (*fenceset) + sizeof (VkFence) * numFences); - fenceset->dev = dev; - fenceset->funcs = dfunc; + fenceset->device = device; fenceset->fences = (VkFence *) (fenceset + 1); fenceset->numFences = numFences; @@ -325,8 +323,9 @@ QFV_CreateFenceSet (qfv_fence_t **fences, int numFences) void QFV_DestroyFence (qfv_fence_t *fence) { - VkDevice dev = fence->dev; - qfv_devfuncs_t *dfunc = fence->funcs; + qfv_device_t *device = fence->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; dfunc->vkDestroyFence (dev, fence->fence, 0); free (fence); @@ -341,8 +340,9 @@ QFV_DestroyFenceSet (qfv_fenceset_t *fences) int QFV_WaitForFences (qfv_fenceset_t *fences, int all, uint64_t timeout) { - VkDevice dev = fences->dev; - qfv_devfuncs_t *dfunc = fences->funcs; + qfv_device_t *device = fences->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; VkResult res = dfunc->vkWaitForFences (dev, fences->numFences, fences->fences, all, timeout); @@ -352,8 +352,9 @@ QFV_WaitForFences (qfv_fenceset_t *fences, int all, uint64_t timeout) int QFV_ResetFences (qfv_fenceset_t *fences) { - VkDevice dev = fences->dev; - qfv_devfuncs_t *dfunc = fences->funcs; + qfv_device_t *device = fences->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; return dfunc->vkResetFences (dev, fences->numFences, fences->fences) == VK_SUCCESS; @@ -364,7 +365,8 @@ QFV_QueueSubmit (qfv_queue_t *queue, qfv_semaphoreset_t *waitSemaphores, qfv_cmdbufferset_t *buffers, qfv_semaphoreset_t *signalSemaphores, qfv_fence_t *fence) { - qfv_devfuncs_t *dfunc = queue->funcs; + qfv_device_t *device = queue->device; + qfv_devfuncs_t *dfunc = device->funcs; VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, waitSemaphores->numSemaphores, @@ -381,6 +383,7 @@ QFV_QueueSubmit (qfv_queue_t *queue, qfv_semaphoreset_t *waitSemaphores, int QFV_QueueWaitIdle (qfv_queue_t *queue) { - qfv_devfuncs_t *dfunc = queue->funcs; + qfv_device_t *device = queue->device; + qfv_devfuncs_t *dfunc = device->funcs; return dfunc->vkQueueWaitIdle (queue->queue) == VK_SUCCESS; } diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index 1c838fdfa..0ed7ec808 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -185,8 +185,7 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) device->physDev = &inst->devices[i]; load_device_funcs (inst, device); - device->queue.dev = device->dev; - device->queue.funcs = dfunc; + device->queue.device = device; device->queue.queueFamily = family; dfunc->vkGetDeviceQueue (device->dev, family, 0, &device->queue.queue); diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c index 5a7a2ecac..bae8e4ff4 100644 --- a/libs/video/renderer/vulkan/swapchain.c +++ b/libs/video/renderer/vulkan/swapchain.c @@ -138,8 +138,7 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) dfuncs->vkGetSwapchainImagesKHR (device, swapchain, &numImages, 0); qfv_swapchain_t *sc = malloc (sizeof (qfv_swapchain_t) + numImages * sizeof (VkImage)); - sc->dev = device; - sc->funcs = ctx->device->funcs; + sc->device = ctx->device; sc->surface = ctx->surface; sc->swapchain = swapchain; sc->numImages = numImages; @@ -152,7 +151,9 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) void QFV_DestroySwapchain (qfv_swapchain_t *swapchain) { - swapchain->funcs->vkDestroySwapchainKHR (swapchain->dev, - swapchain->swapchain, 0); + qfv_device_t *device = swapchain->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + dfunc->vkDestroySwapchainKHR (dev, swapchain->swapchain, 0); free (swapchain); } From 2f9ad73f789d4f83e459db1cfa2be0c330bc82c6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 10 Feb 2020 15:07:35 +0900 Subject: [PATCH 048/435] Implement buffer memory up to barriers Still lots to go (views, destruction, transfer...) and I'm uncertain about the location of the pipeline barrier function. --- include/QF/Vulkan/buffer.h | 47 ++++++++ include/QF/Vulkan/command.h | 10 ++ include/QF/Vulkan/funclist.h | 6 + libs/video/renderer/vulkan/Makefile.am | 1 + libs/video/renderer/vulkan/buffer.c | 161 +++++++++++++++++++++++++ libs/video/renderer/vulkan/command.c | 30 +++++ 6 files changed, 255 insertions(+) create mode 100644 include/QF/Vulkan/buffer.h create mode 100644 libs/video/renderer/vulkan/buffer.c diff --git a/include/QF/Vulkan/buffer.h b/include/QF/Vulkan/buffer.h new file mode 100644 index 000000000..dfd8c2313 --- /dev/null +++ b/include/QF/Vulkan/buffer.h @@ -0,0 +1,47 @@ +#ifndef __QF_Vulkan_buffer_h +#define __QF_Vulkan_buffer_h + +typedef struct qfv_buffer_s { + struct qfv_device_s *device; + VkBuffer buffer; +} qfv_buffer_t; + +typedef struct qfv_memory_s { + struct qfv_device_s *device; + VkDeviceMemory object; +} qfv_memory_t; + +typedef struct qfv_buffertransition_s { + qfv_buffer_t *buffer; + VkAccessFlags srcAccess; + VkAccessFlags dstAccess; + uint32_t srcQueueFamily; + uint32_t dstQueueFamily; + VkDeviceSize offset; + VkDeviceSize size; +} qfv_buffertransition_t; + +typedef struct qfv_bufferbarrierset_s { + struct qfv_device_s *device; + uint32_t numBarriers; + VkBufferMemoryBarrier *barriers; +} qfv_bufferbarrierset_t; + +struct qfv_device_s; +qfv_buffer_t *QFV_CreateBuffer (struct qfv_device_s *device, + VkDeviceSize size, + VkBufferUsageFlags usage); + +qfv_memory_t *QFV_AllocMemory (qfv_buffer_t *buffer, + VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset); + +int QFV_BindBufferMemory (qfv_buffer_t *buffer, qfv_memory_t *memory, + VkDeviceSize offset); + +qfv_bufferbarrierset_t * +QFV_CreateBufferTransitionSet (qfv_buffertransition_t **transitions, + int numTransitions); + + +#endif//__QF_Vulkan_buffer_h diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index 94165ce13..a19ff7bd3 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -79,5 +79,15 @@ int QFV_QueueSubmit (struct qfv_queue_s *queue, qfv_semaphoreset_t *signalSemaphores, qfv_fence_t *fence); int QFV_QueueWaitIdle (struct qfv_queue_s *queue); +struct qfv_memorybarrierset_s *memBarriers; +struct qfv_bufferbarrierset_s *buffBarriers; +struct qfv_imagebarrierset_s *imgBarriers; +void QFV_CmdPipelineBarrier (qfv_cmdbuffer_t *cmdBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + struct qfv_memorybarrierset_s *memBarriers, + struct qfv_bufferbarrierset_s *buffBarriers, + struct qfv_imagebarrierset_s *imgBarriers); #endif//__QF_Vulkan_command_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 5d649d5c2..5337bd472 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -107,6 +107,12 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyFence) DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroySemaphore) DEVICE_LEVEL_VULKAN_FUNCTION (vkFreeCommandBuffers) DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyCommandPool) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkGetBufferMemoryRequirements) +DEVICE_LEVEL_VULKAN_FUNCTION (vkAllocateMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkBindBufferMemory) + +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPipelineBarrier) #undef DEVICE_LEVEL_VULKAN_FUNCTION diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index f754853f2..cfe2acb0d 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -4,6 +4,7 @@ AM_CFLAGS= @PREFER_PIC@ AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES vulkan_src = \ + buffer.c \ command.c \ device.c \ instance.c \ diff --git a/libs/video/renderer/vulkan/buffer.c b/libs/video/renderer/vulkan/buffer.c new file mode 100644 index 000000000..6a69b201d --- /dev/null +++ b/libs/video/renderer/vulkan/buffer.c @@ -0,0 +1,161 @@ +/* + buffer.c + + Vulkan buffer functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +qfv_buffer_t * +QFV_CreateBuffer (qfv_device_t *device, VkDeviceSize size, + VkBufferUsageFlags usage) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + VkBufferCreateInfo createInfo = { + VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, + 0, + size, usage, VK_SHARING_MODE_EXCLUSIVE, + 0, 0 + }; + qfv_buffer_t *buffer = malloc (sizeof (*buffer)); + dfunc->vkCreateBuffer (dev, &createInfo, 0, &buffer->buffer); + buffer->device = device; + return buffer; +} + +qfv_memory_t * +QFV_AllocMemory (qfv_buffer_t *buffer, VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset) +{ + qfv_device_t *device = buffer->device; + VkDevice dev = device->dev; + qfv_physdev_t *physdev = device->physDev; + VkPhysicalDeviceMemoryProperties *memprops = &physdev->memory_properties; + qfv_devfuncs_t *dfunc = device->funcs; + + VkMemoryRequirements requirements; + dfunc->vkGetBufferMemoryRequirements (dev, buffer->buffer, &requirements); + + size = max (size, offset + requirements.size); + VkDeviceMemory object = 0; + + for (uint32_t type = 0; type < memprops->memoryTypeCount; type++) { + if ((requirements.memoryTypeBits & (1 << type)) + && ((memprops->memoryTypes[type].propertyFlags & properties) + == properties)) { + VkMemoryAllocateInfo allocate_info = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, + size, type + }; + + VkResult res = dfunc->vkAllocateMemory (dev, &allocate_info, + 0, &object); + if (res == VK_SUCCESS) { + break; + } + } + } + + qfv_memory_t *memory = 0; + + if (object) { + memory = malloc (sizeof (*memory)); + memory->device = device; + memory->object = object; + } + return memory; +} + +int +QFV_BindBufferMemory (qfv_buffer_t *buffer, qfv_memory_t *memory, + VkDeviceSize offset) +{ + qfv_device_t *device = buffer->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + VkResult res = dfunc->vkBindBufferMemory (dev, buffer->buffer, + memory->object, offset); + return res == VK_SUCCESS; +} + +qfv_bufferbarrierset_t * +QFV_CreateBufferTransitionSet (qfv_buffertransition_t **transitions, + int numTransitions) +{ + qfv_device_t *device = transitions[0]->buffer->device; + qfv_bufferbarrierset_t *barrierset = malloc (sizeof (*barrierset) + + sizeof (VkBufferMemoryBarrier) * numTransitions); + + barrierset->device = device; + barrierset->numBarriers = numTransitions; + barrierset->barriers = (VkBufferMemoryBarrier *) (barrierset + 1); + + for (int i = 0; i < numTransitions; i++) { + VkBufferMemoryBarrier *barrier = &barrierset->barriers[i]; + barrier->sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + barrier->pNext = 0; + barrier->srcAccessMask = transitions[i]->srcAccess; + barrier->dstAccessMask = transitions[i]->dstAccess; + barrier->srcQueueFamilyIndex = transitions[i]->srcQueueFamily; + barrier->dstQueueFamilyIndex = transitions[i]->dstQueueFamily; + barrier->buffer = transitions[i]->buffer->buffer; + barrier->offset = transitions[i]->offset; + barrier->size = transitions[i]->size; + } + return barrierset; +} diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index d3f3d4082..f30b1dfeb 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -49,6 +49,7 @@ #include "QF/va.h" #include "QF/vid.h" #include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/buffer.h"//FIXME should QFV_CmdPipelineBarrier be here? #include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" @@ -387,3 +388,32 @@ QFV_QueueWaitIdle (qfv_queue_t *queue) qfv_devfuncs_t *dfunc = device->funcs; return dfunc->vkQueueWaitIdle (queue->queue) == VK_SUCCESS; } + +void +QFV_CmdPipelineBarrier (qfv_cmdbuffer_t *cmdBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + struct qfv_memorybarrierset_s *memBarrierSet, + qfv_bufferbarrierset_t *buffBarrierSet, + struct qfv_imagebarrierset_s *imgBarrierSet) +{ + qfv_device_t *device = cmdBuffer->device; + qfv_devfuncs_t *dfunc = device->funcs; + uint32_t numMemBarriers = 0; + VkMemoryBarrier *memBarriers = 0; + uint32_t numBuffBarriers = 0; + VkBufferMemoryBarrier *buffBarriers = 0; + uint32_t numImgBarriers = 0; + VkImageMemoryBarrier *imgBarriers = 0; + + if (buffBarrierSet) { + numBuffBarriers = buffBarrierSet->numBarriers; + buffBarriers = buffBarrierSet->barriers; + } + dfunc->vkCmdPipelineBarrier (cmdBuffer->buffer, + srcStageMask, dstStageMask, dependencyFlags, + numMemBarriers, memBarriers, + numBuffBarriers, buffBarriers, + numImgBarriers, imgBarriers); +} From f4c0d0ebcfea88821884abc9a93bff2d8461169e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 10 Feb 2020 18:17:58 +0900 Subject: [PATCH 049/435] Implement buffer view creation And rename memory allocation as it's buffer-specific. --- include/QF/Vulkan/buffer.h | 17 ++++++++++++++--- include/QF/Vulkan/funclist.h | 1 + libs/video/renderer/vulkan/buffer.c | 28 ++++++++++++++++++++++++++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/include/QF/Vulkan/buffer.h b/include/QF/Vulkan/buffer.h index dfd8c2313..e61e4c744 100644 --- a/include/QF/Vulkan/buffer.h +++ b/include/QF/Vulkan/buffer.h @@ -27,14 +27,23 @@ typedef struct qfv_bufferbarrierset_s { VkBufferMemoryBarrier *barriers; } qfv_bufferbarrierset_t; +typedef struct qfv_bufferview_s { + struct qfv_device_s *device; + VkBufferView view; + qfv_buffer_t *buffer; + VkFormat format; + VkDeviceSize offset; + VkDeviceSize size; +} qfv_bufferview_t; + struct qfv_device_s; qfv_buffer_t *QFV_CreateBuffer (struct qfv_device_s *device, VkDeviceSize size, VkBufferUsageFlags usage); -qfv_memory_t *QFV_AllocMemory (qfv_buffer_t *buffer, - VkMemoryPropertyFlags properties, - VkDeviceSize size, VkDeviceSize offset); +qfv_memory_t *QFV_AllocBufferMemory (qfv_buffer_t *buffer, + VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset); int QFV_BindBufferMemory (qfv_buffer_t *buffer, qfv_memory_t *memory, VkDeviceSize offset); @@ -43,5 +52,7 @@ qfv_bufferbarrierset_t * QFV_CreateBufferTransitionSet (qfv_buffertransition_t **transitions, int numTransitions); +qfv_bufferview_t *QFV_CreateBufferView (qfv_buffer_t *buffer, VkFormat format, + VkDeviceSize offset, VkDeviceSize size); #endif//__QF_Vulkan_buffer_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 5337bd472..597cb1dc7 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -111,6 +111,7 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateBuffer) DEVICE_LEVEL_VULKAN_FUNCTION (vkGetBufferMemoryRequirements) DEVICE_LEVEL_VULKAN_FUNCTION (vkAllocateMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkBindBufferMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateBufferView) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPipelineBarrier) diff --git a/libs/video/renderer/vulkan/buffer.c b/libs/video/renderer/vulkan/buffer.c index 6a69b201d..3f67c80bb 100644 --- a/libs/video/renderer/vulkan/buffer.c +++ b/libs/video/renderer/vulkan/buffer.c @@ -79,8 +79,8 @@ QFV_CreateBuffer (qfv_device_t *device, VkDeviceSize size, } qfv_memory_t * -QFV_AllocMemory (qfv_buffer_t *buffer, VkMemoryPropertyFlags properties, - VkDeviceSize size, VkDeviceSize offset) +QFV_AllocBufferMemory (qfv_buffer_t *buffer, VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset) { qfv_device_t *device = buffer->device; VkDevice dev = device->dev; @@ -159,3 +159,27 @@ QFV_CreateBufferTransitionSet (qfv_buffertransition_t **transitions, } return barrierset; } + +qfv_bufferview_t * +QFV_CreateBufferView (qfv_buffer_t *buffer, VkFormat format, + VkDeviceSize offset, VkDeviceSize size) +{ + qfv_device_t *device = buffer->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkBufferViewCreateInfo createInfo = { + VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, 0, + 0, + buffer->buffer, format, offset, size, + }; + + qfv_bufferview_t *view = malloc (sizeof (*view)); + view->device = device; + view->buffer = buffer; + view->format = format; + view->offset = offset; + view->size = size; + dfunc->vkCreateBufferView (dev, &createInfo, 0, &view->view); + return view; +} From 9fdc15c439bf29c497ba676b35bff4540745fd24 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 10 Feb 2020 18:18:37 +0900 Subject: [PATCH 050/435] Implement image stuff up to view creation --- include/QF/Vulkan/funclist.h | 5 + include/QF/Vulkan/image.h | 60 +++++++ libs/video/renderer/vulkan/Makefile.am | 1 + libs/video/renderer/vulkan/command.c | 7 +- libs/video/renderer/vulkan/image.c | 214 +++++++++++++++++++++++++ 5 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 include/QF/Vulkan/image.h create mode 100644 libs/video/renderer/vulkan/image.c diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 597cb1dc7..c5d79af7b 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -113,6 +113,11 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkAllocateMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkBindBufferMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateBufferView) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateImage) +DEVICE_LEVEL_VULKAN_FUNCTION (vkGetImageMemoryRequirements) +DEVICE_LEVEL_VULKAN_FUNCTION (vkBindImageMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateImageView) + DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPipelineBarrier) #undef DEVICE_LEVEL_VULKAN_FUNCTION diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h new file mode 100644 index 000000000..9c927e6b6 --- /dev/null +++ b/include/QF/Vulkan/image.h @@ -0,0 +1,60 @@ +#ifndef __QF_Vulkan_image_h +#define __QF_Vulkan_image_h + +typedef struct qfv_image_s { + struct qfv_device_s *device; + VkImage image; +} qfv_image_t; + +typedef struct qfv_imagetransition_s { + qfv_image_t *image; + VkAccessFlags srcAccess; + VkAccessFlags dstAccess; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamily; + uint32_t dstQueueFamily; + VkImageAspectFlags aspect; +} qfv_imagetransition_t; + +typedef struct qfv_imagebarrierset_s { + struct qfv_device_s *device; + uint32_t numBarriers; + VkImageMemoryBarrier *barriers; +} qfv_imagebarrierset_t; + +typedef struct qfv_imageview_s { + struct qfv_device_s *device; + VkImageView view; + qfv_image_t *image; + VkImageViewType type; + VkFormat format; + VkImageAspectFlags aspect; +} qfv_imageview_t; + +struct qfv_device_s; +qfv_image_t *QFV_CreateImage (struct qfv_device_s *device, int cubemap, + VkImageType type, + VkFormat format, + VkExtent3D size, + uint32_t num_mipmaps, + uint32_t num_layers, + VkSampleCountFlagBits samples, + VkImageUsageFlags usage_scenarios); + +struct qfv_memory_s *QFV_AllocImageMemory (qfv_image_t *image, + VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset); + +int QFV_BindImageMemory (qfv_image_t *image, struct qfv_memory_s *memory, + VkDeviceSize offset); + +qfv_imagebarrierset_t * +QFV_CreateImageTransitionSet (qfv_imagetransition_t **transitions, + int numTransitions); + +qfv_imageview_t *QFV_CreateImageView (qfv_image_t *image, VkImageViewType type, + VkFormat format, + VkImageAspectFlags aspect); + +#endif//__QF_Vulkan_image_h diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index cfe2acb0d..810e86d29 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -7,6 +7,7 @@ vulkan_src = \ buffer.c \ command.c \ device.c \ + image.c \ instance.c \ swapchain.c \ util.c \ diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index f30b1dfeb..ecc6f7975 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -50,6 +50,7 @@ #include "QF/vid.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/buffer.h"//FIXME should QFV_CmdPipelineBarrier be here? +#include "QF/Vulkan/image.h"//FIXME should QFV_CmdPipelineBarrier be here? #include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" @@ -396,7 +397,7 @@ QFV_CmdPipelineBarrier (qfv_cmdbuffer_t *cmdBuffer, VkDependencyFlags dependencyFlags, struct qfv_memorybarrierset_s *memBarrierSet, qfv_bufferbarrierset_t *buffBarrierSet, - struct qfv_imagebarrierset_s *imgBarrierSet) + qfv_imagebarrierset_t *imgBarrierSet) { qfv_device_t *device = cmdBuffer->device; qfv_devfuncs_t *dfunc = device->funcs; @@ -411,6 +412,10 @@ QFV_CmdPipelineBarrier (qfv_cmdbuffer_t *cmdBuffer, numBuffBarriers = buffBarrierSet->numBarriers; buffBarriers = buffBarrierSet->barriers; } + if (imgBarrierSet) { + numImgBarriers = imgBarrierSet->numBarriers; + imgBarriers = imgBarrierSet->barriers; + } dfunc->vkCmdPipelineBarrier (cmdBuffer->buffer, srcStageMask, dstStageMask, dependencyFlags, numMemBarriers, memBarriers, diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c new file mode 100644 index 000000000..18057278f --- /dev/null +++ b/libs/video/renderer/vulkan/image.c @@ -0,0 +1,214 @@ +/* + image.c + + Vulkan image functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/buffer.h"//FIXME qfv_memory_t +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +qfv_image_t * +QFV_CreateImage (qfv_device_t *device, int cubemap, + VkImageType type, + VkFormat format, + VkExtent3D size, + uint32_t num_mipmaps, + uint32_t num_layers, + VkSampleCountFlagBits samples, + VkImageUsageFlags usage_scenarios) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + VkImageCreateInfo createInfo = { + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 0, + cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0, + type, format, size, num_mipmaps, + cubemap ? 6 * num_layers : num_layers, + samples, + VK_IMAGE_TILING_OPTIMAL, + usage_scenarios, + VK_SHARING_MODE_EXCLUSIVE, + 0, 0, + VK_IMAGE_LAYOUT_UNDEFINED, + }; + qfv_image_t *image = malloc (sizeof (*image)); + dfunc->vkCreateImage (dev, &createInfo, 0, &image->image); + image->device = device; + return image; +} + +qfv_memory_t * +QFV_AllocImageMemory (qfv_image_t *image, VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset) +{ + qfv_device_t *device = image->device; + VkDevice dev = device->dev; + qfv_physdev_t *physdev = device->physDev; + VkPhysicalDeviceMemoryProperties *memprops = &physdev->memory_properties; + qfv_devfuncs_t *dfunc = device->funcs; + + VkMemoryRequirements requirements; + dfunc->vkGetImageMemoryRequirements (dev, image->image, &requirements); + + size = max (size, offset + requirements.size); + VkDeviceMemory object = 0; + + for (uint32_t type = 0; type < memprops->memoryTypeCount; type++) { + if ((requirements.memoryTypeBits & (1 << type)) + && ((memprops->memoryTypes[type].propertyFlags & properties) + == properties)) { + VkMemoryAllocateInfo allocate_info = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, + size, type + }; + + VkResult res = dfunc->vkAllocateMemory (dev, &allocate_info, + 0, &object); + if (res == VK_SUCCESS) { + break; + } + } + } + + qfv_memory_t *memory = 0; + + if (object) { + memory = malloc (sizeof (*memory)); + memory->device = device; + memory->object = object; + } + return memory; +} + +int +QFV_BindImageMemory (qfv_image_t *image, qfv_memory_t *memory, + VkDeviceSize offset) +{ + qfv_device_t *device = image->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + VkResult res = dfunc->vkBindImageMemory (dev, image->image, + memory->object, offset); + return res == VK_SUCCESS; +} + +qfv_imagebarrierset_t * +QFV_CreateImageTransitionSet (qfv_imagetransition_t **transitions, + int numTransitions) +{ + qfv_device_t *device = transitions[0]->image->device; + qfv_imagebarrierset_t *barrierset = malloc (sizeof (*barrierset) + + sizeof (VkImageMemoryBarrier) * numTransitions); + + barrierset->device = device; + barrierset->numBarriers = numTransitions; + barrierset->barriers = (VkImageMemoryBarrier *) (barrierset + 1); + + for (int i = 0; i < numTransitions; i++) { + VkImageMemoryBarrier *barrier = &barrierset->barriers[i]; + barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier->pNext = 0; + barrier->srcAccessMask = transitions[i]->srcAccess; + barrier->dstAccessMask = transitions[i]->dstAccess; + barrier->oldLayout = transitions[i]->oldLayout; + barrier->newLayout = transitions[i]->newLayout; + barrier->srcQueueFamilyIndex = transitions[i]->srcQueueFamily; + barrier->dstQueueFamilyIndex = transitions[i]->dstQueueFamily; + barrier->image = transitions[i]->image->image; + barrier->subresourceRange.aspectMask = transitions[i]->aspect; + barrier->subresourceRange.baseMipLevel = 0; + barrier->subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier->subresourceRange.baseArrayLayer = 0; + barrier->subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + } + return barrierset; +} + +qfv_imageview_t * +QFV_CreateImageView (qfv_image_t *image, VkImageViewType type, VkFormat format, + VkImageAspectFlags aspect) +{ + qfv_device_t *device = image->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkImageViewCreateInfo createInfo = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 0, + 0, + image->image, type, format, + { + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + }, + { + aspect, + 0, VK_REMAINING_MIP_LEVELS, + 0, VK_REMAINING_ARRAY_LAYERS, + } + }; + + qfv_imageview_t *view = malloc (sizeof (*view)); + view->device = device; + view->image = image; + view->type = type; + view->format = format; + view->aspect = aspect; + dfunc->vkCreateImageView (dev, &createInfo, 0, &view->view); + return view; +} From 43e37aa31e62ace1b3195d8962c3ced465d38cdd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 10 Feb 2020 18:33:29 +0900 Subject: [PATCH 051/435] Separate out the generic memory stuff --- include/QF/Vulkan/buffer.h | 9 ++------- include/QF/Vulkan/memory.h | 9 +++++++++ libs/video/renderer/vulkan/buffer.c | 1 + libs/video/renderer/vulkan/image.c | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 include/QF/Vulkan/memory.h diff --git a/include/QF/Vulkan/buffer.h b/include/QF/Vulkan/buffer.h index e61e4c744..09ff14c2b 100644 --- a/include/QF/Vulkan/buffer.h +++ b/include/QF/Vulkan/buffer.h @@ -6,11 +6,6 @@ typedef struct qfv_buffer_s { VkBuffer buffer; } qfv_buffer_t; -typedef struct qfv_memory_s { - struct qfv_device_s *device; - VkDeviceMemory object; -} qfv_memory_t; - typedef struct qfv_buffertransition_s { qfv_buffer_t *buffer; VkAccessFlags srcAccess; @@ -41,11 +36,11 @@ qfv_buffer_t *QFV_CreateBuffer (struct qfv_device_s *device, VkDeviceSize size, VkBufferUsageFlags usage); -qfv_memory_t *QFV_AllocBufferMemory (qfv_buffer_t *buffer, +struct qfv_memory_s *QFV_AllocBufferMemory (qfv_buffer_t *buffer, VkMemoryPropertyFlags properties, VkDeviceSize size, VkDeviceSize offset); -int QFV_BindBufferMemory (qfv_buffer_t *buffer, qfv_memory_t *memory, +int QFV_BindBufferMemory (qfv_buffer_t *buffer, struct qfv_memory_s *memory, VkDeviceSize offset); qfv_bufferbarrierset_t * diff --git a/include/QF/Vulkan/memory.h b/include/QF/Vulkan/memory.h new file mode 100644 index 000000000..d50bddd00 --- /dev/null +++ b/include/QF/Vulkan/memory.h @@ -0,0 +1,9 @@ +#ifndef __QF_Vulkan_memory_h +#define __QF_Vulkan_memory_h + +typedef struct qfv_memory_s { + struct qfv_device_s *device; + VkDeviceMemory object; +} qfv_memory_t; + +#endif//__QF_Vulkan_memory_h diff --git a/libs/video/renderer/vulkan/buffer.c b/libs/video/renderer/vulkan/buffer.c index 3f67c80bb..f2053c5db 100644 --- a/libs/video/renderer/vulkan/buffer.c +++ b/libs/video/renderer/vulkan/buffer.c @@ -52,6 +52,7 @@ #include "QF/Vulkan/buffer.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" +#include "QF/Vulkan/memory.h" #include "compat.h" #include "d_iface.h" diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index 18057278f..4564fd2fe 100644 --- a/libs/video/renderer/vulkan/image.c +++ b/libs/video/renderer/vulkan/image.c @@ -49,10 +49,10 @@ #include "QF/va.h" #include "QF/vid.h" #include "QF/Vulkan/qf_vid.h" -#include "QF/Vulkan/buffer.h"//FIXME qfv_memory_t #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" +#include "QF/Vulkan/memory.h" #include "compat.h" #include "d_iface.h" From 1baee0cbba5c8fc530d6641dd19a6ce4d3f8766b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 10 Feb 2020 20:42:19 +0900 Subject: [PATCH 052/435] Implement mem mapping and buffer/image copying --- include/QF/Vulkan/command.h | 18 +++++ include/QF/Vulkan/funclist.h | 7 ++ include/QF/Vulkan/memory.h | 11 +++ libs/video/renderer/vulkan/Makefile.am | 1 + libs/video/renderer/vulkan/command.c | 40 ++++++++++ libs/video/renderer/vulkan/memory.c | 102 +++++++++++++++++++++++++ 6 files changed, 179 insertions(+) create mode 100644 libs/video/renderer/vulkan/memory.c diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index a19ff7bd3..9326617ca 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -90,4 +90,22 @@ void QFV_CmdPipelineBarrier (qfv_cmdbuffer_t *cmdBuffer, struct qfv_bufferbarrierset_s *buffBarriers, struct qfv_imagebarrierset_s *imgBarriers); +struct qfv_buffer_s; +struct qfv_image_s; +void QFV_CmdCopyBuffer (qfv_cmdbuffer_t *cmdBuffer, + struct qfv_buffer_s *src, struct qfv_buffer_s *dst, + VkBufferCopy *regions, uint32_t numRegions); +void QFV_CmdCopyBufferToImage (qfv_cmdbuffer_t *cmdBuffer, + struct qfv_buffer_s *src, + struct qfv_image_s *dst, + VkImageLayout layout, + VkBufferImageCopy *regions, + uint32_t numRegions); +void QFV_CmdCopyImageToBuffer (qfv_cmdbuffer_t *cmdBuffer, + struct qfv_image_s *src, + VkImageLayout layout, + struct qfv_buffer_s *dst, + VkBufferImageCopy *regions, + uint32_t numRegions); + #endif//__QF_Vulkan_command_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index c5d79af7b..aded86eb6 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -118,7 +118,14 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkGetImageMemoryRequirements) DEVICE_LEVEL_VULKAN_FUNCTION (vkBindImageMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateImageView) +DEVICE_LEVEL_VULKAN_FUNCTION (vkMapMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkUnmapMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkFlushMappedMemoryRanges) + DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPipelineBarrier) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBufferToImage) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyImageToBuffer) #undef DEVICE_LEVEL_VULKAN_FUNCTION diff --git a/include/QF/Vulkan/memory.h b/include/QF/Vulkan/memory.h index d50bddd00..bae79d9b7 100644 --- a/include/QF/Vulkan/memory.h +++ b/include/QF/Vulkan/memory.h @@ -6,4 +6,15 @@ typedef struct qfv_memory_s { VkDeviceMemory object; } qfv_memory_t; +typedef struct qfv_mappedmemrange_s { + qfv_memory_t *memory; + VkDeviceSize offset; + VkDeviceSize size; +} qfv_mappedmemrange_t; + +void *QFV_MapMemory (qfv_memory_t *memory, + VkDeviceSize offset, VkDeviceSize size); +void QFV_UnmapMemory (qfv_memory_t *memory); +void QFV_FlushMemory (qfv_mappedmemrange_t *ranges, uint32_t numRanges); + #endif//__QF_Vulkan_memory_h diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index 810e86d29..ba9b64948 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -9,6 +9,7 @@ vulkan_src = \ device.c \ image.c \ instance.c \ + memory.c \ swapchain.c \ util.c \ vulkan_draw.c \ diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index ecc6f7975..46c2ed83f 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -422,3 +422,43 @@ QFV_CmdPipelineBarrier (qfv_cmdbuffer_t *cmdBuffer, numBuffBarriers, buffBarriers, numImgBarriers, imgBarriers); } + +void +QFV_CmdCopyBuffer (qfv_cmdbuffer_t *cmdBuffer, + struct qfv_buffer_s *src, struct qfv_buffer_s *dst, + VkBufferCopy *regions, uint32_t numRegions) +{ + qfv_device_t *device = cmdBuffer->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkCmdCopyBuffer (cmdBuffer->buffer, src->buffer, dst->buffer, + numRegions, regions); +} + +void +QFV_CmdCopyBufferToImage (qfv_cmdbuffer_t *cmdBuffer, + struct qfv_buffer_s *src, + struct qfv_image_s *dst, + VkImageLayout layout, + VkBufferImageCopy *regions, uint32_t numRegions) +{ + qfv_device_t *device = cmdBuffer->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkCmdCopyBufferToImage (cmdBuffer->buffer, src->buffer, dst->image, + layout, numRegions, regions); +} + +void +QFV_CmdCopyImageToBuffer (qfv_cmdbuffer_t *cmdBuffer, + struct qfv_image_s *src, + VkImageLayout layout, + struct qfv_buffer_s *dst, + VkBufferImageCopy *regions, uint32_t numRegions) +{ + qfv_device_t *device = cmdBuffer->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkCmdCopyImageToBuffer (cmdBuffer->buffer, src->image, layout, + dst->buffer, numRegions, regions); +} diff --git a/libs/video/renderer/vulkan/memory.c b/libs/video/renderer/vulkan/memory.c new file mode 100644 index 000000000..4ed912edb --- /dev/null +++ b/libs/video/renderer/vulkan/memory.c @@ -0,0 +1,102 @@ +/* + memory.c + + Vulkan memory functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/memory.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +void * +QFV_MapMemory (qfv_memory_t *memory, VkDeviceSize offset, VkDeviceSize size) +{ + qfv_device_t *device = memory->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + void *map = 0; + + dfunc->vkMapMemory (dev, memory->object, offset, size, 0, &map); + return map; +} + +void +QFV_UnmapMemory (qfv_memory_t *memory) +{ + qfv_device_t *device = memory->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkUnmapMemory (dev, memory->object); +} + +void +QFV_FlushMemory (qfv_mappedmemrange_t *flushRanges, uint32_t numFlushRanges) +{ + qfv_device_t *device = flushRanges[0].memory->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkMappedMemoryRange *ranges = alloca(sizeof (*ranges) * numFlushRanges); + + for (uint32_t i = 0; i < numFlushRanges; i++) { + ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + ranges[i].pNext = 0; + ranges[i].memory = flushRanges[i].memory->object; + ranges[i].offset = flushRanges[i].offset; + ranges[i].size = flushRanges[i].size; + } + dfunc->vkFlushMappedMemoryRanges (dev, numFlushRanges, ranges); +} From 29b1d6baf8f94d31f4472798f6699abac5e832d5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 11 Feb 2020 09:37:04 +0900 Subject: [PATCH 053/435] Finish up memory stuff For now, of course. --- include/QF/Vulkan/buffer.h | 4 ++++ include/QF/Vulkan/funclist.h | 8 +++++++- include/QF/Vulkan/image.h | 4 ++++ include/QF/Vulkan/memory.h | 1 + libs/video/renderer/vulkan/buffer.c | 22 ++++++++++++++++++++++ libs/video/renderer/vulkan/image.c | 22 ++++++++++++++++++++++ libs/video/renderer/vulkan/memory.c | 11 +++++++++++ 7 files changed, 71 insertions(+), 1 deletion(-) diff --git a/include/QF/Vulkan/buffer.h b/include/QF/Vulkan/buffer.h index 09ff14c2b..ef11ae8b7 100644 --- a/include/QF/Vulkan/buffer.h +++ b/include/QF/Vulkan/buffer.h @@ -50,4 +50,8 @@ QFV_CreateBufferTransitionSet (qfv_buffertransition_t **transitions, qfv_bufferview_t *QFV_CreateBufferView (qfv_buffer_t *buffer, VkFormat format, VkDeviceSize offset, VkDeviceSize size); +void QFV_DestroyBufferView (qfv_bufferview_t *view); + +void QFV_DestroyBuffer (qfv_buffer_t *buffer); + #endif//__QF_Vulkan_buffer_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index aded86eb6..1f00d0b54 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -107,17 +107,23 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyFence) DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroySemaphore) DEVICE_LEVEL_VULKAN_FUNCTION (vkFreeCommandBuffers) DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyCommandPool) + DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateBuffer) DEVICE_LEVEL_VULKAN_FUNCTION (vkGetBufferMemoryRequirements) -DEVICE_LEVEL_VULKAN_FUNCTION (vkAllocateMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkBindBufferMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateBufferView) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyBufferView) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyBuffer) DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateImage) DEVICE_LEVEL_VULKAN_FUNCTION (vkGetImageMemoryRequirements) DEVICE_LEVEL_VULKAN_FUNCTION (vkBindImageMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateImageView) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyImageView) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyImage) +DEVICE_LEVEL_VULKAN_FUNCTION (vkAllocateMemory) +DEVICE_LEVEL_VULKAN_FUNCTION (vkFreeMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkMapMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkUnmapMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkFlushMappedMemoryRanges) diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index 9c927e6b6..4258fe2e0 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -57,4 +57,8 @@ qfv_imageview_t *QFV_CreateImageView (qfv_image_t *image, VkImageViewType type, VkFormat format, VkImageAspectFlags aspect); +void QFV_DestroyImageView (qfv_imageview_t *view); + +void QFV_DestroyImage (qfv_image_t *image); + #endif//__QF_Vulkan_image_h diff --git a/include/QF/Vulkan/memory.h b/include/QF/Vulkan/memory.h index bae79d9b7..55b87f6c6 100644 --- a/include/QF/Vulkan/memory.h +++ b/include/QF/Vulkan/memory.h @@ -12,6 +12,7 @@ typedef struct qfv_mappedmemrange_s { VkDeviceSize size; } qfv_mappedmemrange_t; +void QFV_FreeMemory (qfv_memory_t *memory); void *QFV_MapMemory (qfv_memory_t *memory, VkDeviceSize offset, VkDeviceSize size); void QFV_UnmapMemory (qfv_memory_t *memory); diff --git a/libs/video/renderer/vulkan/buffer.c b/libs/video/renderer/vulkan/buffer.c index f2053c5db..e2d598b81 100644 --- a/libs/video/renderer/vulkan/buffer.c +++ b/libs/video/renderer/vulkan/buffer.c @@ -184,3 +184,25 @@ QFV_CreateBufferView (qfv_buffer_t *buffer, VkFormat format, dfunc->vkCreateBufferView (dev, &createInfo, 0, &view->view); return view; } + +void +QFV_DestroyBufferView (qfv_bufferview_t *view) +{ + qfv_device_t *device = view->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyBufferView (dev, view->view, 0); + free (view); +} + +void +QFV_DestroyBuffer (qfv_buffer_t *buffer) +{ + qfv_device_t *device = buffer->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyBuffer (dev, buffer->buffer, 0); + free (buffer); +} diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index 4564fd2fe..63b836be5 100644 --- a/libs/video/renderer/vulkan/image.c +++ b/libs/video/renderer/vulkan/image.c @@ -212,3 +212,25 @@ QFV_CreateImageView (qfv_image_t *image, VkImageViewType type, VkFormat format, dfunc->vkCreateImageView (dev, &createInfo, 0, &view->view); return view; } + +void +QFV_DestroyImageView (qfv_imageview_t *view) +{ + qfv_device_t *device = view->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyImageView (dev, view->view, 0); + free (view); +} + +void +QFV_DestroyImage (qfv_image_t *image) +{ + qfv_device_t *device = image->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyImage (dev, image->image, 0); + free (image); +} diff --git a/libs/video/renderer/vulkan/memory.c b/libs/video/renderer/vulkan/memory.c index 4ed912edb..c18a8144f 100644 --- a/libs/video/renderer/vulkan/memory.c +++ b/libs/video/renderer/vulkan/memory.c @@ -60,6 +60,17 @@ #include "util.h" +void +QFV_FreeMemory (qfv_memory_t *memory) +{ + qfv_device_t *device = memory->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkFreeMemory (dev, memory->object, 0); + free (memory); +} + void * QFV_MapMemory (qfv_memory_t *memory, VkDeviceSize offset, VkDeviceSize size) { From 3144443a822a52ac465953042c441ae9f592ca72 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 11 Feb 2020 12:19:16 +0900 Subject: [PATCH 054/435] Allow vulkan_draw to compile when optimizing Even though it's nowhere near done --- libs/video/renderer/vulkan/vulkan_draw.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 3c8dcc8e4..628306044 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -54,10 +54,22 @@ #include "r_internal.h" +static qpic_t * +pic_data (const char *name, int w, int h, const byte *data) +{ + qpic_t *pic; + + pic = malloc (field_offset (qpic_t, data[w * h])); + pic->width = w; + pic->height = h; + memcpy (pic->data, data, pic->width * pic->height); + return pic; +} + qpic_t * vulkan_Draw_MakePic (int width, int height, const byte *data) { - return 0; + return pic_data (0, width, height, data); } void @@ -68,13 +80,13 @@ vulkan_Draw_DestroyPic (qpic_t *pic) qpic_t * vulkan_Draw_PicFromWad (const char *name) { - return 0; + return pic_data (0, 1, 1, (const byte *)""); } qpic_t * vulkan_Draw_CachePic (const char *path, qboolean alpha) { - return 0; + return pic_data (0, 1, 1, (const byte *)""); } void From fbd79963bbbbf384cca33a61db8c97b088930c7f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 11 Feb 2020 15:20:49 +0900 Subject: [PATCH 055/435] Update for doxygen 1.8.16 --- doc/quakeforge.dox.conf.in | 299 +++++++++++++++++++++-------- include/QF/alloc.h | 4 +- include/QF/cbuf.h | 4 +- include/QF/checksum.h | 4 +- include/QF/cmd.h | 4 +- include/QF/crc.h | 4 +- include/QF/cvar.h | 8 +- include/QF/draw.h | 8 +- include/QF/dstring.h | 20 +- include/QF/hash.h | 4 +- include/QF/idparse.h | 4 +- include/QF/info.h | 4 +- include/QF/keys.h | 4 +- include/QF/math/dual.h | 4 +- include/QF/math/half.h | 4 +- include/QF/math/matrix3.h | 4 +- include/QF/math/matrix4.h | 4 +- include/QF/math/quaternion.h | 4 +- include/QF/math/vector.h | 4 +- include/QF/mathlib.h | 4 +- include/QF/mdfour.h | 4 +- include/QF/msg.h | 4 +- include/QF/pak.h | 4 +- include/QF/pakfile.h | 4 +- include/QF/plugin.h | 4 +- include/QF/pr_type.h | 4 +- include/QF/progs.h | 73 +++---- include/QF/qargs.h | 4 +- include/QF/qendian.h | 4 +- include/QF/qfplist.h | 4 +- include/QF/quakefs.h | 4 +- include/QF/quakeio.h | 4 +- include/QF/script.h | 4 +- include/QF/set.h | 4 +- include/QF/sizebuf.h | 4 +- include/QF/sound.h | 12 +- include/QF/sys.h | 4 +- include/QF/va.h | 4 +- include/QF/ver_check.h | 4 +- include/QF/view.h | 4 +- include/QF/wad.h | 4 +- include/QF/wadfile.h | 4 +- include/QF/winding.h | 4 +- include/QF/zone.h | 4 +- include/net_dgrm.h | 4 +- include/net_loop.h | 4 +- include/net_udp.h | 4 +- include/net_vcr.h | 4 +- include/net_wins.h | 4 +- include/netchan.h | 12 +- include/netmain.h | 28 +-- include/snd_internal.h | 28 +-- libs/models/winding.c | 6 - qtv/include/connection.h | 4 +- qtv/include/qtv.h | 4 +- ruamoko/include/gui/Group.h | 4 +- ruamoko/include/gui/InputLine.h | 8 +- ruamoko/include/gui/Pic.h | 4 +- ruamoko/include/gui/Point.h | 4 +- ruamoko/include/gui/Rect.h | 4 +- ruamoko/include/gui/Size.h | 4 +- ruamoko/include/gui/Slider.h | 4 +- ruamoko/include/gui/Text.h | 4 +- ruamoko/include/gui/View.h | 4 +- tools/qfbsp/include/brush.h | 4 +- tools/qfbsp/include/bsp5.h | 4 +- tools/qfbsp/include/csg4.h | 4 +- tools/qfbsp/include/draw.h | 4 +- tools/qfbsp/include/map.h | 4 +- tools/qfbsp/include/merge.h | 4 +- tools/qfbsp/include/options.h | 4 +- tools/qfbsp/include/outside.h | 4 +- tools/qfbsp/include/portals.h | 4 +- tools/qfbsp/include/readbsp.h | 4 +- tools/qfbsp/include/region.h | 4 +- tools/qfbsp/include/solidbsp.h | 4 +- tools/qfbsp/include/surfaces.h | 4 +- tools/qfbsp/include/tjunc.h | 4 +- tools/qfbsp/include/writebsp.h | 4 +- tools/qfcc/include/dags.h | 4 +- tools/qfcc/include/def.h | 8 +- tools/qfcc/include/defspace.h | 4 +- tools/qfcc/include/diagnostic.h | 4 +- tools/qfcc/include/expr.h | 4 +- tools/qfcc/include/flow.h | 4 +- tools/qfcc/include/function.h | 4 +- tools/qfcc/include/obj_file.h | 21 +- tools/qfcc/include/obj_type.h | 2 - tools/qfcc/include/pragma.h | 4 +- tools/qfcc/include/qfcc.h | 4 +- tools/qfcc/include/symtab.h | 4 +- tools/qfcc/include/value.h | 4 +- tools/qflight/include/entities.h | 4 +- tools/qflight/include/light.h | 4 +- tools/qflight/include/noise.h | 4 +- tools/qflight/include/options.h | 4 +- tools/qflight/include/properties.h | 4 +- tools/qflight/include/threads.h | 4 +- 98 files changed, 496 insertions(+), 373 deletions(-) diff --git a/doc/quakeforge.dox.conf.in b/doc/quakeforge.dox.conf.in index 9db22207d..64028f578 100644 --- a/doc/quakeforge.dox.conf.in +++ b/doc/quakeforge.dox.conf.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.9.1 +# Doxyfile 1.8.16 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -17,11 +17,11 @@ # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 @@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -179,6 +187,16 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus @@ -226,7 +244,12 @@ TAB_SIZE = 4 # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) ALIASES = QF=QuakeForge @@ -264,17 +287,26 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # @@ -285,7 +317,7 @@ EXTENSION_MAPPING = no_extension=C # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -293,6 +325,15 @@ EXTENSION_MAPPING = no_extension=C MARKDOWN_SUPPORT = YES +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -318,7 +359,7 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. @@ -343,6 +384,13 @@ IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = YES + # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent @@ -417,6 +465,12 @@ EXTRACT_ALL = YES EXTRACT_PRIVATE = NO +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. @@ -437,7 +491,7 @@ EXTRACT_STATIC = @STATIC_DOC@ EXTRACT_LOCAL_CLASSES = NO -# This flag is only useful for Objective-C code. When set to YES, local methods, +# This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. @@ -495,7 +549,7 @@ INTERNAL_DOCS = NO # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. +# (including Cygwin) ands Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = NO @@ -682,7 +736,7 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. @@ -727,11 +781,18 @@ WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. # The default value is: NO. WARN_NO_PARAMDOC = NO +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated @@ -755,7 +816,7 @@ WARN_LOGFILE = # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with -# spaces. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = @TOPSRC@/include \ @@ -770,7 +831,7 @@ INPUT = @TOPSRC@/include \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of # possible encodings. # The default value is: UTF-8. @@ -778,12 +839,17 @@ INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.h \ @@ -889,6 +955,10 @@ IMAGE_PATH = @TOPSRC@/doc \ # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. INPUT_FILTER = @@ -898,6 +968,10 @@ INPUT_FILTER = # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. FILTER_PATTERNS = @@ -950,7 +1024,7 @@ INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. +# entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO @@ -982,12 +1056,12 @@ SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # @@ -1015,7 +1089,7 @@ VERBATIM_HEADERS = NO # rich C++ code for which doxygen's built-in parser lacks the necessary type # information. # Note: The availability of this option depends on whether or not doxygen was -# compiled with the --with-libclang option. +# generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO @@ -1028,6 +1102,16 @@ CLANG_ASSISTED_PARSING = NO CLANG_OPTIONS = +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files +# were built. This is equivalent to specifying the "-p" option to a clang tool, +# such as clang-check. These options will then be passed to the parser. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -1146,7 +1230,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1182,6 +1266,17 @@ HTML_COLORSTYLE_GAMMA = 100 HTML_TIMESTAMP = NO +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via Javascript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have Javascript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. @@ -1205,13 +1300,13 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1250,7 +1345,7 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output @@ -1326,7 +1421,7 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1334,7 +1429,7 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1343,7 +1438,7 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1351,7 +1446,7 @@ QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1359,7 +1454,7 @@ QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = @@ -1452,7 +1547,7 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # @@ -1464,7 +1559,7 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1491,8 +1586,8 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest @@ -1553,7 +1648,7 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1566,7 +1661,7 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Xapian (see: https://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1618,21 +1713,35 @@ LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # -# Note that when enabling USE_PDFLATEX this option is only used for generating -# bitmaps for formulas in the HTML output, but not in the Makefile that is -# written to the output directory. -# The default file is: latex. +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = makeindex +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. @@ -1651,9 +1760,12 @@ COMPACT_LATEX = YES PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1750,12 +1862,28 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BIB_STYLE = plain +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- @@ -1795,9 +1923,9 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's config -# file, i.e. a series of assignments. You only have to provide replacements, -# missing definitions are set to their default value. +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the # default style sheet that doxygen normally uses. @@ -1806,8 +1934,8 @@ RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's config file. A template extensions file can be generated -# using doxygen -e rtf extensionFile. +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = @@ -1893,6 +2021,13 @@ XML_OUTPUT = xml XML_PROGRAMLISTING = YES +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- @@ -1925,9 +2060,9 @@ DOCBOOK_PROGRAMLISTING = NO #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sf.net) file that captures the -# structure of the code including all documentation. Note that this feature is -# still experimental and incomplete at the moment. +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -2101,12 +2236,6 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -2120,15 +2249,6 @@ PERL_PATH = /usr/bin/perl CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. @@ -2207,7 +2327,7 @@ COLLABORATION_GRAPH = YES # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -GROUP_GRAPHS = NO +GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling @@ -2261,7 +2381,8 @@ INCLUDED_BY_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2272,7 +2393,8 @@ CALL_GRAPH = NO # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2295,13 +2417,17 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = NO # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). # Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, # png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, -# gif:cairo:gd, gif:gd, gif:gd:gd and svg. +# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2352,6 +2478,11 @@ DIAFILE_DIRS = PLANTUML_JAR_PATH = +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + # When using plantuml, the specified paths are searched for files specified by # the !include statement in a plantuml block. diff --git a/include/QF/alloc.h b/include/QF/alloc.h index 59a57bdf1..f67fe7176 100644 --- a/include/QF/alloc.h +++ b/include/QF/alloc.h @@ -37,7 +37,7 @@ /** \defgroup alloc High-tide allocator. \ingroup utils */ -//@{ +///@{ #ifndef DEBUG_QF_MEMORY /** High-tide structure allocator for use in linked lists. @@ -93,6 +93,6 @@ #define FREE(n, p) do { free (p); } while (0) #endif -//@} +///@} #endif//__QF_alloc_h diff --git a/include/QF/cbuf.h b/include/QF/cbuf.h index 9018fa6b6..29a89588e 100644 --- a/include/QF/cbuf.h +++ b/include/QF/cbuf.h @@ -34,7 +34,7 @@ /** \defgroup cbuf Command buffer management. \ingroup utils */ -//@{ +///@{ #include @@ -100,6 +100,6 @@ void Cbuf_Execute (cbuf_t *cbuf); void Cbuf_Execute_Stack (cbuf_t *cbuf); void Cbuf_Execute_Sets (cbuf_t *cbuf); -//@} +///@} #endif//__QF_cbuf_h diff --git a/include/QF/checksum.h b/include/QF/checksum.h index 9a7dfb8e6..ed6f035b1 100644 --- a/include/QF/checksum.h +++ b/include/QF/checksum.h @@ -30,7 +30,7 @@ /** \addtogroup crc */ -//@{ +///@{ #include "QF/qtypes.h" @@ -38,6 +38,6 @@ unsigned int Com_BlockChecksum (const void *buffer, int length); void Com_BlockFullChecksum (const void *buffer, int len, unsigned char *outbuf); byte COM_BlockSequenceCRCByte (const byte *base, int length, int sequence); -//@} +///@} #endif // __checksum_h diff --git a/include/QF/cmd.h b/include/QF/cmd.h index 2ac508b9f..35846a063 100644 --- a/include/QF/cmd.h +++ b/include/QF/cmd.h @@ -31,7 +31,7 @@ /** \defgroup cmd Command management. \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" #include "QF/cbuf.h" @@ -81,6 +81,6 @@ struct cbuf_interpreter_s *Cmd_GetProvider(const char *name); extern struct cbuf_args_s *cmd_args; extern struct cvar_s *cmd_warncmd; -//@} +///@} #endif//__QF_cmd_h diff --git a/include/QF/crc.h b/include/QF/crc.h index 2aa16b616..cc635e7b9 100644 --- a/include/QF/crc.h +++ b/include/QF/crc.h @@ -31,7 +31,7 @@ /** \defgroup crc Checksum generation. \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -41,6 +41,6 @@ void CRC_ProcessBlock (const byte *start, unsigned short *crcvalue, int count); unsigned short CRC_Value(unsigned short crcvalue) __attribute__((const)); unsigned short CRC_Block (const byte *start, int count) __attribute__((pure)); -//@} +///@} #endif // __crc_h diff --git a/include/QF/cvar.h b/include/QF/cvar.h index 091a13b61..3d81a3b1c 100644 --- a/include/QF/cvar.h +++ b/include/QF/cvar.h @@ -31,7 +31,7 @@ /** \defgroup cvar Configuration variables \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -72,7 +72,7 @@ typedef struct cvar_alias_s { code goes "look, the user made fs_basepath already", uses the users value, but sets CVAR_ROM as per the call. */ -//@{ +///@{ #define CVAR_NONE 0 ///< normal cvar #define CVAR_ARCHIVE 1 ///< set to cause it to be saved to ///< config.cfg @@ -85,7 +85,7 @@ typedef struct cvar_alias_s { #define CVAR_LATCH 2048 ///< will change only when C code next does ///< a Cvar_Get(), so it can't be changed ///< (not implemented) -//@} +///@} // Returns the Cvar if found, creates it with value if not. Description and @@ -138,6 +138,6 @@ void Cvar_Init (void); extern cvar_t *cvar_vars; -//@} +///@} #endif // __cvar_h diff --git a/include/QF/draw.h b/include/QF/draw.h index d8067a4c7..529f3e892 100644 --- a/include/QF/draw.h +++ b/include/QF/draw.h @@ -37,7 +37,7 @@ /** \defgroup video_renderer_draw Generic draw functions \ingroup video_renderer */ -//@{ +///@{ #include "QF/wad.h" @@ -160,12 +160,12 @@ void Draw_FadeScreen (void); /** Shift the screen colors. */ void Draw_BlendScreen (quat_t color); -//@} +///@} /** \defgroup video_renderer_draw_qpic QPic functions \ingroup video_renderer_draw */ -//@{ +///@{ /** Load a qpic from the filesystem. \param path path of the file within the quake filesystem \param alpha transparency level of the pic. @@ -232,6 +232,6 @@ void Draw_Picf (float x, float y, qpic_t *pic); \param height vertical size of the sub-region to be drawn */ void Draw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height); -//@} +///@} #endif // _DRAW_H diff --git a/include/QF/dstring.h b/include/QF/dstring.h index 1075bc04b..638d9e340 100644 --- a/include/QF/dstring.h +++ b/include/QF/dstring.h @@ -31,7 +31,7 @@ /** \defgroup dstring Dynamic Strings \ingroup utils */ -//@{ +///@{ #include #include @@ -52,13 +52,13 @@ typedef struct dstring_s { extern dstring_mem_t dstring_default_mem; // General buffer functions -//@{ +///@{ /** Create a new dstring. size and truesize start at 0 and no string buffer is allocated. */ dstring_t *_dstring_new (dstring_mem_t *mem); dstring_t *dstring_new (void); -//@} +///@} /** Delete a dstring. Both the string buffer and dstring object are freed. */ void dstring_delete (dstring_t *dstr); @@ -103,13 +103,13 @@ void dstring_replace (dstring_t *dstr, unsigned int pos, unsigned int rlen, char *dstring_freeze (dstring_t *dstr); // String-specific functions -//@{ +///@{ /** Allocate a new dstring pre-initialized as a null terminated string. size will be 1 and the first byte 0. */ dstring_t *_dstring_newstr (dstring_mem_t *mem); dstring_t *dstring_newstr (void); -//@} +///@} /** Create a new dstring from a string. Similar to strdup(). \param str the string to copy \return inititialized dstring @@ -160,21 +160,21 @@ void dstring_insertsubstr (dstring_t *dstr, unsigned int pos, const char *str, */ void dstring_clearstr (dstring_t *dstr); -//@{ +///@{ /** Formatted printing to dstrings. Existing data is replaced by the formatted string. */ int dvsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); int dsprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); -//@} -//@{ +///@} +///@{ /** Formatted printing to dstrings. Formatted string is appened to the dstring. Embedded nulls in the dstring are ignored. */ int davsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); int dasprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); -//@} +///@} -//@} +///@} #endif // __dstring_h diff --git a/include/QF/hash.h b/include/QF/hash.h index 1a8a8f912..ae040cfa9 100644 --- a/include/QF/hash.h +++ b/include/QF/hash.h @@ -34,7 +34,7 @@ /** \defgroup hash Hash tables \ingroup utils */ -//@{ +///@{ typedef struct hashtab_s hashtab_t; @@ -209,6 +209,6 @@ void **Hash_GetList (hashtab_t *tab); */ void Hash_Stats (hashtab_t *tab); -//@} +///@} #endif // __hash_h diff --git a/include/QF/idparse.h b/include/QF/idparse.h index 07b5c322e..e48cf30e6 100644 --- a/include/QF/idparse.h +++ b/include/QF/idparse.h @@ -33,7 +33,7 @@ /** \addtogroup cbuf */ -//@{ +///@{ extern const char *com_token; @@ -44,6 +44,6 @@ void COM_TokenizeString (const char *str, struct cbuf_args_s *args); extern struct cbuf_interpreter_s id_interp; -//@} +///@} #endif//__QF_idparse_h diff --git a/include/QF/info.h b/include/QF/info.h index d57a221f6..4e34f6fa2 100644 --- a/include/QF/info.h +++ b/include/QF/info.h @@ -31,7 +31,7 @@ /** \defgroup info Info Keys \ingroup utils */ -//@{ +///@{ #include // for size_t. sys/types.h SHOULD be used, but can't :(bc) #include @@ -63,6 +63,6 @@ void Info_Destroy (info_t *info); char *Info_MakeString (info_t *info, int (*filter)(const char *)); void Info_AddKeys (info_t *info, info_t *keys); -//@} +///@} #endif // _INFO_H diff --git a/include/QF/keys.h b/include/QF/keys.h index ada46a265..66ef8d99e 100644 --- a/include/QF/keys.h +++ b/include/QF/keys.h @@ -39,7 +39,7 @@ /** \defgroup input_keybinding Key Binding Sub-system \ingroup input */ -//@{ +///@{ /// these are the key numbers that should be passed to Key_Event typedef enum { @@ -659,6 +659,6 @@ struct progs_s; void Key_Progs_Init (struct progs_s *pr); #endif -//@} +///@} #endif // _KEYS_H diff --git a/include/QF/math/dual.h b/include/QF/math/dual.h index eba9b8bf0..34c58a984 100644 --- a/include/QF/math/dual.h +++ b/include/QF/math/dual.h @@ -34,7 +34,7 @@ /** \defgroup mathlib_dual Dual and dual quaternion functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -189,6 +189,6 @@ } while (0) #define DualQuatExpand(dq) QuatExpand ((dq).q0.q), QuatExpand ((dq).qe.q) -//@} +///@} #endif // __QF_math_dual_h diff --git a/include/QF/math/half.h b/include/QF/math/half.h index 1fe474cd3..bc9133fc6 100644 --- a/include/QF/math/half.h +++ b/include/QF/math/half.h @@ -34,7 +34,7 @@ /** \defgroup mathlib_half Half-float functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -42,6 +42,6 @@ int16_t FloatToHalf (float x) __attribute__((const)); float HalfToFloat (int16_t x) __attribute__((const)); -//@} +///@} #endif // __QF_math_half_h diff --git a/include/QF/math/matrix3.h b/include/QF/math/matrix3.h index ce2474a99..dfe9b530f 100644 --- a/include/QF/math/matrix3.h +++ b/include/QF/math/matrix3.h @@ -34,7 +34,7 @@ /** \defgroup mathlib_matrix3 3x3 matrix functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -118,6 +118,6 @@ void Mat3SymEigen (const mat3_t m, vec3_t e); */ int Mat3Decompose (const mat4_t mat, quat_t rot, vec3_t shear, vec3_t scale); -//@} +///@} #endif // __QF_math_matrix3_h diff --git a/include/QF/math/matrix4.h b/include/QF/math/matrix4.h index 4f0e0dfb5..a55c8ed94 100644 --- a/include/QF/math/matrix4.h +++ b/include/QF/math/matrix4.h @@ -34,7 +34,7 @@ /** \defgroup mathlib_matrix4 4x4 matrix functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -130,6 +130,6 @@ void Mat4as3MultVec (const mat4_t a, const vec3_t b, vec3_t c); int Mat4Decompose (const mat4_t mat, quat_t rot, vec3_t shear, vec3_t scale, vec3_t trans); -//@} +///@} #endif // __QF_math_matrix4_h diff --git a/include/QF/math/quaternion.h b/include/QF/math/quaternion.h index 84d7b64b4..d6e34814a 100644 --- a/include/QF/math/quaternion.h +++ b/include/QF/math/quaternion.h @@ -34,7 +34,7 @@ /** \defgroup mathlib_quaternion Quaternion functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -168,6 +168,6 @@ void QuatInverse (const quat_t in, quat_t out); void QuatExp (const quat_t a, quat_t b); void QuatToMatrix (const quat_t q, vec_t *m, int homogenous, int vertical); -//@} +///@} #endif // __QF_math_quaternion_h diff --git a/include/QF/math/vector.h b/include/QF/math/vector.h index 73cc1f708..6a8b80809 100644 --- a/include/QF/math/vector.h +++ b/include/QF/math/vector.h @@ -31,7 +31,7 @@ /** \defgroup mathlib_vector Vector functions \ingroup mathlib */ -//@{ +///@{ #include "QF/qtypes.h" @@ -209,6 +209,6 @@ VectorNormalize (vec3_t v) return length; } -//@} +///@} #endif // __QF_math_vector_h diff --git a/include/QF/mathlib.h b/include/QF/mathlib.h index c4575705e..5c9b854fe 100644 --- a/include/QF/mathlib.h +++ b/include/QF/mathlib.h @@ -31,7 +31,7 @@ /** \defgroup mathlib Vector and matrix functions \ingroup utils */ -//@{ +///@{ #include #include "QF/qtypes.h" @@ -218,6 +218,6 @@ int CircumSphere (const vec3_t points[], int num_points, sphere_t *sphere); void BarycentricCoords (const vec_t **points, int num_points, const vec3_t p, vec_t *lambda); -//@} +///@} #endif // __mathlib_h diff --git a/include/QF/mdfour.h b/include/QF/mdfour.h index 94fe99da0..19360e838 100644 --- a/include/QF/mdfour.h +++ b/include/QF/mdfour.h @@ -31,7 +31,7 @@ /** \addtogroup crc */ -//@{ +///@{ #include "QF/uint32.h" @@ -47,6 +47,6 @@ void mdfour_update(struct mdfour *md, const unsigned char *in, int n); //old: MD void mdfour_result(struct mdfour *md, unsigned char *out); // old: MD4Final void mdfour(unsigned char *out, const unsigned char *in, int n); -//@} +///@} #endif // __mdfour_h diff --git a/include/QF/msg.h b/include/QF/msg.h index 6e550a191..6a92e2d54 100644 --- a/include/QF/msg.h +++ b/include/QF/msg.h @@ -30,7 +30,7 @@ /** \defgroup msg Message reading and writing \ingroup utils */ -//@{ +///@{ #include "QF/sizebuf.h" @@ -249,6 +249,6 @@ void MSG_ReadAngle16V (qmsg_t *msg, vec3_t angles); */ int MSG_ReadUTF8 (qmsg_t *msg); -//@} +///@} #endif diff --git a/include/QF/pak.h b/include/QF/pak.h index f176e5733..ea86ffd14 100644 --- a/include/QF/pak.h +++ b/include/QF/pak.h @@ -33,7 +33,7 @@ /** \addtogroup pak */ -//@{ +///@{ // little-endian PACK #define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P') @@ -51,6 +51,6 @@ typedef struct { int dirlen; } dpackheader_t; -//@} +///@} #endif//__qf_pak_h diff --git a/include/QF/pakfile.h b/include/QF/pakfile.h index ecb6738f0..7bb4f3a0e 100644 --- a/include/QF/pakfile.h +++ b/include/QF/pakfile.h @@ -33,7 +33,7 @@ /** \defgroup pak pakfile proccessing \ingroup utils */ -//@{ +///@{ #include "QF/hash.h" #include "QF/pak.h" @@ -64,6 +64,6 @@ int pack_add (pack_t *pack, const char *filename); int pack_extract (pack_t *pack, dpackfile_t *pf); dpackfile_t *pack_find_file (pack_t *pack, const char *filename); -//@} +///@} #endif//__QF_pakfile_h diff --git a/include/QF/plugin.h b/include/QF/plugin.h index 28cb9962f..0a06f73f2 100644 --- a/include/QF/plugin.h +++ b/include/QF/plugin.h @@ -31,7 +31,7 @@ /** \defgroup plugin Plugins \ingroup utils */ -//@{ +///@{ #define QFPLUGIN_VERSION "1.0" @@ -111,6 +111,6 @@ void PI_Shutdown (void); // FIXME: we need a generic function to initialize unused fields -//@} +///@} #endif // __QF_plugin_h_ diff --git a/include/QF/pr_type.h b/include/QF/pr_type.h index 4cc6cf82e..0c8b37664 100644 --- a/include/QF/pr_type.h +++ b/include/QF/pr_type.h @@ -36,7 +36,7 @@ All \c pointer_t \c type fields are pointers within the type qfo_space. */ -//@{ +///@{ #include "QF/pr_comp.h" @@ -102,6 +102,6 @@ typedef struct qfot_type_encodings_s { pr_int_t size; } qfot_type_encodings_t; -//@} +///@} #endif//__pr_type_h diff --git a/include/QF/progs.h b/include/QF/progs.h index 5b834d1f0..7631f1de1 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -39,18 +39,18 @@ struct QFile_s; /** \ingroup progs */ -//@{ +///@{ typedef struct progs_s progs_t; typedef struct pr_resource_s pr_resource_t; typedef struct edict_s edict_t; -//@} +///@} //============================================================================ /** \defgroup progs_misc Miscelaneous functions \ingroup progs */ -//@{ +///@{ /** Initialize the progs engine. */ @@ -63,12 +63,12 @@ void PR_Init_Cvars (void); void PR_Error (progs_t *pr, const char *error, ...) __attribute__((format(printf,2,3), noreturn)); void PR_RunError (progs_t *pr, const char *error, ...) __attribute__((format(printf,2,3), noreturn)); -//@} +///@} /** \defgroup progs_execution Execution \ingroup progs */ -//@{ +///@{ /** Ensure P_* macros point to the right place for passing parameters to progs functions. @@ -128,12 +128,12 @@ void PR_ExecuteProgram (progs_t *pr, func_t fnum); */ int PR_CallFunction (progs_t *pr, func_t fnum); -//@} +///@} /** \defgroup progs_load Loading \ingroup progs */ -//@{ +///@{ /** Type of functions that are called at progs load. \param pr pointer to ::progs_t VM struct @@ -204,12 +204,12 @@ int PR_Check_Opcodes (progs_t *pr); void PR_BoundsCheckSize (progs_t *pr, pointer_t addr, unsigned size); void PR_BoundsCheck (progs_t *pr, int addr, etype_t type); -//@} +///@} /** \defgroup progs_edict Edict management \ingroup progs */ -//@{ +///@{ struct edict_s { qboolean free; @@ -261,13 +261,13 @@ void ED_EntityParseFunction (progs_t *pr); # define NUM_FOR_EDICT(p,e) ED_NumForEdict (p, e) #endif -//@} +///@} /** \defgroup pr_symbols Symbol Management \ingroup progs Lookup functions for symbol name resolution. */ -//@{ +///@{ ddef_t *PR_FieldAtOfs (progs_t *pr, pr_int_t ofs) __attribute__((pure)); ddef_t *PR_GlobalAtOfs (progs_t *pr, pr_int_t ofs) __attribute__((pure)); @@ -282,7 +282,7 @@ int PR_AccessField (progs_t *pr, const char *name, etype_t type, const char *file, int line); void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute__((noreturn)); -//@} +///@} //============================================================================ @@ -296,7 +296,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ Typed global access macros. No checking is done against the QC type, but the appropriate C type will be used. */ -//@{ +///@{ /** \internal \param p pointer to ::progs_t VM struct @@ -479,14 +479,14 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ #define G_STRUCT(p,t,o) (*(t *)G_GPOINTER (p, o)) -//@} +///@} /** \defgroup prda_parameters Parameters \ingroup progs_data_access Typed parameter access macros. No checking is done against the QC type, but the appropriate C type will be used. */ -//@{ +///@{ /** \internal \param p pointer to ::progs_t VM struct @@ -669,7 +669,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ #define P_STRUCT(p,t,n) (*(t *)P_GPOINTER (p, n)) -//@} +///@} /** \defgroup prda_return Return Values \ingroup progs_data_access @@ -680,7 +680,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ ask for an \c int from a function that returned a \c float, you're asking for trouble. */ -//@{ +///@{ /** \internal \param p pointer to ::progs_t VM struct @@ -836,14 +836,14 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ #define RETURN_QUAT(p,q) VectorCopy (q, R_QUAT (p)) -//@} +///@} /** \defgroup prda_entity_fields Entity Fields \ingroup progs_data_access Typed entity field access macros. No checking is done against the QC type, but the appropriate C type will be used. */ -//@{ +///@{ /** \internal \param e pointer to the entity @@ -980,7 +980,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ #define E_DSTRING(p,e,o) (PR_GetMutableString (p, E_STRING (e, o))) -//@} +///@} /** \defgroup pr_builtins VM Builtin functions \ingroup progs @@ -993,7 +993,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ 0x8000000 to 0xffffffff is unavailable due to the builtin number being a negative statement address. */ -//@{ +///@{ #define PR_RANGE_SHIFT 16 #define PR_RANGE_MASK 0xffff0000 @@ -1067,7 +1067,7 @@ builtin_t *PR_FindBuiltinNum (progs_t *pr, pr_int_t num); */ int PR_RelocateBuiltins (progs_t *pr); -//@} +///@} /** \defgroup pr_strings String Management \ingroup progs @@ -1093,7 +1093,7 @@ int PR_RelocateBuiltins (progs_t *pr); They can be created, altered, and destroyed at any time by the main program (or the progs code via an appropriate builtin function). */ -//@{ +///@{ /** Initialize the string tables using the strings supplied by the progs. Called automatically during progs load. @@ -1254,13 +1254,13 @@ void PR_FreeTempStrings (progs_t *pr); void PR_Sprintf (progs_t *pr, struct dstring_s *result, const char *name, const char *format, int count, pr_type_t **args); -//@} +///@} /** \defgroup pr_resources Resource Management \ingroup progs Builtin module private data management. */ -//@{ +///@{ /** Initialize the resource management fields. @@ -1314,7 +1314,7 @@ void *PR_Resources_Find (progs_t *pr, const char *name); \note \p map is the resource map itself, not a pointer to the resource map. */ -//@{ +///@{ /** Type delcaration for the resource map. @@ -1416,29 +1416,30 @@ void *PR_Resources_Find (progs_t *pr, const char *name); return ~(i * 1024 + d); \ } \ return 0 -//@} +///@} -//@} +///@} /** \defgroup pr_zone VM memory management. \ingroup progs Used to allocate and free memory in the VM address space. */ -//@{ +///@{ void PR_Zone_Init (progs_t *pr); void PR_Zone_Free (progs_t *pr, void *ptr); void *PR_Zone_Malloc (progs_t *pr, pr_int_t size); void *PR_Zone_Realloc (progs_t *pr, void *ptr, pr_int_t size); -//@} +///@} /** \defgroup debug VM Debugging \ingroup progs Progs debugging support. */ -//@{ +/// \addtogroup debug +///@{ void PR_Debug_Init (void); void PR_Debug_Init_Cvars (void); @@ -1464,20 +1465,20 @@ extern struct cvar_s *pr_deadbeef_locals; extern struct cvar_s *pr_boundscheck; extern struct cvar_s *pr_faultchecks; -//@} +///@} /** \defgroup pr_cmds Quake and Quakeworld common builtins \ingroup progs \todo This really doesn't belong in progs. */ -//@{ +///@{ char *PF_VarString (progs_t *pr, int first); void PR_Cmds_Init (progs_t *pr); extern const char *pr_gametype; -//@} +///@} //============================================================================ @@ -1682,7 +1683,7 @@ struct progs_s { /** \addtogroup progs_data_access */ -//@{ +///@{ /** Convert a progs offset/pointer to a C pointer. \param pr pointer to ::progs_t VM struct @@ -1706,7 +1707,7 @@ PR_SetPointer (progs_t *pr, void *p) return p ? (pr_type_t *) p - pr->pr_globals : 0; } -//@} +///@} /** \example vm-exec.c */ diff --git a/include/QF/qargs.h b/include/QF/qargs.h index fe4eb98f8..50dfbd35a 100644 --- a/include/QF/qargs.h +++ b/include/QF/qargs.h @@ -32,7 +32,7 @@ /** \addtogroup misc */ -//@{ +///@{ #include "QF/qtypes.h" @@ -50,6 +50,6 @@ void COM_Init_Cvars (void); void COM_InitArgv (int argc, const char **argv); void COM_ParseConfig (void); -//@} +///@} #endif // __qargs_h diff --git a/include/QF/qendian.h b/include/QF/qendian.h index d63ca2d0c..a42bd749f 100644 --- a/include/QF/qendian.h +++ b/include/QF/qendian.h @@ -33,7 +33,7 @@ /** \defgroup qendian Endian handling functions \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -118,6 +118,6 @@ byte ReadByte (struct QFile_s *file); unsigned short ReadShort (struct QFile_s *file); unsigned int ReadLong (struct QFile_s *file); -//@} +///@} #endif // __qendian_h diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 6c5d61202..e0c2557ca 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -31,7 +31,7 @@ /** \defgroup qfplist Property lists \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" @@ -226,6 +226,6 @@ plitem_t *PL_NewString (const char *str); */ void PL_Free (plitem_t *item); -//@} +///@} #endif // __QF_qfplist_h_ diff --git a/include/QF/quakefs.h b/include/QF/quakefs.h index 336537495..364718db0 100644 --- a/include/QF/quakefs.h +++ b/include/QF/quakefs.h @@ -33,7 +33,7 @@ /** \defgroup quakefs Quake Filesystem \ingroup utils */ -//@{ +///@{ #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -418,6 +418,6 @@ void QFS_FilelistFill (filelist_t *list, const char *path, const char *ext, */ void QFS_FilelistFree (filelist_t *list); -//@} +///@} #endif // __quakefs_h diff --git a/include/QF/quakeio.h b/include/QF/quakeio.h index d72d8ec29..08b14af69 100644 --- a/include/QF/quakeio.h +++ b/include/QF/quakeio.h @@ -34,7 +34,7 @@ /** \defgroup quakeio File IO \ingroup utils */ -//@{ +///@{ typedef struct QFile_s QFile; @@ -60,6 +60,6 @@ int Qflush(QFile *file); int Qeof(QFile *file); const char *Qgetline(QFile *file); -//@} +///@} #endif /*__quakeio_h*/ diff --git a/include/QF/script.h b/include/QF/script.h index 2fe21c215..357e5100b 100644 --- a/include/QF/script.h +++ b/include/QF/script.h @@ -25,7 +25,7 @@ Line oriented script parsing. Multiple scripts being parsed at the same time is supported. */ -//@{ +///@{ #include "QF/qtypes.h" @@ -97,6 +97,6 @@ void Script_UngetToken (script_t *script); */ const char *Script_Token (script_t *script) __attribute__((pure)); -//@} +///@} #endif//__QF_script_h diff --git a/include/QF/set.h b/include/QF/set.h index 2f4dd76e5..1261bdb40 100644 --- a/include/QF/set.h +++ b/include/QF/set.h @@ -36,7 +36,7 @@ /** \defgroup set Set handling \ingroup utils */ -//@{ +///@{ //FIXME other archs #ifdef __x86_64__ @@ -370,5 +370,5 @@ set_iter_t *set_next_r (set_pool_t *set_pool, set_iter_t *set_iter); */ const char *set_as_string (const set_t *set); -//@} +///@} #endif//__QF_set_h diff --git a/include/QF/sizebuf.h b/include/QF/sizebuf.h index 8605f803d..7f6fc4ac3 100644 --- a/include/QF/sizebuf.h +++ b/include/QF/sizebuf.h @@ -31,7 +31,7 @@ \ingroup utils Fixed size buffer management */ -//@{ +///@{ #include "QF/qtypes.h" @@ -51,6 +51,6 @@ void *SZ_GetSpace (sizebuf_t *buf, int length); void SZ_Write (sizebuf_t *buf, const void *data, int length); void SZ_Print (sizebuf_t *buf, const char *data); // strcats onto the sizebuf -//@} +///@} #endif // __sizebuf_h diff --git a/include/QF/sound.h b/include/QF/sound.h index 3e37a5871..11f103080 100644 --- a/include/QF/sound.h +++ b/include/QF/sound.h @@ -37,7 +37,7 @@ /** \ingroup sound */ -//@{ +///@{ typedef struct sfx_s sfx_t; struct sfx_s { @@ -62,14 +62,14 @@ struct sfx_s sfx_t *(*open) (sfx_t *sfx); void (*close) (sfx_t *sfx); }; -//@} +///@} struct model_s; /** \defgroup sound_init Initialization functions \ingroup sound */ -//@{ +///@{ /** Initialize the sound engine. \param viewentity pointer to view entity index @@ -81,12 +81,12 @@ void S_Init (int *viewentity, double *host_frametime); */ void S_Init_Cvars (void); -//@} +///@} /** \defgroup sound_stuff Unclassified \ingroup sound */ -//@{ +///@{ /** Start a sound playing. \param entnum index of entity the sound is associated with. @@ -189,6 +189,6 @@ void S_AmbientOn (void); struct progs_s; void S_Progs_Init (struct progs_s *pr); -//@} +///@} #endif // _SOUND_H diff --git a/include/QF/sys.h b/include/QF/sys.h index 7c669563e..10c1c902e 100644 --- a/include/QF/sys.h +++ b/include/QF/sys.h @@ -32,7 +32,7 @@ \ingroup utils Non-portable functions */ -//@{ +///@{ #include #include @@ -159,6 +159,6 @@ int Sys_CreatePath (const char *path); */ char *Sys_ExpandSquiggle (const char *path); -//@} +///@} #endif // __sys_h diff --git a/include/QF/va.h b/include/QF/va.h index 6a5e54465..40c794712 100644 --- a/include/QF/va.h +++ b/include/QF/va.h @@ -32,13 +32,13 @@ /** \addtogroup misc Formatted printing. */ -//@{ +///@{ // does a varargs printf into a temp buffer char *va(const char *format, ...) __attribute__((format(printf,1,2))); // does a varargs printf into a malloced buffer char *nva(const char *format, ...) __attribute__((format(printf,1,2))); -//@} +///@} #endif // __va_h diff --git a/include/QF/ver_check.h b/include/QF/ver_check.h index 5d8c1061c..8ac943796 100644 --- a/include/QF/ver_check.h +++ b/include/QF/ver_check.h @@ -34,7 +34,7 @@ /** \defgroup misc Miscellaneous functions \ingroup utils */ -//@{ +///@{ /* ver_compare @@ -45,6 +45,6 @@ */ int ver_compare (const char *, const char *); -//@} +///@} #endif // __ver_check_h_ diff --git a/include/QF/view.h b/include/QF/view.h index ecb2ea920..570935ae8 100644 --- a/include/QF/view.h +++ b/include/QF/view.h @@ -34,7 +34,7 @@ /** \defgroup console_view Console View Objects \ingroup console */ -//@{ +///@{ /** Control the positioning of a view within its parent. The directions are the standard compass rose (north, east, south, west in clockwise order) @@ -215,6 +215,6 @@ void view_resize (view_t *view, int xl, int yl); */ void view_move (view_t *view, int xp, int yp); -//@} +///@} #endif//__qf_view_h diff --git a/include/QF/wad.h b/include/QF/wad.h index 805a69925..82e836dc9 100644 --- a/include/QF/wad.h +++ b/include/QF/wad.h @@ -32,7 +32,7 @@ /** \addtogroup wad Wad Files */ -//@{ +///@{ #include "QF/wadfile.h" @@ -46,6 +46,6 @@ void *W_GetLumpName (const char *name); void SwapPic (qpic_t *pic); -//@} +///@} #endif // _WAD_H diff --git a/include/QF/wadfile.h b/include/QF/wadfile.h index 79e5e2055..9e6c220f6 100644 --- a/include/QF/wadfile.h +++ b/include/QF/wadfile.h @@ -29,7 +29,7 @@ \ingroup utils Wadfile processing */ -//@{ +///@{ #ifndef __QF_wadfile_h #define __QF_wadfile_h @@ -102,6 +102,6 @@ int wad_add_data (wad_t *wad, const char *lumpname, byte type, const void *data, int bytes); lumpinfo_t *wad_find_lump (wad_t *wad, const char *filename); -//@} +///@} #endif//__QF_wadfile_h diff --git a/include/QF/winding.h b/include/QF/winding.h index 5ef3d8094..5815ac793 100644 --- a/include/QF/winding.h +++ b/include/QF/winding.h @@ -26,7 +26,7 @@ /** \defgroup winding Winding Manipulation */ -//@{ +///@{ struct plane_s; @@ -138,6 +138,6 @@ winding_t *ClipWinding (winding_t *in, struct plane_s *split, qboolean keepon); void DivideWinding (winding_t *in, struct plane_s *split, winding_t **front, winding_t **back); -//@} +///@} #endif//__QF_winding_h diff --git a/include/QF/zone.h b/include/QF/zone.h index 379f4557a..1f968737f 100644 --- a/include/QF/zone.h +++ b/include/QF/zone.h @@ -88,7 +88,7 @@ ----- Bottom of Memory ----- */ -//@{ +///@{ typedef struct memzone_s memzone_t; @@ -140,6 +140,6 @@ void *Cache_Get (cache_user_t *c); void Cache_Release (cache_user_t *c); int Cache_ReadLock (cache_user_t *c) __attribute__((pure)); -//@} +///@} #endif // __zone_h diff --git a/include/net_dgrm.h b/include/net_dgrm.h index 712864dd3..38c2f7e19 100644 --- a/include/net_dgrm.h +++ b/include/net_dgrm.h @@ -29,7 +29,7 @@ /** \defgroup nq-dgrm NetQuake Datagram network driver. \ingroup nq-nd */ -//@{ +///@{ /** Initialize the Datagram net driver. @@ -125,4 +125,4 @@ void Datagram_Close (qsocket_t *sock); */ void Datagram_Shutdown (void); -//@} +///@} diff --git a/include/net_loop.h b/include/net_loop.h index a0f58a34a..9247f949e 100644 --- a/include/net_loop.h +++ b/include/net_loop.h @@ -34,7 +34,7 @@ /** \defgroup nq-loop NetQuake loopback network driver. \ingroup nq-nd */ -//@{ +///@{ int Loop_Init (void); void Loop_Listen (qboolean state); @@ -49,6 +49,6 @@ qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock); void Loop_Close (qsocket_t *sock); void Loop_Shutdown (void); -//@} +///@} #endif//__net_loop_h diff --git a/include/net_udp.h b/include/net_udp.h index 78f26a6ec..bd414513d 100644 --- a/include/net_udp.h +++ b/include/net_udp.h @@ -33,7 +33,7 @@ /** \defgroup nq-udp NetQuake UDP lan driver. \ingroup nq-ld */ -//@{ +///@{ /** Initialize the UDP network interface. @@ -193,6 +193,6 @@ int UDP_GetSocketPort (netadr_t *addr); */ int UDP_SetSocketPort (netadr_t *addr, int port); -//@} +///@} #endif // __net_udp_h diff --git a/include/net_vcr.h b/include/net_vcr.h index f5383b572..9f5446453 100644 --- a/include/net_vcr.h +++ b/include/net_vcr.h @@ -29,7 +29,7 @@ /** \defgroup nq-vcr NetQuake VCR network driver. \ingroup nq-nd */ -//@{ +///@{ #define VCR_OP_CONNECT 1 #define VCR_OP_GETMESSAGE 2 @@ -48,4 +48,4 @@ qboolean VCR_CanSendMessage (qsocket_t *sock); void VCR_Close (qsocket_t *sock); void VCR_Shutdown (void); -//@} +///@} diff --git a/include/net_wins.h b/include/net_wins.h index fe4133f50..c4954f9ac 100644 --- a/include/net_wins.h +++ b/include/net_wins.h @@ -35,7 +35,7 @@ /** \defgroup nq-wins NetQuake Winsock lan driver. \ingroup nq-ld */ -//@{ +///@{ extern int winsock_initialized; extern WSADATA winsockdata; @@ -58,6 +58,6 @@ int WINS_AddrCompare (netadr_t *addr1, netadr_t *addr2); int WINS_GetSocketPort (netadr_t *addr); int WINS_SetSocketPort (netadr_t *addr, int port); -//@} +///@} #endif//__net_wins_h diff --git a/include/netchan.h b/include/netchan.h index 4aa266fc8..cebfe4bd4 100644 --- a/include/netchan.h +++ b/include/netchan.h @@ -39,7 +39,7 @@ /** \defgroup qw-net QuakeWorld network support. \ingroup network */ -//{ +///@{ #define MAX_MSGLEN 1450 ///< max length of a reliable message #define MAX_DATAGRAM 1450 ///< max length of unreliable message @@ -75,12 +75,12 @@ void Analyze_Client_Packet (const byte * data, int len, int has_sequence); void Analyze_Server_Packet (const byte * data, int len, int has_sequence); extern struct cvar_s *net_packetlog; -//@} +///@} /** \defgroup qw-udp QuakeWorld udp support. \ingroup qw-net */ -//@{ +///@{ /** Initialize the UDP network interface. @@ -161,7 +161,7 @@ const char *NET_BaseAdrToString (netadr_t a); */ qboolean NET_StringToAdr (const char *s, netadr_t *a); -//@} +///@} /** \defgroup netchan Netchan \ingroup qw-net @@ -216,7 +216,7 @@ qboolean NET_StringToAdr (const char *s, netadr_t *a); the channel matches even if the IP port differs. The IP port should be updated to the new value before sending out any replies. */ -//@{ +///@{ #define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG) #define MAX_LATENT 32 @@ -377,6 +377,6 @@ qboolean Netchan_CanReliable (netchan_t *chan) __attribute__((pure)); */ void Netchan_SendPacket (int length, const void *data, netadr_t to); -//@} +///@} #endif // _NET_H diff --git a/include/netmain.h b/include/netmain.h index fdb870628..351e615ba 100644 --- a/include/netmain.h +++ b/include/netmain.h @@ -34,7 +34,7 @@ /** \defgroup nq-net NetQuake network support. \ingroup network */ -//@{ +///@{ typedef struct { @@ -56,7 +56,7 @@ typedef struct /** \name NetHeader flags */ -//@{ +///@{ #define NETFLAG_LENGTH_MASK 0x0000ffff #define NETFLAG_DATA 0x00010000 #define NETFLAG_ACK 0x00020000 @@ -64,7 +64,7 @@ typedef struct #define NETFLAG_EOM 0x00080000 #define NETFLAG_UNRELIABLE 0x00100000 #define NETFLAG_CTL 0x80000000 -//@} +///@} #define NET_PROTOCOL_VERSION 3 @@ -86,7 +86,7 @@ typedef struct a full address and port in a string. It is used for returning the address of a server that is not running locally. */ -//@{ +///@{ /** Connect Request: \arg \b string \c game_name \em "QUAKE" @@ -153,7 +153,7 @@ typedef struct \arg \b string \c value */ #define CCREP_RULE_INFO 0x85 -//@} +///@} typedef struct qsocket_s { struct qsocket_s *next; @@ -205,11 +205,11 @@ typedef struct qsocket_s { /** \name socket management */ -//@{ +///@{ extern qsocket_t *net_activeSockets; extern qsocket_t *net_freeSockets; extern int net_numsockets; -//@} +///@} #define MAX_NET_DRIVERS 8 @@ -220,12 +220,12 @@ extern int net_driverlevel; /** \name message statistics */ -//@{ +///@{ extern int messagesSent; extern int messagesReceived; extern int unreliableMessagesSent; extern int unreliableMessagesReceived; -//@} +///@} /** Create and initialize a new qsocket. @@ -386,12 +386,12 @@ extern struct cvar_s *hostname; extern QFile *vcrFile; -//@} +///@} /** \defgroup nq-ld NetQuake lan drivers. \ingroup nq-net */ -//@{ +///@{ typedef struct { const char *name; @@ -419,12 +419,12 @@ typedef struct { extern int net_numlandrivers; extern net_landriver_t net_landrivers[MAX_NET_DRIVERS]; -//@} +///@} /** \defgroup nq-nd NetQuake network drivers. \ingroup nq-net */ -//@{ +///@{ typedef struct { const char *name; @@ -447,6 +447,6 @@ typedef struct { extern int net_numdrivers; extern net_driver_t net_drivers[MAX_NET_DRIVERS]; -//@} +///@} #endif // __net_h diff --git a/include/snd_internal.h b/include/snd_internal.h index 0b1e87a21..ca4dc76c6 100644 --- a/include/snd_internal.h +++ b/include/snd_internal.h @@ -35,7 +35,7 @@ /** \defgroup sound_render Sound rendering sub-system. \ingroup sound */ -//@{ +///@{ #include "QF/plugin/general.h" #include "QF/plugin/snd_render.h" @@ -234,12 +234,12 @@ extern snd_render_data_t snd_render_data; #define PAINTBUFFER_SIZE 512 extern portable_samplepair_t snd_paintbuffer[PAINTBUFFER_SIZE * 2]; -//@} +///@} /** \defgroup sound_render_sfx Sound sfx \ingroup sound_render_mix */ -//@{ +///@{ /** Cache sound data. Initializes caching fields of sfx. \param sfx \param realname @@ -289,7 +289,7 @@ sfx_t *SND_LoadSound (const char *name); */ void SND_SFX_Init (void); -//@} +///@} /** \defgroup sound_render_mix_channels Sound channels \ingroup sound_render_mix @@ -302,7 +302,7 @@ void SND_SFX_Init (void); - MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels - 1
static sounds */ -//@{ +///@{ #define MAX_CHANNELS 512 //!< number of available mixing channels #define MAX_DYNAMIC_CHANNELS 128 //!< number of dynamic channels #define MAX_STATIC_CHANNELS 256 //!< number of static channels @@ -390,13 +390,13 @@ void SND_StopSound (int entnum, int entchannel); \param s name of sound to play */ void SND_LocalSound (const char *s); -//@} +///@} /** \defgroup sound_render_mix Mixer engine. \ingroup sound_render */ -//@{ +///@{ /** sound clock in samples */ extern unsigned snd_paintedtime; @@ -414,13 +414,13 @@ void SND_InitScaletable (void); \param sc sfxbuffer to set. */ void SND_SetPaint (sfxbuffer_t *sc); -//@} +///@} /** \defgroup sound_render_resample Resampling functions \ingroup sound_render */ -//@{ +///@{ /** Set up the various parameters that depend on the actual sample rate. \param sc buffer to setup \param streamed non-zero if this is for a stream. @@ -448,13 +448,13 @@ void SND_Resample (sfxbuffer_t *sc, float *data, int length); */ void SND_Convert (byte *idata, float *fdata, int frames, int channels, int width); -//@} +///@} /** \defgroup sound_render_load Sound loading functions \ingroup sound_render */ -//@{ +///@{ /** Load the referenced sound. \param sfx sound reference \return 0 if ok, -1 on error @@ -492,12 +492,12 @@ int SND_LoadWav (QFile *file, sfx_t *sfx, char *realname); \return 0 if ok, -1 on error */ int SND_LoadMidi (QFile *file, sfx_t *sfx, char *realname); -//@} +///@} /** \defgroup sound_render_cache_stream Cache/Stream Functions. \ingroup sound_render */ -//@{ +///@{ /** Retrieve wavinfo from a cached sound. \param sfx sound reference \return pointer to sound's wavinfo @@ -579,6 +579,6 @@ void SND_StreamSetPos (sfxbuffer_t *buffer, unsigned int pos); */ sfxbuffer_t *SND_GetCache (long samples, int rate, int channels, sfxblock_t *block, cache_allocator_t allocator); -//@} +///@} #endif//__snd_internal_h diff --git a/libs/models/winding.c b/libs/models/winding.c index d065224f7..62ae9fcb8 100644 --- a/libs/models/winding.c +++ b/libs/models/winding.c @@ -40,10 +40,6 @@ #define BOGUS (18000.0) -/** \addtogroup qfbsp_winding -*/ -//@{ - int c_activewindings, c_peakwindings; winding_t * @@ -326,5 +322,3 @@ FreeWinding (winding_t *w) c_activewindings--; free (w); } - -//@} diff --git a/qtv/include/connection.h b/qtv/include/connection.h index d02e4b971..18bbbc277 100644 --- a/qtv/include/connection.h +++ b/qtv/include/connection.h @@ -36,7 +36,7 @@ /** \defgroup qtv_connection Connection Management \ingroup qtv */ -//@{ +///@{ typedef struct connection_s { netadr_t address; ///< Address of the remote end. @@ -77,6 +77,6 @@ void Connection_Del (connection_t *con); */ connection_t *Connection_Find (netadr_t *address); -//@} +///@} #endif//__connection_h diff --git a/qtv/include/qtv.h b/qtv/include/qtv.h index 57947af16..732febfb3 100644 --- a/qtv/include/qtv.h +++ b/qtv/include/qtv.h @@ -40,7 +40,7 @@ /** \defgroup qtv_general General Functions \ingroup qtv */ -//@{ +///@{ #define PORT_QTV 27501 ///< Default port to listen for connecting clients. @@ -91,6 +91,6 @@ void qtv_end_redirect (void); void qtv_sbar_init (void); -//@} +///@} #endif//__qtv_h diff --git a/ruamoko/include/gui/Group.h b/ruamoko/include/gui/Group.h index b9ea99386..f20cca09c 100644 --- a/ruamoko/include/gui/Group.h +++ b/ruamoko/include/gui/Group.h @@ -4,7 +4,7 @@ #include "View.h" /** \addtogroup gui */ -//@{ +///@{ @class Array; @@ -41,6 +41,6 @@ - (id) addViews: (Array*)viewlist; @end -//@} +///@} #endif//__ruamoko_gui_Group_h diff --git a/ruamoko/include/gui/InputLine.h b/ruamoko/include/gui/InputLine.h index 692562a08..363cc0b8c 100644 --- a/ruamoko/include/gui/InputLine.h +++ b/ruamoko/include/gui/InputLine.h @@ -8,7 +8,7 @@ Interface functions to the engine implementation. */ -//@{ +///@{ /** Opaque handle to an inputline. @@ -118,10 +118,10 @@ typedef void (il_enterfunc)(string, void*); \return The current text of the intputline. */ @extern string InputLine_GetText (inputline_t il); -//@} +///@} /** \addtogroup gui */ -//@{ +///@{ /** Class representation of the low-level inputline objects. */ @@ -252,6 +252,6 @@ typedef void (il_enterfunc)(string, void*); - (string) text; @end -//@} +///@} #endif //__ruamoko_gui_InputLine_h diff --git a/ruamoko/include/gui/Pic.h b/ruamoko/include/gui/Pic.h index f19e8b6e4..9ed9e3380 100644 --- a/ruamoko/include/gui/Pic.h +++ b/ruamoko/include/gui/Pic.h @@ -4,7 +4,7 @@ #include "gui/View.h" /** \addtogroup gui */ -//@{ +///@{ @interface Pic : View { @@ -18,6 +18,6 @@ -(void)draw; @end -//@} +///@} #endif//__ruamoko_gui_Pic_h diff --git a/ruamoko/include/gui/Point.h b/ruamoko/include/gui/Point.h index 4ac36391a..9de4d7f5e 100644 --- a/ruamoko/include/gui/Point.h +++ b/ruamoko/include/gui/Point.h @@ -2,7 +2,7 @@ #define __ruamoko_gui_Point_h /** \addtogroup gui */ -//@{ +///@{ struct Point { int x; @@ -15,6 +15,6 @@ typedef struct Point Point; @extern Point addPoint (Point a, Point b); @extern Point subtractPoint (Point a, Point b); -//@} +///@} #endif //__ruamoko_gui_Point_h diff --git a/ruamoko/include/gui/Rect.h b/ruamoko/include/gui/Rect.h index 145815d66..005ce4a70 100644 --- a/ruamoko/include/gui/Rect.h +++ b/ruamoko/include/gui/Rect.h @@ -5,7 +5,7 @@ #include "gui/Size.h" /** \addtogroup gui */ -//@{ +///@{ struct Rect { Point origin; @@ -30,6 +30,6 @@ typedef struct Rect Rect; - (Rect) offsetBySize: (Size)aSize; #endif -//@} +///@} #endif //__ruamoko_gui_Rect_h diff --git a/ruamoko/include/gui/Size.h b/ruamoko/include/gui/Size.h index 0f6b387a3..dd48c6259 100644 --- a/ruamoko/include/gui/Size.h +++ b/ruamoko/include/gui/Size.h @@ -2,7 +2,7 @@ #define __ruamoko_gui_Size_h /** \addtogroup gui */ -//@{ +///@{ struct Size { int width; @@ -15,6 +15,6 @@ typedef struct Size Size; @extern Size addSize (Size a, Size b); @extern Size subtractSize (Size a, Size b); -//@} +///@} #endif //__ruamoko_gui_Size_h diff --git a/ruamoko/include/gui/Slider.h b/ruamoko/include/gui/Slider.h index 13a68f492..66710d28e 100644 --- a/ruamoko/include/gui/Slider.h +++ b/ruamoko/include/gui/Slider.h @@ -4,7 +4,7 @@ #include "View.h" /** \addtogroup gui */ -//@{ +///@{ @interface Slider: View { @@ -19,6 +19,6 @@ @end -//@} +///@} #endif //__ruamoko_gui_Slider_h diff --git a/ruamoko/include/gui/Text.h b/ruamoko/include/gui/Text.h index d9c6a1311..d5654d555 100644 --- a/ruamoko/include/gui/Text.h +++ b/ruamoko/include/gui/Text.h @@ -4,7 +4,7 @@ #include "View.h" /** \addtogroup gui */ -//@{ +///@{ @interface Text: View { @@ -18,6 +18,6 @@ - (void) draw; @end -//@} +///@} #endif //__ruamoko_gui_Text_h diff --git a/ruamoko/include/gui/View.h b/ruamoko/include/gui/View.h index a84f05e06..c2a99e036 100644 --- a/ruamoko/include/gui/View.h +++ b/ruamoko/include/gui/View.h @@ -8,7 +8,7 @@ */ /** \addtogroup gui */ -//@{ +///@{ /** The View class. */ @@ -34,6 +34,6 @@ - (int) keyEvent:(int)key unicode:(int)unicode down:(int)down; @end -//@} +///@} #endif //__ruamoko_gui_View_h diff --git a/tools/qfbsp/include/brush.h b/tools/qfbsp/include/brush.h index f51beab00..345b14747 100644 --- a/tools/qfbsp/include/brush.h +++ b/tools/qfbsp/include/brush.h @@ -30,7 +30,7 @@ /** \defgroup qfbsp_brush Brush Functions \ingroup qfbsp */ -//@{ +///@{ #define NUM_HULLS 2 // normal and +16 @@ -95,6 +95,6 @@ int NormalizePlane (plane_t *dp); */ int FindPlane (const plane_t *dplane, int *side); -//@} +///@} #endif//qfbsp_brush_h diff --git a/tools/qfbsp/include/bsp5.h b/tools/qfbsp/include/bsp5.h index 4cacb23ae..b949cf77c 100644 --- a/tools/qfbsp/include/bsp5.h +++ b/tools/qfbsp/include/bsp5.h @@ -32,7 +32,7 @@ /** \defgroup qfbsp_general General functions \ingroup qfbsp */ -//@{ +///@{ #define MAX_THREADS 4 @@ -129,6 +129,6 @@ node_t *AllocNode (void); extern bsp_t *bsp; -//@} +///@} #endif//qfbsp_bsp5_h diff --git a/tools/qfbsp/include/csg4.h b/tools/qfbsp/include/csg4.h index dd48047f4..e6ff8b4a3 100644 --- a/tools/qfbsp/include/csg4.h +++ b/tools/qfbsp/include/csg4.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_csg4 CSG Functions \ingroup qfbsp */ -//@{ +///@{ struct plane_s; struct visfacet_s; @@ -84,6 +84,6 @@ struct surface_s *CSGFaces (struct brushset_s *bs); void SplitFace (struct visfacet_s *in, struct plane_s *split, struct visfacet_s **front, struct visfacet_s **back); -//@} +///@} #endif//qfbsp_csg4_h diff --git a/tools/qfbsp/include/draw.h b/tools/qfbsp/include/draw.h index ecaa3fd53..740fa9050 100644 --- a/tools/qfbsp/include/draw.h +++ b/tools/qfbsp/include/draw.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_draw Debug Drawing Functions \ingroup qfbsp */ -//@{ +///@{ struct visfacet_s; struct portal_s; @@ -53,6 +53,6 @@ void DrawBrush (const struct brush_s *b); void DrawWinding (const struct winding_s *w); void DrawTri (const vec3_t p1, const vec3_t p2, const vec3_t p3); -//@} +///@} #endif//qfbsp_draw_h diff --git a/tools/qfbsp/include/map.h b/tools/qfbsp/include/map.h index e531fad8a..25c56d4ef 100644 --- a/tools/qfbsp/include/map.h +++ b/tools/qfbsp/include/map.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_map Map Parser \ingroup qfbsp */ -//@{ +///@{ #define MAX_FACES 256 typedef struct mface_s { @@ -120,6 +120,6 @@ void GetVectorForKey (const entity_t *ent, const char *key, vec3_t vec); */ void WriteEntitiesToString (void); -//@} +///@} #endif//qfbsp_map_h diff --git a/tools/qfbsp/include/merge.h b/tools/qfbsp/include/merge.h index 81e8b2c1c..c65ee15ff 100644 --- a/tools/qfbsp/include/merge.h +++ b/tools/qfbsp/include/merge.h @@ -25,7 +25,7 @@ /** \defgroup qfbsp_merge Merge Functions \ingroup qfbsp */ -//@{ +///@{ /** Add a face to the list of faces, doing any possible merging. @@ -63,6 +63,6 @@ void MergePlaneFaces (surface_t *plane); */ void MergeAll (surface_t *surfhead); -//@} +///@} #endif//qfbsp_merge_h diff --git a/tools/qfbsp/include/options.h b/tools/qfbsp/include/options.h index 4b062f27e..47a8e0df7 100644 --- a/tools/qfbsp/include/options.h +++ b/tools/qfbsp/include/options.h @@ -33,7 +33,7 @@ /** \defgroup qfbsp_options Command-line Options Parsing \ingroup qfbsp */ -//@{ +///@{ typedef struct { int verbosity; // 0=silent @@ -65,6 +65,6 @@ extern options_t options; int DecodeArgs (int argc, char **argv); extern const char *this_program; -//@} +///@} #endif//qfbsp_options_h diff --git a/tools/qfbsp/include/outside.h b/tools/qfbsp/include/outside.h index 8ad85fe49..e45e11496 100644 --- a/tools/qfbsp/include/outside.h +++ b/tools/qfbsp/include/outside.h @@ -25,7 +25,7 @@ /** \defgroup qfbsp_outside Outside Functions \ingroup qfbsp */ -//@{ +///@{ struct node_s; @@ -41,6 +41,6 @@ struct node_s; */ qboolean FillOutside (struct node_s *node); -//@} +///@} #endif//qfbsp_outside_h diff --git a/tools/qfbsp/include/portals.h b/tools/qfbsp/include/portals.h index 381bbf0f9..6d5da460e 100644 --- a/tools/qfbsp/include/portals.h +++ b/tools/qfbsp/include/portals.h @@ -31,7 +31,7 @@ Decision nodes will not have portals on them, though as part of the portal building process, they will temporarily have portals. */ -//@{ +///@{ struct node_s; @@ -89,6 +89,6 @@ void FreeAllPortals (struct node_s *node); */ void WritePortalfile (struct node_s *headnode); -//@} +///@} #endif//qfbsp_portals_h diff --git a/tools/qfbsp/include/readbsp.h b/tools/qfbsp/include/readbsp.h index 17f1b2890..5887a68ea 100644 --- a/tools/qfbsp/include/readbsp.h +++ b/tools/qfbsp/include/readbsp.h @@ -25,7 +25,7 @@ /** \defgroup qfbsp_readbsp BSP Reading Functions \ingroup qfbsp */ -//@{ +///@{ /** Load the bspfile into memory. */ @@ -47,6 +47,6 @@ void extract_entities (void); */ void extract_hull (void); -//@} +///@} #endif//qfbsp_readbsp_h diff --git a/tools/qfbsp/include/region.h b/tools/qfbsp/include/region.h index ce30e71f7..2a17734c5 100644 --- a/tools/qfbsp/include/region.h +++ b/tools/qfbsp/include/region.h @@ -25,7 +25,7 @@ /** \defgroup qfbsp_region Region Functions \ingroup qfbsp */ -//@{ +///@{ struct node_s; @@ -35,6 +35,6 @@ struct node_s; */ void GrowNodeRegions (struct node_s *headnode); -//@} +///@} #endif//qfbsp_region_h diff --git a/tools/qfbsp/include/solidbsp.h b/tools/qfbsp/include/solidbsp.h index 18bd306a6..5a3d7fbe4 100644 --- a/tools/qfbsp/include/solidbsp.h +++ b/tools/qfbsp/include/solidbsp.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_solidbsp BSP Creation Functions \ingroup qfbsp */ -//@{ +///@{ struct visfacet_s; struct plane_s; @@ -48,6 +48,6 @@ void CalcSurfaceInfo (struct surface_s *surf); */ struct node_s *SolidBSP (struct surface_s *surfhead, qboolean midsplit); -//@} +///@} #endif//qfbsp_solidbsp_h diff --git a/tools/qfbsp/include/surfaces.h b/tools/qfbsp/include/surfaces.h index ebb8314cc..561d21048 100644 --- a/tools/qfbsp/include/surfaces.h +++ b/tools/qfbsp/include/surfaces.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_surface Surface Functions \ingroup qfbsp */ -//@{ +///@{ struct visfacet_s; struct node_s; @@ -104,6 +104,6 @@ struct surface_s *GatherNodeFaces (struct node_s *headnode); */ void MakeFaceEdges (struct node_s *headnode); -//@} +///@} #endif//surfaces_h diff --git a/tools/qfbsp/include/tjunc.h b/tools/qfbsp/include/tjunc.h index 46fa939fc..3557e4df7 100644 --- a/tools/qfbsp/include/tjunc.h +++ b/tools/qfbsp/include/tjunc.h @@ -25,7 +25,7 @@ /** \defgroup qfbsp_tjunc T-Junction Repair \ingroup qfbsp */ -//@{ +///@{ struct node_s; @@ -35,6 +35,6 @@ struct node_s; */ void tjunc (struct node_s *headnode); -//@} +///@} #endif//qfbsp_tjunc_h diff --git a/tools/qfbsp/include/writebsp.h b/tools/qfbsp/include/writebsp.h index 6d2a5cf0f..759220904 100644 --- a/tools/qfbsp/include/writebsp.h +++ b/tools/qfbsp/include/writebsp.h @@ -27,7 +27,7 @@ /** \defgroup qfbsp_writebsp BSP Writing Functions \ingroup qfbsp */ -//@{ +///@{ struct node_s; @@ -78,6 +78,6 @@ void BeginBSPFile (void); */ void FinishBSPFile (void); -//@} +///@} #endif//qfbsp_writebsp_h diff --git a/tools/qfcc/include/dags.h b/tools/qfcc/include/dags.h index c0d07c4b3..c83c029f6 100644 --- a/tools/qfcc/include/dags.h +++ b/tools/qfcc/include/dags.h @@ -33,7 +33,7 @@ /** \defgroup qfcc_dags DAG building \ingroup qfcc */ -//@{ +///@{ #include "QF/pr_comp.h" @@ -110,6 +110,6 @@ dag_t *dag_create (struct flownode_s *flownode); void dag_remove_dead_nodes (dag_t *dag); void dag_generate (dag_t *dag, sblock_t *block); -//@} +///@} #endif//dags_h diff --git a/tools/qfcc/include/def.h b/tools/qfcc/include/def.h index 68b946fab..df0104178 100644 --- a/tools/qfcc/include/def.h +++ b/tools/qfcc/include/def.h @@ -37,7 +37,7 @@ /** \defgroup qfcc_def Def handling \ingroup qfcc */ -//@{ +///@{ struct symbol_s; struct expr_s; @@ -180,7 +180,7 @@ void free_def (def_t *def); Temporary defs are bound to the current function (::current_func must be valid). They are always allocated from the funciont's local defspace. */ -//@{ +///@{ /** Get a temporary def. If the current function has a free temp def of the same size as \a size, @@ -207,7 +207,7 @@ def_t *temp_def (struct type_s *type); \param temp The temp def to be recycled. */ void free_temp_def (def_t *temp); -//@} +///@} /** Initialize a vm def from a qfcc def. @@ -306,6 +306,6 @@ int def_size (def_t *def) __attribute__((pure)); */ int def_visit_all (def_t *def, int overlap, int (*visit) (def_t *, void *), void *data); -//@} +///@} #endif//__def_h diff --git a/tools/qfcc/include/defspace.h b/tools/qfcc/include/defspace.h index 8e7f034d6..bd4b68920 100644 --- a/tools/qfcc/include/defspace.h +++ b/tools/qfcc/include/defspace.h @@ -37,7 +37,7 @@ /** \defgroup qfcc_defspace Defspace handling \ingroup qfcc */ -//@{ +///@{ typedef enum { ds_backed, ///< data space is globally addressable (near/far/type) and @@ -145,6 +145,6 @@ void defspace_free_loc (defspace_t *space, int ofs, int size); */ int defspace_add_data (defspace_t *space, pr_type_t *data, int size); -//@} +///@} #endif//__defspace_h diff --git a/tools/qfcc/include/diagnostic.h b/tools/qfcc/include/diagnostic.h index bd32711f8..3a19c9722 100644 --- a/tools/qfcc/include/diagnostic.h +++ b/tools/qfcc/include/diagnostic.h @@ -36,7 +36,7 @@ /** \defgroup qfcc_diagnostic Diagnostic Messages \ingroup qfcc */ -//@{ +///@{ typedef void (*diagnostic_hook)(const char *message); extern diagnostic_hook bug_hook; @@ -73,6 +73,6 @@ void _bug (struct expr_s *e, const char *file, int line, const char *fmt, ...) __attribute__ ((format (printf, 4, 5))); #define bug(e, fmt...) _bug(e, __FILE__, __LINE__, fmt) -//@} +///@} #endif//__diagnostic_h diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 5109b364e..d83610b7f 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -36,7 +36,7 @@ /** \defgroup qfcc_expr Expressions \ingroup qfcc */ -//@{ +///@{ /** Type of the exression node in an expression tree. */ @@ -652,6 +652,6 @@ expr_t *sizeof_expr (expr_t *expr, struct type_s *type); expr_t *fold_constants (expr_t *e); -//@} +///@} #endif//__expr_h diff --git a/tools/qfcc/include/flow.h b/tools/qfcc/include/flow.h index 591704a01..b4cc48cf5 100644 --- a/tools/qfcc/include/flow.h +++ b/tools/qfcc/include/flow.h @@ -33,7 +33,7 @@ /** \defgroup qfcc_flow Flow graph analysis \ingroup qfcc */ -//@{ +///@{ struct function_s; struct sblock_s; @@ -120,6 +120,6 @@ void dump_dot_flow_live (void *g, const char *filename); void dump_dot_flow_reaching (void *g, const char *filename); void dump_dot_flow_statements (void *g, const char *filename); -//@} +///@} #endif//flow_h diff --git a/tools/qfcc/include/function.h b/tools/qfcc/include/function.h index d145fc53e..88ea05dc8 100644 --- a/tools/qfcc/include/function.h +++ b/tools/qfcc/include/function.h @@ -34,7 +34,7 @@ /** \defgroup qfcc_function Internal function structures. \ingroup qfcc */ -//@{ +///@{ #include "QF/pr_comp.h" #include "QF/pr_debug.h" @@ -147,6 +147,6 @@ void emit_function (function_t *f, struct expr_s *e); int function_parms (function_t *f, byte *parm_size); void clear_functions (void); -//@} +///@} #endif//__function_h diff --git a/tools/qfcc/include/obj_file.h b/tools/qfcc/include/obj_file.h index 1fe1d3690..0e6096028 100644 --- a/tools/qfcc/include/obj_file.h +++ b/tools/qfcc/include/obj_file.h @@ -34,7 +34,7 @@ /** \defgroup qfcc_qfo Object file functions \ingroup qfcc */ -//@{ +///@{ #include "QF/pr_comp.h" #include "QF/pr_debug.h" @@ -106,12 +106,12 @@ typedef struct qfo_def_s { string_t file; ///< source file name pr_uint_t line; ///< source line number } qfo_def_t; -//@} +///@} /** \defgroup qfcc_qfo_QFOD QFOD flags \ingroup qfcc_qfo */ -//@{ +///@{ /** The def has been initialized. @@ -168,11 +168,11 @@ typedef struct qfo_def_s { \hideinitializer */ #define QFOD_PARAM (1u<<8) -//@} +///@} /** \addtogroup qfcc_qfo */ -//@{ +///@{ /** Representation of a function in the object file. */ @@ -286,13 +286,13 @@ enum { qfo_num_spaces }; -//@} +///@} /** \defgroup qfcc_qfo_data_access QFO Data Acess \ingroup qfcc_qfo Macros for accessing data in the QFO address space */ -//@{ +///@{ /** \internal \param q pointer to ::qfo_t struct @@ -361,7 +361,6 @@ enum { \param q pointer to ::qfo_t struct \param s space index - \param s offset into object file string space \return (char *) \hideinitializer @@ -439,11 +438,11 @@ enum { */ #define QFO_STRUCT(q, s, t, o) (*QFO_POINTER (q, s, t, o)) -//@} +///@} /** \addtogroup qfcc_qfo */ -//@{ +///@{ struct pr_info_s; @@ -485,6 +484,6 @@ qfo_t *qfo_new (void); */ void qfo_delete (qfo_t *qfo); -//@} +///@} #endif//__obj_file_h diff --git a/tools/qfcc/include/obj_type.h b/tools/qfcc/include/obj_type.h index d9c677641..13ce701e4 100644 --- a/tools/qfcc/include/obj_type.h +++ b/tools/qfcc/include/obj_type.h @@ -38,6 +38,4 @@ struct type_s; struct def_s *qfo_encode_type (struct type_s *type); -//@} - #endif//__obj_type_h diff --git a/tools/qfcc/include/pragma.h b/tools/qfcc/include/pragma.h index 1f6726f28..5f660ac23 100644 --- a/tools/qfcc/include/pragma.h +++ b/tools/qfcc/include/pragma.h @@ -33,10 +33,10 @@ /** \defgroup qfcc_pragma pragma handling \ingroup qfcc */ -//@{ +///@{ void pragma (const char *id); -//@} +///@} #endif//pragma_h diff --git a/tools/qfcc/include/qfcc.h b/tools/qfcc/include/qfcc.h index 0bec07d37..1a1793b34 100644 --- a/tools/qfcc/include/qfcc.h +++ b/tools/qfcc/include/qfcc.h @@ -39,7 +39,7 @@ /** \defgroup qfcc_general General functions \ingroup qfcc */ -//@{ +///@{ typedef struct srcline_s srcline_t; struct srcline_s { @@ -132,6 +132,6 @@ char *fix_backslash (char *path); */ #define RUP(x,a) (((x) + ((a) - 1)) & ~((a) - 1)) -//@} +///@} #endif//__qfcc_h diff --git a/tools/qfcc/include/symtab.h b/tools/qfcc/include/symtab.h index f338077eb..c0c064f3e 100644 --- a/tools/qfcc/include/symtab.h +++ b/tools/qfcc/include/symtab.h @@ -39,7 +39,7 @@ enum storage_class_e; /** \defgroup qfcc_symtab Symbol Table Management \ingroup qfcc */ -//@{ +///@{ typedef enum vis_e { vis_public, @@ -235,6 +235,6 @@ symtab_t *symtab_flat_copy (symtab_t *symtab, symtab_t *parent); symbol_t *make_symbol (const char *name, struct type_s *type, struct defspace_s *space, enum storage_class_e storage); -//@} +///@} #endif//__symtab_h diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index 11bee26e6..883af01e0 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -34,7 +34,7 @@ /** \defgroup qfcc_value Constant values. \ingroup qfcc_expr */ -//@{ +///@{ struct ex_value_s; struct type_s; @@ -63,6 +63,6 @@ int ReuseString (const char *str); void clear_immediates (void); -//@} +///@} #endif//__value_h diff --git a/tools/qflight/include/entities.h b/tools/qflight/include/entities.h index 82bf378cc..6f3d1dd12 100644 --- a/tools/qflight/include/entities.h +++ b/tools/qflight/include/entities.h @@ -34,7 +34,7 @@ /** \defgroup qflight_entities Light entity data. \ingroup qflight */ -//@{ +///@{ #define DEFAULTLIGHTLEVEL 300 #define DEFAULTFALLOFF 1.0f @@ -106,6 +106,6 @@ void GetVectorForKey (entity_t *ent, const char *key, vec3_t vec); void LoadEntities (void); void WriteEntitiesToString (void); -//@} +///@} #endif// __entities_h diff --git a/tools/qflight/include/light.h b/tools/qflight/include/light.h index e06a9157a..350b7e442 100644 --- a/tools/qflight/include/light.h +++ b/tools/qflight/include/light.h @@ -37,7 +37,7 @@ /** \defgroup qflight_general General functions \ingroup qflight */ -//@{ +///@{ #define ON_EPSILON 0.1 #define MAXLIGHTS 1024 @@ -130,6 +130,6 @@ extern int num_novislights; const char *get_tex_name (int texindex) __attribute__((pure)); -//@} +///@} #endif// __light_h diff --git a/tools/qflight/include/noise.h b/tools/qflight/include/noise.h index 30625ae13..be63d9de1 100644 --- a/tools/qflight/include/noise.h +++ b/tools/qflight/include/noise.h @@ -31,7 +31,7 @@ /** \defgroup qflight_noise Light noise functions. \ingroup qflight */ -//@{ +///@{ float noise3d (vec3_t v, int num) __attribute__((pure)); float noiseXYZ (float x, float y, float z, int num) __attribute__((pure)); @@ -39,4 +39,4 @@ float noise_scaled (vec3_t v, float s, int num) __attribute__((pure)); float noise_perlin (vec3_t v, float p, int num) __attribute__((pure)); void snap_vector (vec3_t v_old, vec3_t v_new, float scale); -//@} +///@} diff --git a/tools/qflight/include/options.h b/tools/qflight/include/options.h index a90592519..32c6d6755 100644 --- a/tools/qflight/include/options.h +++ b/tools/qflight/include/options.h @@ -33,7 +33,7 @@ /** \defgroup qflight_options Light command line options. \ingroup qflight */ -//@{ +///@{ typedef struct { int verbosity; // 0=silent @@ -59,6 +59,6 @@ extern const char *this_program; int DecodeArgs (int argc, char **argv); void usage (int status) __attribute__((noreturn)); -//@} +///@} #endif//__options_h diff --git a/tools/qflight/include/properties.h b/tools/qflight/include/properties.h index a6b724d19..d5e73db7f 100644 --- a/tools/qflight/include/properties.h +++ b/tools/qflight/include/properties.h @@ -33,7 +33,7 @@ /** \defgroup qflight_properties Lighting properties \ingroup qflight */ -//@{ +///@{ struct plitem_s; @@ -199,6 +199,6 @@ void set_properties (entity_t *ent, struct plitem_s *dict); */ void LoadProperties (const char *filename); -//@} +///@} #endif//__properties_h diff --git a/tools/qflight/include/threads.h b/tools/qflight/include/threads.h index 30b9cc59f..0fd5c00af 100644 --- a/tools/qflight/include/threads.h +++ b/tools/qflight/include/threads.h @@ -32,7 +32,7 @@ /** \defgroup qflight_threads Light thread handling. \ingroup qflight */ -//@{ +///@{ #if defined (HAVE_PTHREAD_H) && defined (HAVE_PTHREAD) @@ -66,6 +66,6 @@ typedef void *(threadfunc_t) (void *); void InitThreads (void); void RunThreadsOn (threadfunc_t func); -//@} +///@} #endif// __threads_h From 3208fce42e7b497a8cf129bc223fdc7007482814 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 11 Feb 2020 15:27:32 +0900 Subject: [PATCH 056/435] Fix ambiguous image file name warnings Most of the warnings are due to a bug in doxygen (fixed in 1.8.17, but...), however some were legit due to overzealous image search paths wildly including the doxygen output tree. --- doc/quakeforge.dox.conf.in | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/quakeforge.dox.conf.in b/doc/quakeforge.dox.conf.in index 64028f578..3781f222a 100644 --- a/doc/quakeforge.dox.conf.in +++ b/doc/quakeforge.dox.conf.in @@ -937,7 +937,6 @@ EXAMPLE_RECURSIVE = NO # \image command). IMAGE_PATH = @TOPSRC@/doc \ - @builddir@ \ @builddir@/progs \ @builddir@/qtv From 6e96b91aa1b34815027f3a8a21f7443603de1ea2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 11 Feb 2020 15:59:12 +0900 Subject: [PATCH 057/435] Fix a couple more optimization warnings --- libs/video/renderer/vulkan/device.c | 2 +- libs/video/renderer/vulkan/util.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index 0ed7ec808..750534f53 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -59,7 +59,7 @@ #include "util.h" -static int +static int __attribute__((const)) count_bits (uint32_t val) { int bits = 0; diff --git a/libs/video/renderer/vulkan/util.h b/libs/video/renderer/vulkan/util.h index ae87b8096..41181ff9e 100644 --- a/libs/video/renderer/vulkan/util.h +++ b/libs/video/renderer/vulkan/util.h @@ -5,7 +5,7 @@ typedef struct strset_s strset_t; -int count_strings (const char * const *str); +int count_strings (const char * const *str) __attribute__((const)); void merge_strings (const char **out, const char * const *in1, const char * const *in2); void prune_strings (strset_t *strset, const char **strings, uint32_t *count); From 85a2f9f621e67b6db5691c5da01573e6671475b3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 12 Feb 2020 16:36:01 +0900 Subject: [PATCH 058/435] Implement descriptor stuff --- include/QF/Vulkan/descriptor.h | 123 +++++++++ include/QF/Vulkan/funclist.h | 11 + libs/video/renderer/vulkan/Makefile.am | 1 + libs/video/renderer/vulkan/descriptor.c | 342 ++++++++++++++++++++++++ 4 files changed, 477 insertions(+) create mode 100644 include/QF/Vulkan/descriptor.h create mode 100644 libs/video/renderer/vulkan/descriptor.c diff --git a/include/QF/Vulkan/descriptor.h b/include/QF/Vulkan/descriptor.h new file mode 100644 index 000000000..ced2805a1 --- /dev/null +++ b/include/QF/Vulkan/descriptor.h @@ -0,0 +1,123 @@ +#ifndef __QF_Vulkan_descriptor_h +#define __QF_Vulkan_descriptor_h + +typedef struct qfv_sampler_s { + struct qfv_device_s *device; + VkSampler sampler; +} qfv_sampler_t; + +typedef struct qfv_bindingset_s { + int numBindings; + VkDescriptorSetLayoutBinding bindings[]; +} qfv_bindingset_t; + +typedef struct qfv_descriptorsetlayout_s { + struct qfv_device_s *device; + VkDescriptorSetLayout layout; +} qfv_descriptorsetlayout_t; + +typedef struct qfv_descriptorpool_s { + struct qfv_device_s *device; + VkDescriptorPool pool; +} qfv_descriptorpool_t; + +typedef struct qfv_descriptorset_s { + struct qfv_device_s *device; + qfv_descriptorpool_t *pool; + VkDescriptorSet set; +} qfv_descriptorset_t; + +typedef struct qfv_imagedescriptorinfo_s { + qfv_descriptorset_t *descriptorset; + uint32_t binding; + uint32_t arrayElement; + VkDescriptorType type; + uint32_t numInfo; + VkDescriptorImageInfo infos[]; +} qfv_imagedescriptorinfo_t; + +typedef struct qfv_bufferdescriptorinfo_s { + qfv_descriptorset_t *descriptorset; + uint32_t binding; + uint32_t arrayElement; + VkDescriptorType type; + uint32_t numInfo; + VkDescriptorBufferInfo infos[]; +} qfv_bufferdescriptorinfo_t; + +typedef struct qfv_texelbufferdescriptorinfo_s { + qfv_descriptorset_t *descriptorset; + uint32_t binding; + uint32_t arrayElement; + VkDescriptorType type; + uint32_t numInfo; + VkBufferView infos[]; +} qfv_texelbufferdescriptorinfo_t; + +typedef struct qfv_copydescriptorinfo_s { + qfv_descriptorset_t *dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + qfv_descriptorset_t *srcSet; + uint32_t srcBinding; + uint32_t srcArrayElement; + uint32_t descriptorCount; +} qfv_copydescriptorinfo_t; + +qfv_sampler_t *QFV_CreateSampler (struct qfv_device_s *device, + VkFilter magFilter, VkFilter minFilter, + VkSamplerMipmapMode mipmapMode, + VkSamplerAddressMode addressModeU, + VkSamplerAddressMode addressModeV, + VkSamplerAddressMode addressModeW, + float mipLodBias, + VkBool32 anisotryEnable, float maxAnisotropy, + VkBool32 compareEnable, VkCompareOp compareOp, + float minLod, float maxLod, + VkBorderColor borderColor, + VkBool32 unnormalizedCoordinates); + +qfv_bindingset_t *QFV_CreateBindingSet (int numBindings); +void QFV_DestroyBindingSet (qfv_bindingset_t *bindingset); + +qfv_descriptorsetlayout_t * +QFV_CreateDescriptorSetLayout (struct qfv_device_s *device, + qfv_bindingset_t *bindings); + +qfv_descriptorpool_t * +QFV_CreateDescriptorPool (struct qfv_device_s *device, + VkDescriptorPoolCreateFlags flags, uint32_t maxSets, + qfv_bindingset_t *bindings); + +qfv_descriptorset_t * +QFV_AllocateDescriptorSet (qfv_descriptorpool_t *pool, + qfv_descriptorsetlayout_t *layout); + +#define QFV_allocateinfo(type, num, allocator) \ + allocator (field_offset (type, infos[num])) +#define QFV_ImageDescriptorInfo(num, allocator) \ + QFV_allocateinfo(qfv_imagedescriptorinfo_t, num, allocator) +#define QFV_BufferDescriptorInfo(num, allocator) \ + QFV_allocateinfo(qfv_bufferdescriptorinfo_t, num, allocator) +#define QFV_TexelBufferDescriptorInfo(num, allocator) \ + QFV_allocateinfo(qfv_texelbufferdescriptorinfo_t, num, allocator) + +void +QFV_UpdateDescriptorSets (struct qfv_device_s *device, + uint32_t numImageInfos, + qfv_imagedescriptorinfo_t *imageInfos, + uint32_t numBufferInfos, + qfv_bufferdescriptorinfo_t *bufferInfos, + uint32_t numTexelBufferInfos, + qfv_texelbufferdescriptorinfo_t *texelbufferInfos, + uint32_t numCopyInfos, + qfv_copydescriptorinfo_t *copyInfos); + +void QFV_FreeDescriptorSet (qfv_descriptorset_t *set); +void QFV_ResetDescriptorPool (qfv_descriptorpool_t *pool); +void QFV_DestroyDescriptorPool (qfv_descriptorpool_t *pool); +void QFV_DestroyDescriptorSetLayout (qfv_descriptorsetlayout_t *layout); +void QFV_DestroySampler (qfv_sampler_t *sampler); + + +#endif//__QF_Vulkan_descriptor_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 1f00d0b54..e25188999 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -128,6 +128,17 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkMapMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkUnmapMemory) DEVICE_LEVEL_VULKAN_FUNCTION (vkFlushMappedMemoryRanges) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateSampler) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateDescriptorSetLayout) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateDescriptorPool) +DEVICE_LEVEL_VULKAN_FUNCTION (vkAllocateDescriptorSets) +DEVICE_LEVEL_VULKAN_FUNCTION (vkUpdateDescriptorSets) +DEVICE_LEVEL_VULKAN_FUNCTION (vkFreeDescriptorSets) +DEVICE_LEVEL_VULKAN_FUNCTION (vkResetDescriptorPool) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyDescriptorPool) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyDescriptorSetLayout) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroySampler) + DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPipelineBarrier) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBuffer) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBufferToImage) diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index ba9b64948..ec888d6cd 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -6,6 +6,7 @@ AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES vulkan_src = \ buffer.c \ command.c \ + descriptor.c \ device.c \ image.c \ instance.c \ diff --git a/libs/video/renderer/vulkan/descriptor.c b/libs/video/renderer/vulkan/descriptor.c new file mode 100644 index 000000000..4662cb9b4 --- /dev/null +++ b/libs/video/renderer/vulkan/descriptor.c @@ -0,0 +1,342 @@ +/* + descriptor.c + + Vulkan descriptor functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +qfv_sampler_t * +QFV_CreateSampler (qfv_device_t *device, + VkFilter magFilter, VkFilter minFilter, + VkSamplerMipmapMode mipmapMode, + VkSamplerAddressMode addressModeU, + VkSamplerAddressMode addressModeV, + VkSamplerAddressMode addressModeW, + float mipLodBias, + VkBool32 anisotryEnable, float maxAnisotropy, + VkBool32 compareEnable, VkCompareOp compareOp, + float minLod, float maxLod, + VkBorderColor borderColor, + VkBool32 unnormalizedCoordinates) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkSamplerCreateInfo createInfo = { + VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 0, + 0, + magFilter, minFilter, mipmapMode, + addressModeU, addressModeV, addressModeW, + mipLodBias, + anisotryEnable, maxAnisotropy, + compareEnable, compareOp, + minLod, maxLod, + borderColor, unnormalizedCoordinates, + }; + + qfv_sampler_t *sampler = malloc (sizeof (*sampler)); + sampler->device = device; + dfunc->vkCreateSampler (dev, &createInfo, 0, &sampler->sampler); + return sampler; +} + +qfv_bindingset_t * +QFV_CreateBindingSet (int numBindings) +{ + qfv_bindingset_t *bindingset; + bindingset = malloc (field_offset (qfv_bindingset_t, + bindings[numBindings])); + bindingset->numBindings = numBindings; + return bindingset; +} + +void +QFV_DestroyBindingSet (qfv_bindingset_t *bindingset) +{ + free (bindingset); +} + +qfv_descriptorsetlayout_t * +QFV_CreateDescriptorSetLayout (qfv_device_t *device, + qfv_bindingset_t *bindingset) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkDescriptorSetLayoutCreateInfo createInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 0, + 0, + bindingset->numBindings, bindingset->bindings, + }; + + qfv_descriptorsetlayout_t *layout = malloc (sizeof (layout)); + layout->device = device; + dfunc->vkCreateDescriptorSetLayout (dev, &createInfo, 0, &layout->layout); + return layout; +} + +// There are currently only 13 descriptor types, so 16 should be plenty +static VkDescriptorPoolSize poolsize_pool[16]; +static VkDescriptorPoolSize *poolsize_next; + +static uintptr_t +poolsize_gethash (const void *ele, void *unused) +{ + const VkDescriptorPoolSize *poolsize = ele; + return poolsize->type; +} + +static int +poolsize_compmare (const void *ele1, const void *ele2, void *unused) +{ + const VkDescriptorPoolSize *poolsize1 = ele1; + const VkDescriptorPoolSize *poolsize2 = ele2; + return poolsize1->type == poolsize2->type; +} + +//FIXME not thread-safe +qfv_descriptorpool_t * +QFV_CreateDescriptorPool (qfv_device_t *device, + VkDescriptorPoolCreateFlags flags, uint32_t maxSets, + qfv_bindingset_t *bindings) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + static hashtab_t *poolsizes; + + if (!poolsizes) { + poolsizes = Hash_NewTable (16, 0, 0, 0); + Hash_SetHashCompare (poolsizes, poolsize_gethash, poolsize_compmare); + } else { + Hash_FlushTable (poolsizes); + } + poolsize_next = poolsize_pool; + + VkDescriptorPoolSize *ps; + for (int i = 0; i < bindings->numBindings; i++) { + VkDescriptorPoolSize test = { bindings->bindings[i].descriptorType, 0 }; + ps = Hash_FindElement (poolsizes, &test); + if (!ps) { + ps = poolsize_next++; + if ((size_t) (poolsize_next - poolsize_pool) + > sizeof (poolsize_pool) / sizeof (poolsize_pool[0])) { + Sys_Error ("Too many descriptor types"); + } + Hash_AddElement (poolsizes, ps); + } + //XXX is descriptorCount correct? + //FIXME assumes only one layout is used with this pool + ps->descriptorCount += bindings->bindings[i].descriptorCount * maxSets; + } + + VkDescriptorPoolCreateInfo createInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 0, + flags, maxSets, ps - poolsize_pool, poolsize_pool, + }; + + qfv_descriptorpool_t *descriptorpool = malloc (sizeof (descriptorpool)); + descriptorpool->device = device; + dfunc->vkCreateDescriptorPool (dev, &createInfo, 0, &descriptorpool->pool); + return descriptorpool; +} + +qfv_descriptorset_t * +QFV_AllocateDescriptorSet (qfv_descriptorpool_t *pool, + qfv_descriptorsetlayout_t *layout) +{ + qfv_device_t *device = pool->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkDescriptorSetAllocateInfo allocateInfo = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 0, + pool->pool, 1, &layout->layout, + }; + + qfv_descriptorset_t *descriptorset = malloc (sizeof (*descriptorset)); + descriptorset->device = device; + descriptorset->pool = pool; + dfunc->vkAllocateDescriptorSets (dev, &allocateInfo, &descriptorset->set); + return descriptorset; +} + +void +QFV_UpdateDescriptorSets (qfv_device_t *device, + uint32_t numImageInfos, + qfv_imagedescriptorinfo_t *imageInfos, + uint32_t numBufferInfos, + qfv_bufferdescriptorinfo_t *bufferInfos, + uint32_t numTexelBufferInfos, + qfv_texelbufferdescriptorinfo_t *texelbufferInfos, + uint32_t numCopyInfos, + qfv_copydescriptorinfo_t *copyInfos) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + uint32_t numWrite = 0; + numWrite += numImageInfos; + numWrite += numBufferInfos; + numWrite += numTexelBufferInfos; + VkWriteDescriptorSet *writeSets = alloca (numWrite * sizeof (*writeSets)); + VkWriteDescriptorSet *writeSet = writeSets; + for (uint32_t i = 0; i < numImageInfos; i++, writeSet++) { + writeSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeSet->pNext = 0; + writeSet->dstSet = imageInfos[i].descriptorset->set; + writeSet->dstBinding = imageInfos[i].binding; + writeSet->dstArrayElement = imageInfos[i].arrayElement; + writeSet->descriptorCount = imageInfos[i].numInfo; + writeSet->descriptorType = imageInfos[i].type; + writeSet->pImageInfo = imageInfos[i].infos; + writeSet->pBufferInfo = 0; + writeSet->pTexelBufferView = 0; + } + for (uint32_t i = 0; i < numBufferInfos; i++, writeSet++) { + writeSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeSet->pNext = 0; + writeSet->dstSet = bufferInfos[i].descriptorset->set; + writeSet->dstBinding = bufferInfos[i].binding; + writeSet->dstArrayElement = bufferInfos[i].arrayElement; + writeSet->descriptorCount = bufferInfos[i].numInfo; + writeSet->descriptorType = bufferInfos[i].type; + writeSet->pImageInfo = 0; + writeSet->pBufferInfo = bufferInfos[i].infos; + writeSet->pTexelBufferView = 0; + } + for (uint32_t i = 0; i < numTexelBufferInfos; i++, writeSet++) { + writeSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeSet->pNext = 0; + writeSet->dstSet = bufferInfos[i].descriptorset->set; + writeSet->dstBinding = texelbufferInfos[i].binding; + writeSet->dstArrayElement = texelbufferInfos[i].arrayElement; + writeSet->descriptorCount = texelbufferInfos[i].numInfo; + writeSet->descriptorType = texelbufferInfos[i].type; + writeSet->pImageInfo = 0; + writeSet->pBufferInfo = 0; + writeSet->pTexelBufferView = texelbufferInfos[i].infos; + } + VkCopyDescriptorSet *copySets = alloca (numWrite * sizeof (*copySets)); + VkCopyDescriptorSet *copySet = copySets; + for (uint32_t i = 0; i < numCopyInfos; i++, copySet++) { + copySet->sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET; + copySet->pNext = 0; + copySet->srcSet = copyInfos[i].srcSet->set; + copySet->srcBinding = copyInfos[i].srcBinding; + copySet->srcArrayElement = copyInfos[i].srcArrayElement; + copySet->dstSet = copyInfos[i].dstSet->set; + copySet->dstBinding = copyInfos[i].dstBinding; + copySet->dstArrayElement = copyInfos[i].dstArrayElement; + copySet->descriptorCount = copyInfos[i].descriptorCount; + } + dfunc->vkUpdateDescriptorSets (dev, numWrite, writeSets, + numCopyInfos, copySets); +} + +void +QFV_FreeDescriptorSet (qfv_descriptorset_t *set) +{ + qfv_device_t *device = set->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + VkDescriptorPool pool = set->pool->pool; + + dfunc->vkFreeDescriptorSets (dev, pool, 1, &set->set); +} + +void +QFV_ResetDescriptorPool (qfv_descriptorpool_t *pool) +{ + qfv_device_t *device = pool->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkResetDescriptorPool (dev, pool->pool, 0); +} + +void +QFV_DestroyDescriptorPool (qfv_descriptorpool_t *pool) +{ + qfv_device_t *device = pool->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyDescriptorPool (dev, pool->pool, 0); +} + +void +QFV_DestroyDescriptorSetLayout (qfv_descriptorsetlayout_t *layout) +{ + qfv_device_t *device = layout->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyDescriptorSetLayout (dev, layout->layout, 0); +} + +void +QFV_DestroySampler (qfv_sampler_t *sampler) +{ + qfv_device_t *device = sampler->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroySampler (dev, sampler->sampler, 0); +} From 44f5b134e6d2589071842a4fab5f7930a59c721d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 12 Feb 2020 18:55:22 +0900 Subject: [PATCH 059/435] Free custom descriptor structs Forgot this earlier --- libs/video/renderer/vulkan/descriptor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/video/renderer/vulkan/descriptor.c b/libs/video/renderer/vulkan/descriptor.c index 4662cb9b4..d0b2031c1 100644 --- a/libs/video/renderer/vulkan/descriptor.c +++ b/libs/video/renderer/vulkan/descriptor.c @@ -319,6 +319,7 @@ QFV_DestroyDescriptorPool (qfv_descriptorpool_t *pool) qfv_devfuncs_t *dfunc = device->funcs; dfunc->vkDestroyDescriptorPool (dev, pool->pool, 0); + free (pool); } void @@ -329,6 +330,7 @@ QFV_DestroyDescriptorSetLayout (qfv_descriptorsetlayout_t *layout) qfv_devfuncs_t *dfunc = device->funcs; dfunc->vkDestroyDescriptorSetLayout (dev, layout->layout, 0); + free (layout); } void @@ -339,4 +341,5 @@ QFV_DestroySampler (qfv_sampler_t *sampler) qfv_devfuncs_t *dfunc = device->funcs; dfunc->vkDestroySampler (dev, sampler->sampler, 0); + free (sampler); } From 61036378e2d7670f2de5564ee94c23bd71c2ef02 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 12 Feb 2020 18:55:51 +0900 Subject: [PATCH 060/435] Implement render pass stuff --- include/QF/Vulkan/command.h | 12 ++ include/QF/Vulkan/funclist.h | 8 ++ include/QF/Vulkan/renderpass.h | 72 +++++++++++ libs/video/renderer/vulkan/Makefile.am | 1 + libs/video/renderer/vulkan/command.c | 42 +++++++ libs/video/renderer/vulkan/renderpass.c | 151 ++++++++++++++++++++++++ 6 files changed, 286 insertions(+) create mode 100644 include/QF/Vulkan/renderpass.h create mode 100644 libs/video/renderer/vulkan/renderpass.c diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index 9326617ca..ffb462b98 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -92,6 +92,8 @@ void QFV_CmdPipelineBarrier (qfv_cmdbuffer_t *cmdBuffer, struct qfv_buffer_s; struct qfv_image_s; +struct qfv_renderpass_s; +struct qfv_framebuffer_s; void QFV_CmdCopyBuffer (qfv_cmdbuffer_t *cmdBuffer, struct qfv_buffer_s *src, struct qfv_buffer_s *dst, VkBufferCopy *regions, uint32_t numRegions); @@ -107,5 +109,15 @@ void QFV_CmdCopyImageToBuffer (qfv_cmdbuffer_t *cmdBuffer, struct qfv_buffer_s *dst, VkBufferImageCopy *regions, uint32_t numRegions); +void QFV_CmdBeginRenderPass (qfv_cmdbuffer_t *cmdBuffer, + struct qfv_renderpass_s *renderPass, + struct qfv_framebuffer_s *framebuffer, + VkRect2D renderArea, + uint32_t numClearValues, + VkClearValue *clearValues, + VkSubpassContents subpassContents); +void QFV_CmdNextSubpass (qfv_cmdbuffer_t *cmdBuffer, + VkSubpassContents subpassContents); +void QFV_CmdEndRenderPass (qfv_cmdbuffer_t *cmdBuffer); #endif//__QF_Vulkan_command_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index e25188999..f51e53478 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -139,10 +139,18 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyDescriptorPool) DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyDescriptorSetLayout) DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroySampler) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateRenderPass) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateFramebuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyRenderPass) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyFramebuffer) + DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPipelineBarrier) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBuffer) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBufferToImage) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyImageToBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBeginRenderPass) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdNextSubpass) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdEndRenderPass) #undef DEVICE_LEVEL_VULKAN_FUNCTION diff --git a/include/QF/Vulkan/renderpass.h b/include/QF/Vulkan/renderpass.h new file mode 100644 index 000000000..c8fdc2965 --- /dev/null +++ b/include/QF/Vulkan/renderpass.h @@ -0,0 +1,72 @@ +#ifndef __QF_Vulkan_renderpass_h +#define __QF_Vulkan_renderpass_h + +typedef struct qfv_attachmentdescription_s { + uint32_t numAttachments; + VkAttachmentDescription attachments[]; +} qfv_attachmentdescription_t; + +#define QFV_AllocAttachmentDescription(num, allocator) \ + allocator (field_offset (qfv_attachmentdescription_t, attachments[num])) + +typedef struct qfv_attachmentreference_s { + uint32_t numReferences; + VkAttachmentReference references[]; +} qfv_attachmentreference_t; + +#define QFV_AllocAttachmentReference(num, allocator) \ + allocator (field_offset (qfv_attachmentreference_t, references[num])) + +typedef struct qfv_subpassparameters_s { + VkPipelineBindPoint pipelineBindPoint; + qfv_attachmentreference_t *inputAttachments; + qfv_attachmentreference_t *colorAttachments; + qfv_attachmentreference_t *resolveAttachments; + VkAttachmentReference *depthStencilAttachment; + uint32_t numPreserve; + uint32_t *preserveAttachments; +} qfv_subpassparameters_t; + +typedef struct qfv_subpassparametersset_s { + uint32_t numSubpasses; + qfv_subpassparameters_t subpasses[]; +} qfv_subpassparametersset_t; + +#define QFV_AllocSubpassParametersSet(num, allocator) \ + allocator (field_offset (qfv_subpassparametersset_t, subpasses[num])) + +typedef struct qfv_subpassdependency_s { + uint32_t numDependencies; + VkSubpassDependency dependencies[]; +} qfv_subpassdependency_t; + +#define QFV_AllocSubpassDependencies(num, allocator) \ + allocator (field_offset (qfv_subpassdependency_t, dependencies[num])) + +typedef struct qfv_renderpass_s { + struct qfv_device_s *device; + VkRenderPass renderPass; +} qfv_renderpass_t; + +typedef struct qfv_framebuffer_s { + struct qfv_device_s *device; + VkFramebuffer framebuffer; +} qfv_framebuffer_t; + +qfv_renderpass_t * +QFV_CreateRenderPass (struct qfv_device_s *device, + qfv_attachmentdescription_t *attachments, + qfv_subpassparametersset_t *subpasses, + qfv_subpassdependency_t *dependencies); + +struct qfv_imageview_s; +qfv_framebuffer_t * +QFV_CreateFramebuffer (qfv_renderpass_t *renderPass, + uint32_t numAttachments, + struct qfv_imageview_s **attachments, + uint32_t width, uint32_t height, uint32_t layers); + +void QFV_DestroyFramebuffer (qfv_framebuffer_t *framebuffer); +void QFV_DestroyRenderPass (qfv_renderpass_t *renderPass); + +#endif//__QF_Vulkan_renderpass_h diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index ec888d6cd..936dd504d 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -11,6 +11,7 @@ vulkan_src = \ image.c \ instance.c \ memory.c \ + renderpass.c \ swapchain.c \ util.c \ vulkan_draw.c \ diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index 46c2ed83f..15e884b64 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -51,6 +51,7 @@ #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/buffer.h"//FIXME should QFV_CmdPipelineBarrier be here? #include "QF/Vulkan/image.h"//FIXME should QFV_CmdPipelineBarrier be here? +#include "QF/Vulkan/renderpass.h"//FIXME should QFV_CmdPipelineBarrier be here? #include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" @@ -462,3 +463,44 @@ QFV_CmdCopyImageToBuffer (qfv_cmdbuffer_t *cmdBuffer, dfunc->vkCmdCopyImageToBuffer (cmdBuffer->buffer, src->image, layout, dst->buffer, numRegions, regions); } + +void +QFV_CmdBeginRenderPass (qfv_cmdbuffer_t *cmdBuffer, + qfv_renderpass_t *renderPass, + qfv_framebuffer_t *framebuffer, + VkRect2D renderArea, + uint32_t numClearValues, + VkClearValue *clearValues, + VkSubpassContents subpassContents) +{ + qfv_device_t *device = cmdBuffer->device; + qfv_devfuncs_t *dfunc = device->funcs; + + VkRenderPassBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 0, + renderPass->renderPass, framebuffer->framebuffer, renderArea, + numClearValues, clearValues, + }; + + dfunc->vkCmdBeginRenderPass (cmdBuffer->buffer, &beginInfo, + subpassContents); +} + +void +QFV_CmdNextSubpass (qfv_cmdbuffer_t *cmdBuffer, + VkSubpassContents subpassContents) +{ + qfv_device_t *device = cmdBuffer->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkCmdNextSubpass (cmdBuffer->buffer, subpassContents); +} + +void +QFV_CmdEndRenderPass (qfv_cmdbuffer_t *cmdBuffer) +{ + qfv_device_t *device = cmdBuffer->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkCmdEndRenderPass (cmdBuffer->buffer); +} diff --git a/libs/video/renderer/vulkan/renderpass.c b/libs/video/renderer/vulkan/renderpass.c new file mode 100644 index 000000000..9c1064192 --- /dev/null +++ b/libs/video/renderer/vulkan/renderpass.c @@ -0,0 +1,151 @@ +/* + descriptor.c + + Vulkan descriptor functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/renderpass.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +qfv_renderpass_t * +QFV_CreateRenderPass (qfv_device_t *device, + qfv_attachmentdescription_t *attachments, + qfv_subpassparametersset_t *subpassparams, + qfv_subpassdependency_t *dependencies) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkSubpassDescription *subpasses = alloca (subpassparams->numSubpasses + * sizeof (*subpasses)); + + for (uint32_t i = 0; i < subpassparams->numSubpasses; i++) { + qfv_subpassparameters_t *params = &subpassparams->subpasses[i]; + subpasses[i].flags = 0; + subpasses[i].pipelineBindPoint = params->pipelineBindPoint; + subpasses[i].inputAttachmentCount = params->inputAttachments->numReferences; + subpasses[i].pInputAttachments = params->inputAttachments->references; + subpasses[i].colorAttachmentCount = params->colorAttachments->numReferences; + subpasses[i].pColorAttachments = params->colorAttachments->references; + if (params->resolveAttachments) { + subpasses[i].pResolveAttachments = params->resolveAttachments->references; + } + subpasses[i].pDepthStencilAttachment = params->depthStencilAttachment; + subpasses[i].preserveAttachmentCount = params->numPreserve; + subpasses[i].pPreserveAttachments = params->preserveAttachments; + } + + VkRenderPassCreateInfo createInfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 0, 0, + attachments->numAttachments, attachments->attachments, + subpassparams->numSubpasses, subpasses, + dependencies->numDependencies, dependencies->dependencies, + }; + + qfv_renderpass_t *renderpass = malloc (sizeof (*renderpass)); + renderpass->device = device; + dfunc->vkCreateRenderPass (dev, &createInfo, 0, &renderpass->renderPass); + return renderpass; +} + +qfv_framebuffer_t * +QFV_CreateFramebuffer (qfv_renderpass_t *renderPass, + uint32_t numAttachments, qfv_imageview_t **attachments, + uint32_t width, uint32_t height, uint32_t layers) +{ + qfv_device_t *device = renderPass->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkImageView *views = alloca (numAttachments * sizeof (*views)); + for (uint32_t i = 0; i < numAttachments; i++) { + views[i] = attachments[i]->view; + } + + VkFramebufferCreateInfo createInfo = { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 0, 0, + renderPass->renderPass, numAttachments, views, width, height, layers, + }; + + qfv_framebuffer_t *framebuffer = malloc (sizeof (*framebuffer)); + framebuffer->device = device; + dfunc->vkCreateFramebuffer (dev, &createInfo, 0, &framebuffer->framebuffer); + return framebuffer; +} + +void +QFV_DestroyFramebuffer (qfv_framebuffer_t *framebuffer) +{ + qfv_device_t *device = framebuffer->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyFramebuffer (dev, framebuffer->framebuffer, 0); + free (framebuffer); +} + +void +QFV_DestroyRenderPass (qfv_renderpass_t *renderPass) +{ + qfv_device_t *device = renderPass->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyRenderPass (dev, renderPass->renderPass, 0); + free (renderPass); +} From 69c110193aefc07a8c1fdd9792071542c1d79050 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 13 Feb 2020 04:20:54 +0900 Subject: [PATCH 061/435] Fix a thinko Wrong var for computing number of slots used. --- libs/video/renderer/vulkan/descriptor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/descriptor.c b/libs/video/renderer/vulkan/descriptor.c index d0b2031c1..cc9cce6d4 100644 --- a/libs/video/renderer/vulkan/descriptor.c +++ b/libs/video/renderer/vulkan/descriptor.c @@ -188,7 +188,7 @@ QFV_CreateDescriptorPool (qfv_device_t *device, VkDescriptorPoolCreateInfo createInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 0, - flags, maxSets, ps - poolsize_pool, poolsize_pool, + flags, maxSets, poolsize_next - poolsize_pool, poolsize_pool, }; qfv_descriptorpool_t *descriptorpool = malloc (sizeof (descriptorpool)); From 53b46f05416ca3eaa8ad00180d3d0b074a60152d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 13 Feb 2020 04:21:35 +0900 Subject: [PATCH 062/435] Implement pipeline stuff --- include/QF/Vulkan/command.h | 4 + include/QF/Vulkan/descriptor.h | 9 + include/QF/Vulkan/funclist.h | 13 + include/QF/Vulkan/pipeline.h | 244 ++++++++++++ libs/video/renderer/vulkan/Makefile.am | 1 + libs/video/renderer/vulkan/command.c | 12 + libs/video/renderer/vulkan/pipeline.c | 525 +++++++++++++++++++++++++ 7 files changed, 808 insertions(+) create mode 100644 include/QF/Vulkan/pipeline.h create mode 100644 libs/video/renderer/vulkan/pipeline.c diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index ffb462b98..c1d54d43d 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -119,5 +119,9 @@ void QFV_CmdBeginRenderPass (qfv_cmdbuffer_t *cmdBuffer, void QFV_CmdNextSubpass (qfv_cmdbuffer_t *cmdBuffer, VkSubpassContents subpassContents); void QFV_CmdEndRenderPass (qfv_cmdbuffer_t *cmdBuffer); +struct qfv_pipeline_s; +void QFV_CmdBindPipeline (qfv_cmdbuffer_t *cmdBuffer, + VkPipelineBindPoint bindPoint, + struct qfv_pipeline_s *pipeline); #endif//__QF_Vulkan_command_h diff --git a/include/QF/Vulkan/descriptor.h b/include/QF/Vulkan/descriptor.h index ced2805a1..48a1cd92d 100644 --- a/include/QF/Vulkan/descriptor.h +++ b/include/QF/Vulkan/descriptor.h @@ -16,6 +16,15 @@ typedef struct qfv_descriptorsetlayout_s { VkDescriptorSetLayout layout; } qfv_descriptorsetlayout_t; +typedef struct qfv_descriptorsetlayoutset_s { + uint32_t numLayouts; + qfv_descriptorsetlayout_t *layouts[]; +} qfv_descriptorsetlayoutset_t; + +#define QFV_AllocDescriptorSetLayoutSet(num, allocator) \ + allocator (field_offset (qfv_descriptorsetlayoutset_t, layouts[num])) + + typedef struct qfv_descriptorpool_s { struct qfv_device_s *device; VkDescriptorPool pool; diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index f51e53478..5bacf29eb 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -144,6 +144,18 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateFramebuffer) DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyRenderPass) DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyFramebuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateShaderModule) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyShaderModule) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreatePipelineCache) +DEVICE_LEVEL_VULKAN_FUNCTION (vkGetPipelineCacheData) +DEVICE_LEVEL_VULKAN_FUNCTION (vkMergePipelineCaches) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyPipelineCache) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreatePipelineLayout) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyPipelineLayout) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateGraphicsPipelines) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateComputePipelines) +DEVICE_LEVEL_VULKAN_FUNCTION (vkDestroyPipeline) + DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPipelineBarrier) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBuffer) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBufferToImage) @@ -151,6 +163,7 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyImageToBuffer) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBeginRenderPass) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdNextSubpass) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdEndRenderPass) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindPipeline) #undef DEVICE_LEVEL_VULKAN_FUNCTION diff --git a/include/QF/Vulkan/pipeline.h b/include/QF/Vulkan/pipeline.h new file mode 100644 index 000000000..6a532102b --- /dev/null +++ b/include/QF/Vulkan/pipeline.h @@ -0,0 +1,244 @@ +#ifndef __QF_Vulkan_pipeline_h +#define __QF_Vulkan_pipeline_h + +typedef struct qfv_shadermodule_s { + struct qfv_device_s *device; + VkShaderModule module; +} qfv_shadermodule_t; + +typedef struct qfv_shaderstageparams_s { + VkShaderStageFlagBits stageFlags; + qfv_shadermodule_t *module; + const char *entryPointName; + const VkSpecializationInfo *specializationInfo; +} qfv_shaderstageparams_t; + +typedef struct qfv_shaderstageparamsset_s { + uint32_t numParams; + qfv_shaderstageparams_t params[]; +} qfv_shaderstageparamsset_t; + +#define QFV_AllocShaderParamsSet(num, allocator) \ + allocator (field_offset (qfv_shaderstageparamsset_t, params[num])) + +typedef struct qfv_vertexinputbindingset_s { + uint32_t numBindings; + VkVertexInputBindingDescription bindings[]; +} qfv_vertexinputbindingset_t; + +#define QFV_AllocVertexInputBindingSet(num, allocator) \ + allocator (field_offset (qfv_vertexinputbindingset_t, bindings[num])) + +typedef struct qfv_vertexinputattributeset_s { + uint32_t numAttributes; + VkVertexInputAttributeDescription attributes[]; +} qfv_vertexinputattributeset_t; + +#define QFV_AllocVertexInputAttributeSet(num, allocator) \ + allocator (field_offset (qfv_vertexinputattributeset_t, bindings[num])) + +typedef struct qfv_vertexinputstate_s { + qfv_vertexinputbindingset_t *bindings; + qfv_vertexinputattributeset_t *attributes; +} qfv_vertexinputstate_t; + +typedef struct qfv_pipelineinputassembly_s { + VkPrimitiveTopology topology; + VkBool32 primativeRestartEnable; +} qfv_pipelineinputassembly_t; + +typedef struct qfv_pipelinetessellation_s { + uint32_t patchControlPoints; +} qfv_pipelinetessellation_t; + +typedef struct qfv_viewportset_s { + uint32_t numViewports; + VkViewport viewports[]; +} qfv_viewportset_t; + +#define QFV_AllocViewportSet(num, allocator) \ + allocator (field_offset (qfv_viewportset_t, viewports[num])) + +typedef struct qfv_scissorsset_s { + uint32_t numScissors; + VkRect2D scissors[]; +} qfv_scissorsset_t; + +#define QFV_AllocScissorsSet(num, allocator) \ + allocator (field_offset (qfv_scissorsset_t, scissors[num])) + +typedef struct qfv_viewportinfo_s { + qfv_viewportset_t *viewportset; + qfv_scissorsset_t *scissorsset; +} qfv_viewportinfo_t; + +typedef struct qfv_pipelinerasterization_s { + VkBool32 depthClampEnable; + VkBool32 rasterizerDiscardEnable; + VkPolygonMode polygonMode; + VkCullModeFlags cullMode; + VkFrontFace frontFace; + VkBool32 depthBiasEnable; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; + float lineWidth; +} qfv_pipelinerasterization_t; + +typedef struct qfv_pipelinemultisample_s { + VkSampleCountFlagBits rasterizationSamples; + VkBool32 sampleShadingEnable; + float minSampleShading; + const VkSampleMask *sampleMask; + VkBool32 alphaToCoverageEnable; + VkBool32 alphaToOneEnable; +} qfv_pipelinemultisample_t; + +typedef struct qfv_pipelinedepthandstencil_s { + VkBool32 depthTestEnable; + VkBool32 depthWriteEnable; + VkCompareOp depthCompareOp; + VkBool32 depthBoundsTestEnable; + VkBool32 stencilTestEnable; + VkStencilOpState front; + VkStencilOpState back; + float minDepthBounds; + float maxDepthBounds; +} qfv_pipelinedepthandstencil_t; + +typedef struct qfv_blendattachmentset_s { + uint32_t numAttachments; + VkPipelineColorBlendAttachmentState attachments[]; +} qfv_blendattachmentset_t; + +#define QFV_AllocBlendAttachmentSet(num, allocator) \ + allocator (field_offset (qfv_blendattachmentset_t, attachments[num])) + +typedef struct qfv_pipelineblend_s { + VkBool32 logicOpEnable; + VkLogicOp logicOp; + qfv_blendattachmentset_t *blendAttachments; + float blendConstants[4]; +} qfv_pipelineblend_t; + +typedef struct qfv_dynamicstateset_s { + uint32_t numStates; + VkDynamicState states[]; +} qfv_dynamicstateset_t; + +#define QFV_AllocDynamicStateSet(num, allocator) \ + allocator (field_offset (qfv_dynamicstateset_t, states[num])) + +typedef struct qfv_pushconstantrangeset_s { + uint32_t numRanges; + VkPushConstantRange ranges[]; +} qfv_pushconstantrangeset_t; + +#define QFV_AllocPushConstantRangeSet(num, allocator) \ + allocator (field_offset (qfv_pushconstantrangeset_t, ranges[num])) + +typedef struct qfv_pipelinelayout_s { + struct qfv_device_s *device; + VkPipelineLayout layout; +} qfv_pipelinelayout_t; + +typedef struct qfv_pipeline_s { + struct qfv_device_s *device; + VkPipeline pipeline; +} qfv_pipeline_t; + +typedef struct qfv_pipelineset_s { + uint32_t numPipelines; + qfv_pipeline_t *pipelines[]; +} qfv_pipelineset_t; + +#define QFV_AllocPipelineSet(num, allocator) \ + allocator (field_offset (qfv_pipelineset_t, pipelines[num])) + +typedef struct qfv_graphicspipelinecreateinfo_s { + VkPipelineCreateFlags flags; + qfv_shaderstageparamsset_t *stages; + qfv_vertexinputstate_t *vertexState; + qfv_pipelineinputassembly_t *inputAssemblyState; + qfv_pipelinetessellation_t *tessellationState; + qfv_viewportinfo_t *viewportState; + qfv_pipelinerasterization_t *rasterizationState; + qfv_pipelinemultisample_t *multisampleState; + qfv_pipelinedepthandstencil_t *depthStencilState; + qfv_pipelineblend_t *colorBlendState; + qfv_dynamicstateset_t *dynamicState; + qfv_pipelinelayout_t *layout; + struct qfv_renderpass_s *renderPass; + uint32_t subpass; + qfv_pipeline_t *basePipeline; + int32_t basePipelineIndex; +} qfv_graphicspipelinecreateinfo_t; + +typedef struct qfv_graphicspipelinecreateinfoset_s { + uint32_t numPipelines; + qfv_graphicspipelinecreateinfo_t *pipelines[]; +} qfv_graphicspipelinecreateinfoset_t; + +#define QFV_AllocGraphicsPipelineCreateInfoSet(num, allocator) \ + allocator (field_offset (qfv_graphicspipelinecreateinfoset_t, \ + pipelines[num])) + +typedef struct qfv_computepipelinecreateinfo_s { + VkPipelineCreateFlags flags; + qfv_shaderstageparams_t *stage; + qfv_pipelinelayout_t *layout; + qfv_pipeline_t *basePipeline; + int32_t basePipelineIndex; +} qfv_computepipelinecreateinfo_t; + +typedef struct qfv_computepipelinecreateinfoset_s { + uint32_t numPipelines; + qfv_computepipelinecreateinfo_t *pipelines[]; +} qfv_computepipelinecreateinfoset_t; + +#define QFV_AllocComputePipelineCreateInfoSet(num, allocator) \ + allocator (field_offset (qfv_computepipelinecreateinfoset_t, \ + pipelines[num])) + +typedef struct qfv_pipelinecache_s { + struct qfv_device_s *device; + VkPipelineCache cache; +} qfv_pipelinecache_t; + +typedef struct qfv_pipelinecacheset_s { + uint32_t numCaches; + qfv_pipelinecache_t *caches[]; +} qfv_pipelinecacheset_t; + +#define QFV_AllocPipelineCacheSet(num, allocator) \ + allocator (field_offset (qfv_pipelinecacheset_t, caches[num])) + +qfv_shadermodule_t *QFV_CreateShaderModule (struct qfv_device_s *device, + size_t size, const uint32_t *code); +void QFV_DestroyShaderModule (qfv_shadermodule_t *module); + +struct dstring_s; +qfv_pipelinecache_t *QFV_CreatePipelineCache (struct qfv_device_s *device, + struct dstring_s *cacheData); +struct dstring_s *QFV_GetPipelineCacheData (qfv_pipelinecache_t *cache); +void QFV_MergePipelineCaches (qfv_pipelinecache_t *targetCache, + qfv_pipelinecacheset_t *sourceCaches); +void QFV_DestroyPipelineCache (qfv_pipelinecache_t *cache); + +struct qfv_descriptorsetlayoutset_s; +qfv_pipelinelayout_t * +QFV_CreatePipelineLayout (struct qfv_device_s *device, + struct qfv_descriptorsetlayoutset_s *layouts, + qfv_pushconstantrangeset_t *pushConstants); +void QFV_DestroyPipelineLayout (qfv_pipelinelayout_t *layout); +qfv_pipelineset_t * +QFV_CreateGraphicsPipelines (struct qfv_device_s *device, + qfv_pipelinecache_t *cache, + qfv_graphicspipelinecreateinfoset_t *gpciSet); +qfv_pipelineset_t * +QFV_CreateComputePipelines (struct qfv_device_s *device, + qfv_pipelinecache_t *cache, + qfv_computepipelinecreateinfoset_t *cpciSet); +void QFV_DestroyPipeline (qfv_pipeline_t *pipeline); + +#endif//__QF_Vulkan_pipeline_h diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am index 936dd504d..707b6b064 100644 --- a/libs/video/renderer/vulkan/Makefile.am +++ b/libs/video/renderer/vulkan/Makefile.am @@ -11,6 +11,7 @@ vulkan_src = \ image.c \ instance.c \ memory.c \ + pipeline.c \ renderpass.c \ swapchain.c \ util.c \ diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index 15e884b64..09621ede5 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -52,6 +52,7 @@ #include "QF/Vulkan/buffer.h"//FIXME should QFV_CmdPipelineBarrier be here? #include "QF/Vulkan/image.h"//FIXME should QFV_CmdPipelineBarrier be here? #include "QF/Vulkan/renderpass.h"//FIXME should QFV_CmdPipelineBarrier be here? +#include "QF/Vulkan/pipeline.h"//FIXME should QFV_CmdPipelineBarrier be here? #include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" @@ -504,3 +505,14 @@ QFV_CmdEndRenderPass (qfv_cmdbuffer_t *cmdBuffer) dfunc->vkCmdEndRenderPass (cmdBuffer->buffer); } + +void +QFV_CmdBindPipeline (qfv_cmdbuffer_t *cmdBuffer, + VkPipelineBindPoint bindPoint, + qfv_pipeline_t *pipeline) +{ + qfv_device_t *device = cmdBuffer->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkCmdBindPipeline (cmdBuffer->buffer, bindPoint, pipeline->pipeline); +} diff --git a/libs/video/renderer/vulkan/pipeline.c b/libs/video/renderer/vulkan/pipeline.c new file mode 100644 index 000000000..168ec100d --- /dev/null +++ b/libs/video/renderer/vulkan/pipeline.c @@ -0,0 +1,525 @@ +/* + pipeline.c + + Vulkan pipeline functions + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/pipeline.h" +#include "QF/Vulkan/renderpass.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +qfv_shadermodule_t * +QFV_CreateShaderModule (qfv_device_t *device, + size_t size, const uint32_t *code) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkShaderModuleCreateInfo createInfo = { + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0, 0, + size, code, + }; + + qfv_shadermodule_t *module = malloc (sizeof (*module)); + module->device = device; + dfunc->vkCreateShaderModule (dev, &createInfo, 0, &module->module); + return module; +} + +void +QFV_DestroyShaderModule (qfv_shadermodule_t *module) +{ + qfv_device_t *device = module->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyShaderModule (dev, module->module, 0); + free (module); +} + +qfv_pipelinecache_t * +QFV_CreatePipelineCache (qfv_device_t *device, dstring_t *cacheData) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkPipelineCacheCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, 0, 0, + cacheData->size, cacheData->str, + }; + + qfv_pipelinecache_t *cache = malloc (sizeof (*cache)); + cache->device = device; + dfunc->vkCreatePipelineCache (dev, &createInfo, 0, &cache->cache); + return cache; +} + +dstring_t * +QFV_GetPipelineCacheData (qfv_pipelinecache_t *cache) +{ + qfv_device_t *device = cache->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + dstring_t *cacheData = dstring_new (); + + dfunc->vkGetPipelineCacheData (dev, cache->cache, &cacheData->size, 0); + dstring_adjust (cacheData); + dfunc->vkGetPipelineCacheData (dev, cache->cache, &cacheData->size, + cacheData->str); + return cacheData; +} + +void +QFV_MergePipelineCaches (qfv_pipelinecache_t *targetCache, + qfv_pipelinecacheset_t *sourceCaches) +{ + qfv_device_t *device = targetCache->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + VkPipelineCache *srcCaches = alloca (sourceCaches->numCaches + * sizeof (*srcCaches)); + for (uint32_t i = 0; i < sourceCaches->numCaches; i++) { + srcCaches[i] = sourceCaches->caches[i]->cache; + } + dfunc->vkMergePipelineCaches (dev, targetCache->cache, + sourceCaches->numCaches, srcCaches); +} + +void +QFV_DestroyPipelineCache (qfv_pipelinecache_t *cache) +{ + qfv_device_t *device = cache->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyPipelineCache (dev, cache->cache, 0); +} + +qfv_pipelinelayout_t * +QFV_CreatePipelineLayout (qfv_device_t *device, + qfv_descriptorsetlayoutset_t *layoutset, + qfv_pushconstantrangeset_t *pushConstants) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + uint32_t numLayouts = layoutset->numLayouts; + VkDescriptorSetLayout *layouts = alloca (numLayouts * sizeof (*layouts)); + + for (uint32_t i = 0; i < numLayouts; i++) { + layouts[i] = layoutset->layouts[i]->layout; + } + + VkPipelineLayoutCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 0, 0, + numLayouts, layouts, pushConstants->numRanges, pushConstants->ranges, + }; + + qfv_pipelinelayout_t *layout = malloc (sizeof (layout)); + layout->device = device; + dfunc->vkCreatePipelineLayout (dev, &createInfo, 0, &layout->layout); + return layout; +} + +void +QFV_DestroyPipelineLayout (qfv_pipelinelayout_t *layout) +{ + qfv_device_t *device = layout->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyPipelineLayout (dev, layout->layout, 0); + free (layout); +} + +static VkPipelineShaderStageCreateInfo +shaderStageCI (qfv_shaderstageparams_t params) +{ + VkPipelineShaderStageCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 0, 0, + params.stageFlags, params.module->module, + params.entryPointName, params.specializationInfo, + }; + return createInfo; +} + +static VkPipelineVertexInputStateCreateInfo +vertexInputSCI (qfv_vertexinputstate_t vertexState) +{ + VkPipelineVertexInputStateCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 0, 0, + vertexState.bindings->numBindings, + vertexState.bindings->bindings, + vertexState.attributes->numAttributes, + vertexState.attributes->attributes, + }; + return createInfo; +} + +static VkPipelineInputAssemblyStateCreateInfo +inputAssemblySCI (qfv_pipelineinputassembly_t inputAssemblyState) +{ + VkPipelineInputAssemblyStateCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 0, 0, + inputAssemblyState.topology, + inputAssemblyState.primativeRestartEnable, + }; + return createInfo; +} + +static VkPipelineTessellationStateCreateInfo +tessellationSCI (qfv_pipelinetessellation_t tessellationState) +{ + VkPipelineTessellationStateCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, 0, 0, + tessellationState.patchControlPoints + }; + return createInfo; +} + +static VkPipelineViewportStateCreateInfo +viewportSCI (qfv_viewportinfo_t viewportState) +{ + VkPipelineViewportStateCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 0, 0, + viewportState.viewportset->numViewports, + viewportState.viewportset->viewports, + viewportState.scissorsset->numScissors, + viewportState.scissorsset->scissors, + }; + return createInfo; +} + +static VkPipelineRasterizationStateCreateInfo +rasterizationSCI (qfv_pipelinerasterization_t rasterizationState) +{ + VkPipelineRasterizationStateCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, 0, 0, + rasterizationState.depthClampEnable, + rasterizationState.rasterizerDiscardEnable, + rasterizationState.polygonMode, + rasterizationState.cullMode, + rasterizationState.frontFace, + rasterizationState.depthBiasEnable, + rasterizationState.depthBiasConstantFactor, + rasterizationState.depthBiasClamp, + rasterizationState.depthBiasSlopeFactor, + rasterizationState.lineWidth, + }; + return createInfo; +} + +static VkPipelineMultisampleStateCreateInfo +multisampleSCI (qfv_pipelinemultisample_t multisampleState) +{ + VkPipelineMultisampleStateCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 0, 0, + multisampleState.rasterizationSamples, + multisampleState.sampleShadingEnable, + multisampleState.minSampleShading, + multisampleState.sampleMask, + multisampleState.alphaToCoverageEnable, + multisampleState.alphaToOneEnable, + }; + return createInfo; +} + +static VkPipelineDepthStencilStateCreateInfo +depthStencilSCI (qfv_pipelinedepthandstencil_t depthStencilState) +{ + VkPipelineDepthStencilStateCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, 0, 0, + depthStencilState.depthTestEnable, + depthStencilState.depthWriteEnable, + depthStencilState.depthCompareOp, + depthStencilState.depthBoundsTestEnable, + depthStencilState.stencilTestEnable, + depthStencilState.front, + depthStencilState.back, + depthStencilState.minDepthBounds, + depthStencilState.maxDepthBounds, + }; + return createInfo; +} + +static VkPipelineColorBlendStateCreateInfo +colorBlendSCI (qfv_pipelineblend_t colorBlendState) +{ + VkPipelineColorBlendStateCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 0, 0, + colorBlendState.logicOpEnable, + colorBlendState.logicOp, + colorBlendState.blendAttachments->numAttachments, + colorBlendState.blendAttachments->attachments, + { + colorBlendState.blendConstants[0], + colorBlendState.blendConstants[1], + colorBlendState.blendConstants[2], + colorBlendState.blendConstants[3], + }, + }; + return createInfo; +} + +static VkPipelineDynamicStateCreateInfo +dynamicSCI (qfv_dynamicstateset_t *dynamicState) +{ + VkPipelineDynamicStateCreateInfo createInfo = { + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, 0, 0, + dynamicState->numStates, dynamicState->states, + }; + return createInfo; +} + +qfv_pipelineset_t * +QFV_CreateGraphicsPipelines (qfv_device_t *device, + qfv_pipelinecache_t *cache, + qfv_graphicspipelinecreateinfoset_t *gpciSet) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + uint32_t numPipelines = gpciSet->numPipelines; + uint32_t stageCount = 0; + for (uint32_t i = 0; i < numPipelines; i++) { + stageCount += gpciSet->pipelines[i]->stages->numParams; + } + + size_t blockSize = numPipelines + * (sizeof (VkGraphicsPipelineCreateInfo) + + sizeof (VkPipelineVertexInputStateCreateInfo) + + sizeof (VkPipelineInputAssemblyStateCreateInfo) + + sizeof (VkPipelineTessellationStateCreateInfo) + + sizeof (VkPipelineViewportStateCreateInfo) + + sizeof (VkPipelineRasterizationStateCreateInfo) + + sizeof (VkPipelineMultisampleStateCreateInfo) + + sizeof (VkPipelineDepthStencilStateCreateInfo) + + sizeof (VkPipelineColorBlendStateCreateInfo) + + sizeof (VkPipelineDynamicStateCreateInfo)) + + stageCount * sizeof (VkPipelineShaderStageCreateInfo); + VkGraphicsPipelineCreateInfo *pipelineInfos = malloc (blockSize); + + pipelineInfos->pStages = (void *)(pipelineInfos + numPipelines); + pipelineInfos->pVertexInputState + = (void *)(pipelineInfos->pStages + stageCount); + pipelineInfos->pInputAssemblyState + = (void *)(pipelineInfos->pVertexInputState + numPipelines); + pipelineInfos->pTessellationState + = (void *)(pipelineInfos->pInputAssemblyState + numPipelines); + pipelineInfos->pViewportState + = (void *)(pipelineInfos->pTessellationState + numPipelines); + pipelineInfos->pRasterizationState + = (void *)(pipelineInfos->pViewportState + numPipelines); + pipelineInfos->pMultisampleState + = (void *)(pipelineInfos->pRasterizationState + numPipelines); + pipelineInfos->pDepthStencilState + = (void *)(pipelineInfos->pMultisampleState + numPipelines); + pipelineInfos->pColorBlendState + = (void *)(pipelineInfos->pDepthStencilState + numPipelines); + pipelineInfos->pDynamicState + = (void *)(pipelineInfos->pColorBlendState + numPipelines); + for (uint32_t i = 1; i < gpciSet->numPipelines; i++) { + pipelineInfos[i].pStages = pipelineInfos[i - 1].pStages + + gpciSet->pipelines[i - 1]->stages->numParams; + pipelineInfos[i].pVertexInputState + = pipelineInfos[i - 1].pVertexInputState + 1; + pipelineInfos[i].pInputAssemblyState + = pipelineInfos[i - 1].pInputAssemblyState + 1; + pipelineInfos[i].pTessellationState + = pipelineInfos[i - 1].pTessellationState + 1; + pipelineInfos[i].pViewportState + = pipelineInfos[i - 1].pViewportState + 1; + pipelineInfos[i].pRasterizationState + = pipelineInfos[i - 1].pRasterizationState + 1; + pipelineInfos[i].pMultisampleState + = pipelineInfos[i - 1].pMultisampleState + 1; + pipelineInfos[i].pDepthStencilState + = pipelineInfos[i - 1].pDepthStencilState + 1; + pipelineInfos[i].pColorBlendState + = pipelineInfos[i - 1].pColorBlendState + 1; + pipelineInfos[i].pDynamicState + = pipelineInfos[i - 1].pDynamicState + 1; + } + for (uint32_t i = 0; i < gpciSet->numPipelines; i++) { + VkGraphicsPipelineCreateInfo *gci = pipelineInfos + i; + qfv_graphicspipelinecreateinfo_t *ci = gpciSet->pipelines[i]; + gci->sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + gci->pNext = 0; + gci->flags = ci->flags; + gci->stageCount = ci->stages->numParams; + for (uint32_t j = 0; j < gci->stageCount; j++) { + ((VkPipelineShaderStageCreateInfo *)gci->pStages)[i] = shaderStageCI (ci->stages->params[j]); + } + if (ci->vertexState) { + *(VkPipelineVertexInputStateCreateInfo *)gci->pVertexInputState = vertexInputSCI (*ci->vertexState); + } else { + gci->pVertexInputState = 0; + } + if (ci->inputAssemblyState) { + *(VkPipelineInputAssemblyStateCreateInfo *)gci->pInputAssemblyState = inputAssemblySCI (*ci->inputAssemblyState); + } else { + gci->pInputAssemblyState = 0; + } + if (ci->tessellationState) { + *(VkPipelineTessellationStateCreateInfo *)gci->pTessellationState = tessellationSCI (*ci->tessellationState); + } else { + gci->pTessellationState = 0; + } + if (ci->viewportState) { + *(VkPipelineViewportStateCreateInfo *)gci->pViewportState = viewportSCI (*ci->viewportState); + } else { + gci->pViewportState = 0; + } + if (ci->rasterizationState) { + *(VkPipelineRasterizationStateCreateInfo *)gci->pRasterizationState = rasterizationSCI (*ci->rasterizationState); + } else { + gci->pRasterizationState = 0; + } + if (ci->multisampleState) { + *(VkPipelineMultisampleStateCreateInfo *)gci->pMultisampleState = multisampleSCI (*ci->multisampleState); + } else { + gci->pMultisampleState = 0; + } + if (ci->depthStencilState) { + *(VkPipelineDepthStencilStateCreateInfo *)gci->pDepthStencilState = depthStencilSCI (*ci->depthStencilState); + } else { + gci->pDepthStencilState = 0; + } + if (ci->colorBlendState) { + *(VkPipelineColorBlendStateCreateInfo *)gci->pColorBlendState = colorBlendSCI (*ci->colorBlendState); + } else { + gci->pColorBlendState = 0; + } + if (ci->dynamicState) { + *(VkPipelineDynamicStateCreateInfo *)gci->pDynamicState = dynamicSCI (ci->dynamicState); + } else { + gci->pDynamicState = 0; + } + gci->layout = ci->layout->layout; + gci->renderPass = ci->renderPass->renderPass; + gci->subpass = ci->subpass; + gci->basePipelineHandle = ci->basePipeline->pipeline; + gci->basePipelineIndex = ci->basePipelineIndex; + } + + VkPipeline *pipelines = alloca (numPipelines * sizeof (pipelines)); + dfunc->vkCreateGraphicsPipelines (dev, cache->cache, + numPipelines, pipelineInfos, 0, + pipelines); + + qfv_pipelineset_t *pipelineset = QFV_AllocPipelineSet (numPipelines, malloc); + pipelineset->numPipelines = numPipelines; + for (uint32_t i = 0; i < numPipelines; i++) { + pipelineset->pipelines[i] = malloc (sizeof (qfv_pipeline_t)); + pipelineset->pipelines[i]->device = device; + pipelineset->pipelines[i]->pipeline = pipelines[i]; + } + return pipelineset; +} + +qfv_pipelineset_t * +QFV_CreateComputePipelines (qfv_device_t *device, + qfv_pipelinecache_t *cache, + qfv_computepipelinecreateinfoset_t *cpciSet) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + uint32_t numPipelines = cpciSet->numPipelines; + + size_t blockSize = numPipelines * (sizeof (VkComputePipelineCreateInfo)); + VkComputePipelineCreateInfo *pipelineInfos = malloc (blockSize); + + for (uint32_t i = 0; i < cpciSet->numPipelines; i++) { + VkComputePipelineCreateInfo *cci = pipelineInfos + i; + qfv_computepipelinecreateinfo_t *ci = cpciSet->pipelines[i]; + cci->sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + cci->pNext = 0; + cci->flags = ci->flags; + cci->stage = shaderStageCI (*ci->stage); + cci->layout = ci->layout->layout; + cci->basePipelineHandle = ci->basePipeline->pipeline; + cci->basePipelineIndex = ci->basePipelineIndex; + } + + VkPipeline *pipelines = alloca (numPipelines * sizeof (pipelines)); + dfunc->vkCreateComputePipelines (dev, cache->cache, + numPipelines, pipelineInfos, 0, + pipelines); + + qfv_pipelineset_t *pipelineset = QFV_AllocPipelineSet (numPipelines, malloc); + pipelineset->numPipelines = numPipelines; + for (uint32_t i = 0; i < numPipelines; i++) { + pipelineset->pipelines[i] = malloc (sizeof (qfv_pipeline_t)); + pipelineset->pipelines[i]->device = device; + pipelineset->pipelines[i]->pipeline = pipelines[i]; + } + return pipelineset; +} + +void +QFV_DestroyPipeline (qfv_pipeline_t *pipeline) +{ + qfv_device_t *device = pipeline->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyPipeline (dev, pipeline->pipeline, 0); +} From d56f88f779e9abbf52173a5fc4af48de057eb00c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 14 Feb 2020 11:11:27 +0900 Subject: [PATCH 063/435] Implement swapchain image acquisition --- include/QF/Vulkan/swapchain.h | 5 +++++ libs/video/renderer/vulkan/swapchain.c | 28 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/QF/Vulkan/swapchain.h b/include/QF/Vulkan/swapchain.h index cd9323009..1a9abb896 100644 --- a/include/QF/Vulkan/swapchain.h +++ b/include/QF/Vulkan/swapchain.h @@ -13,5 +13,10 @@ struct vulkan_ctx_s; qfv_swapchain_t *QFV_CreateSwapchain (struct vulkan_ctx_s *ctx, VkSwapchainKHR old_swapchain); void QFV_DestroySwapchain (qfv_swapchain_t *swapchain); +struct qfv_semaphore_s; +struct qfv_fence_s; +int QFV_AcquireNextImage (qfv_swapchain_t *swapchain, + struct qfv_semaphore_s *semaphore, + struct qfv_fence_s *fence, uint32_t *imageIndex); #endif//__QF_Vulkan_swapchain_h diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c index bae8e4ff4..b32e3b3ed 100644 --- a/libs/video/renderer/vulkan/swapchain.c +++ b/libs/video/renderer/vulkan/swapchain.c @@ -11,6 +11,7 @@ #include "QF/sys.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/cvars.h" +#include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/swapchain.h" @@ -157,3 +158,30 @@ QFV_DestroySwapchain (qfv_swapchain_t *swapchain) dfunc->vkDestroySwapchainKHR (dev, swapchain->swapchain, 0); free (swapchain); } + +int +QFV_AcquireNextImage (qfv_swapchain_t *swapchain, qfv_semaphore_t *semaphore, + qfv_fence_t *fence, uint32_t *imageIndex) +{ + qfv_device_t *device = swapchain->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + uint64_t timeout = 2000000000; + VkSemaphore sem = semaphore ? semaphore->semaphore : VK_NULL_HANDLE; + VkFence fnc = fence ? fence->fence : VK_NULL_HANDLE; + *imageIndex = ~0u; + VkResult res = dfunc->vkAcquireNextImageKHR (dev, swapchain->swapchain, + timeout, sem, fnc, + imageIndex); + switch (res) { + case VK_SUCCESS: + case VK_TIMEOUT: + case VK_NOT_READY: + return 1; + case VK_SUBOPTIMAL_KHR: + case VK_ERROR_OUT_OF_DATE_KHR: + return 0; + default: + Sys_Error ("vkAcquireNextImageKHR failed: %d", res); + } +} From 8654ac44bb5736272f8f5e4c85de36d6b61779d0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 14 Feb 2020 16:34:14 +0900 Subject: [PATCH 064/435] Fix incorrect struct forward declaraction --- include/QF/Vulkan/command.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index c1d54d43d..7f28e7c88 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -79,9 +79,9 @@ int QFV_QueueSubmit (struct qfv_queue_s *queue, qfv_semaphoreset_t *signalSemaphores, qfv_fence_t *fence); int QFV_QueueWaitIdle (struct qfv_queue_s *queue); -struct qfv_memorybarrierset_s *memBarriers; -struct qfv_bufferbarrierset_s *buffBarriers; -struct qfv_imagebarrierset_s *imgBarriers; +struct qfv_memorybarrierset_s; +struct qfv_bufferbarrierset_s; +struct qfv_imagebarrierset_s; void QFV_CmdPipelineBarrier (qfv_cmdbuffer_t *cmdBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, From b947cc1791a37e8f483d43d07950cd7c212ce5fd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 16 Feb 2020 22:43:57 +0900 Subject: [PATCH 065/435] Rework command buffer and fence-set management I found command buffer handling to be totally redundant and fence-set management to be a bit awkward. --- include/QF/Vulkan/command.h | 28 ++--- libs/video/renderer/vulkan/command.c | 150 ++++++++++++++------------- 2 files changed, 92 insertions(+), 86 deletions(-) diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index 7f28e7c88..14eb625ac 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -8,13 +8,14 @@ typedef struct qfv_cmdpool_s { typedef struct qfv_cmdbuffer_s { struct qfv_device_s *device; - VkCommandPool cmdpool; - VkCommandBuffer buffer; + VkCommandBuffer *buffer; } qfv_cmdbuffer_t; typedef struct qfv_cmdbufferset_s { struct qfv_device_s *device; - VkCommandBuffer *buffers; + qfv_cmdbuffer_t **buffers; + VkCommandBuffer *vkBuffers; + VkCommandPool cmdpool; int numBuffers; } qfv_cmdbufferset_t; @@ -37,7 +38,8 @@ typedef struct qfv_fence_s { typedef struct qfv_fenceset_s { struct qfv_device_s *device; - VkFence *fences; + qfv_fence_t **fences; + VkFence *vkFences; int numFences; } qfv_fenceset_t; @@ -47,13 +49,9 @@ qfv_cmdpool_t *QFV_CreateCommandPool (struct qfv_device_s *device, int transient, int reset); int QFV_ResetCommandPool (qfv_cmdpool_t *pool, int release); void QFV_DestroyCommandPool (qfv_cmdpool_t *pool); -qfv_cmdbuffer_t *QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, - int secondary, int count); -qfv_cmdbufferset_t *QFV_CreateCommandBufferSet (qfv_cmdbuffer_t **buffers, - int numBuffers); -void QFV_FreeCommandBuffers (qfv_cmdbuffer_t *buffer, int count); -// NOTE: does not destroy buffers -void QFV_DestroyCommandBufferSet (qfv_cmdbufferset_t *buffers); +qfv_cmdbufferset_t *QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, + int secondary, int count); +void QFV_FreeCommandBuffers (qfv_cmdbufferset_t *buffer); int QFV_BeginCommandBuffer (qfv_cmdbuffer_t *buffer, int oneTime, int rpContinue, int simultaneous, VkCommandBufferInheritanceInfo *inheritanceInfo); @@ -70,9 +68,11 @@ qfv_fence_t *QFV_CreateFence (struct qfv_device_s *device, int signaled); qfv_fenceset_t *QFV_CreateFenceSet (qfv_fence_t **fences, int numFences); void QFV_DestroyFence (qfv_fence_t *fence); // NOTE: does not destroy fences -void QFV_DestroyFenceSet (qfv_fenceset_t *fences); -int QFV_WaitForFences (qfv_fenceset_t *fences, int all, uint64_t timeout); -int QFV_ResetFences (qfv_fenceset_t *fences); +void QFV_DestroyFenceSet (qfv_fenceset_t *fenceset); +int QFV_WaitForFences (qfv_fenceset_t *fenceset, int all, uint64_t timeout); +int QFV_WaitForFence (qfv_fence_t *fence, uint64_t timeout); +int QFV_ResetFences (qfv_fenceset_t *fenceset); +int QFV_ResetFence (qfv_fence_t *fence); int QFV_QueueSubmit (struct qfv_queue_s *queue, qfv_semaphoreset_t *waitSemaphores, qfv_cmdbufferset_t *buffers, diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index 09621ede5..9f581ded6 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -115,7 +115,7 @@ QFV_DestroyCommandPool (qfv_cmdpool_t *pool) free (pool); } -qfv_cmdbuffer_t * +qfv_cmdbufferset_t * QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count) { qfv_device_t *device = pool->device; @@ -129,54 +129,34 @@ QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count) VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, pool->cmdpool, level, count }; - qfv_cmdbuffer_t *cmdbuffers = malloc (count * sizeof (*cmdbuffers)); - VkCommandBuffer *buffers = alloca (count * sizeof (*buffers)); - dfunc->vkAllocateCommandBuffers (dev, &allocInfo, buffers); + qfv_cmdbufferset_t *cmdbufferset; + cmdbufferset = malloc (sizeof (qfv_cmdbufferset_t) + + count * sizeof (qfv_buffer_t *) + + count * sizeof (qfv_buffer_t) + + count * sizeof (VkCommandBuffer)); + cmdbufferset->buffers = (qfv_cmdbuffer_t **) (cmdbufferset + 1); + cmdbufferset->vkBuffers = (VkCommandBuffer *) (cmdbufferset->buffers + + count); + cmdbufferset->cmdpool = pool->cmdpool; + cmdbufferset->numBuffers = count; + dfunc->vkAllocateCommandBuffers (dev, &allocInfo, cmdbufferset->vkBuffers); for (int i = 0; i < count; i++) { - cmdbuffers[i].device = device; - cmdbuffers[i].cmdpool = pool->cmdpool; - cmdbuffers[i].buffer = buffers[i]; + cmdbufferset->buffers[i]->device = device; + cmdbufferset->buffers[i]->buffer = &cmdbufferset->vkBuffers[i]; } - return cmdbuffers; + return cmdbufferset; } -qfv_cmdbufferset_t * -QFV_CreateCommandBufferSet (qfv_cmdbuffer_t **buffers, int numBuffers) +void QFV_FreeCommandBuffers (qfv_cmdbufferset_t *bufferset) { - qfv_device_t *device = buffers[0]->device; - qfv_cmdbufferset_t *bufferset = malloc (sizeof (*bufferset) - + sizeof (VkCommandBuffer) - * numBuffers); - - bufferset->device = device; - bufferset->buffers = (VkCommandBuffer *) (bufferset + 1); - bufferset->numBuffers = numBuffers; - - for (int i = 0; i < numBuffers; i++) { - bufferset->buffers[i] = buffers[i]->buffer; - } - return bufferset; -} - -void QFV_FreeCommandBuffers (qfv_cmdbuffer_t *buffer, int count) -{ - qfv_device_t *device = buffer->device; + qfv_device_t *device = bufferset->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - VkCommandBuffer *buffers = alloca (sizeof (*buffers) * count); - for (int i = 0; i < count; i++) { - buffers[i] = buffer[i].buffer; - } - - dfunc->vkFreeCommandBuffers (dev, buffer->cmdpool, count, buffers); - free (buffer); -} - -void -QFV_DestroyCommandBufferSet (qfv_cmdbufferset_t *buffers) -{ - free (buffers); + dfunc->vkFreeCommandBuffers (dev, bufferset->cmdpool, + bufferset->numBuffers, + bufferset->vkBuffers); + free (bufferset); } int @@ -186,7 +166,7 @@ QFV_BeginCommandBuffer (qfv_cmdbuffer_t *buffer, int oneTime, int rpContinue, { qfv_device_t *device = buffer->device; qfv_devfuncs_t *dfunc = device->funcs; - VkCommandBuffer buff = buffer->buffer; + VkCommandBuffer buff = *buffer->buffer; VkCommandBufferUsageFlags usage = 0; if (oneTime) { @@ -213,7 +193,7 @@ QFV_EndCommandBuffer (qfv_cmdbuffer_t *buffer) { qfv_device_t *device = buffer->device; qfv_devfuncs_t *dfunc = device->funcs; - VkCommandBuffer buff = buffer->buffer; + VkCommandBuffer buff = *buffer->buffer; return dfunc->vkEndCommandBuffer (buff) == VK_SUCCESS; } @@ -223,7 +203,7 @@ QFV_ResetCommandBuffer (qfv_cmdbuffer_t *buffer, int release) { qfv_device_t *device = buffer->device; qfv_devfuncs_t *dfunc = device->funcs; - VkCommandBuffer buff = buffer->buffer; + VkCommandBuffer buff = *buffer->buffer; VkCommandBufferResetFlags release_flag = 0; if (release) { @@ -310,16 +290,20 @@ QFV_CreateFence (qfv_device_t *device, int signaled) qfv_fenceset_t * QFV_CreateFenceSet (qfv_fence_t **fences, int numFences) { - qfv_device_t *device = fences[0]->device; qfv_fenceset_t *fenceset = malloc (sizeof (*fenceset) + + sizeof (qfv_fence_t) * numFences + sizeof (VkFence) * numFences); - fenceset->device = device; - fenceset->fences = (VkFence *) (fenceset + 1); + fenceset->fences = (qfv_fence_t **) (fenceset + 1); + fenceset->vkFences = (VkFence *) (fenceset->fences + numFences); fenceset->numFences = numFences; - for (int i = 0; i < numFences; i++) { - fenceset->fences[i] = fences[i]->fence; + if (fences) { + fenceset->device = fences[0]->device; + for (int i = 0; i < numFences; i++) { + fenceset->fences[i] = fences[i]; + fenceset->vkFences[i] = fences[i]->fence; + } } return fenceset; } @@ -336,32 +320,53 @@ QFV_DestroyFence (qfv_fence_t *fence) } void -QFV_DestroyFenceSet (qfv_fenceset_t *fences) +QFV_DestroyFenceSet (qfv_fenceset_t *fenceset) { - free (fences); + free (fenceset); } int -QFV_WaitForFences (qfv_fenceset_t *fences, int all, uint64_t timeout) +QFV_WaitForFences (qfv_fenceset_t *fenceset, int all, uint64_t timeout) { - qfv_device_t *device = fences->device; + qfv_device_t *device = fenceset->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - VkResult res = dfunc->vkWaitForFences (dev, fences->numFences, - fences->fences, all, timeout); + VkResult res = dfunc->vkWaitForFences (dev, fenceset->numFences, + fenceset->vkFences, all, timeout); return res == VK_SUCCESS; } int -QFV_ResetFences (qfv_fenceset_t *fences) +QFV_WaitForFence (qfv_fence_t *fence, uint64_t timeout) { - qfv_device_t *device = fences->device; + qfv_device_t *device = fence->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - return dfunc->vkResetFences (dev, fences->numFences, - fences->fences) == VK_SUCCESS; + VkResult res = dfunc->vkWaitForFences (dev, 1, &fence->fence, 1, timeout); + return res == VK_SUCCESS; +} + +int +QFV_ResetFences (qfv_fenceset_t *fenceset) +{ + qfv_device_t *device = fenceset->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + return dfunc->vkResetFences (dev, fenceset->numFences, + fenceset->vkFences) == VK_SUCCESS; +} + +int +QFV_ResetFence (qfv_fence_t *fence) +{ + qfv_device_t *device = fence->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + return dfunc->vkResetFences (dev, 1, &fence->fence) == VK_SUCCESS; } int @@ -375,7 +380,7 @@ QFV_QueueSubmit (qfv_queue_t *queue, qfv_semaphoreset_t *waitSemaphores, VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, waitSemaphores->numSemaphores, waitSemaphores->semaphores, waitSemaphores->stages, - buffers->numBuffers, buffers->buffers, + buffers->numBuffers, buffers->vkBuffers, signalSemaphores->numSemaphores, signalSemaphores->semaphores }; @@ -418,11 +423,11 @@ QFV_CmdPipelineBarrier (qfv_cmdbuffer_t *cmdBuffer, numImgBarriers = imgBarrierSet->numBarriers; imgBarriers = imgBarrierSet->barriers; } - dfunc->vkCmdPipelineBarrier (cmdBuffer->buffer, - srcStageMask, dstStageMask, dependencyFlags, - numMemBarriers, memBarriers, - numBuffBarriers, buffBarriers, - numImgBarriers, imgBarriers); + dfunc->vkCmdPipelineBarrier (*cmdBuffer->buffer, + srcStageMask, dstStageMask, dependencyFlags, + numMemBarriers, memBarriers, + numBuffBarriers, buffBarriers, + numImgBarriers, imgBarriers); } void @@ -433,7 +438,7 @@ QFV_CmdCopyBuffer (qfv_cmdbuffer_t *cmdBuffer, qfv_device_t *device = cmdBuffer->device; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkCmdCopyBuffer (cmdBuffer->buffer, src->buffer, dst->buffer, + dfunc->vkCmdCopyBuffer (*cmdBuffer->buffer, src->buffer, dst->buffer, numRegions, regions); } @@ -447,7 +452,7 @@ QFV_CmdCopyBufferToImage (qfv_cmdbuffer_t *cmdBuffer, qfv_device_t *device = cmdBuffer->device; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkCmdCopyBufferToImage (cmdBuffer->buffer, src->buffer, dst->image, + dfunc->vkCmdCopyBufferToImage (*cmdBuffer->buffer, src->buffer, dst->image, layout, numRegions, regions); } @@ -461,7 +466,7 @@ QFV_CmdCopyImageToBuffer (qfv_cmdbuffer_t *cmdBuffer, qfv_device_t *device = cmdBuffer->device; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkCmdCopyImageToBuffer (cmdBuffer->buffer, src->image, layout, + dfunc->vkCmdCopyImageToBuffer (*cmdBuffer->buffer, src->image, layout, dst->buffer, numRegions, regions); } @@ -483,7 +488,7 @@ QFV_CmdBeginRenderPass (qfv_cmdbuffer_t *cmdBuffer, numClearValues, clearValues, }; - dfunc->vkCmdBeginRenderPass (cmdBuffer->buffer, &beginInfo, + dfunc->vkCmdBeginRenderPass (*cmdBuffer->buffer, &beginInfo, subpassContents); } @@ -494,7 +499,7 @@ QFV_CmdNextSubpass (qfv_cmdbuffer_t *cmdBuffer, qfv_device_t *device = cmdBuffer->device; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkCmdNextSubpass (cmdBuffer->buffer, subpassContents); + dfunc->vkCmdNextSubpass (*cmdBuffer->buffer, subpassContents); } void @@ -503,7 +508,7 @@ QFV_CmdEndRenderPass (qfv_cmdbuffer_t *cmdBuffer) qfv_device_t *device = cmdBuffer->device; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkCmdEndRenderPass (cmdBuffer->buffer); + dfunc->vkCmdEndRenderPass (*cmdBuffer->buffer); } void @@ -514,5 +519,6 @@ QFV_CmdBindPipeline (qfv_cmdbuffer_t *cmdBuffer, qfv_device_t *device = cmdBuffer->device; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkCmdBindPipeline (cmdBuffer->buffer, bindPoint, pipeline->pipeline); + dfunc->vkCmdBindPipeline (*cmdBuffer->buffer, bindPoint, + pipeline->pipeline); } From 559bd2e636778e0721212a730285972bb0a70e42 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 16 Feb 2020 22:45:27 +0900 Subject: [PATCH 066/435] Create command pool and frame timing fences Nothing is actually done yet, so the reported fps is around 172k (yes, k), but startup and shutdown seems to be clean (yay validation layers). --- include/vid_vulkan.h | 11 +++ libs/video/renderer/vid_render_vulkan.c | 114 +++++++++++++++++------- 2 files changed, 92 insertions(+), 33 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 9cfb3ad8a..cd1964ff7 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -6,6 +6,13 @@ #endif #include +typedef struct vulkan_frameset_s { + int curFrame; // index into fences + int curImage; // index into cmdBuffers and swapchain images + struct qfv_fenceset_s *fences; + struct qfv_cmdbufferset_s *cmdBuffers; +} vulkan_frameset_t; + typedef struct vulkan_ctx_s { void (*load_vulkan) (struct vulkan_ctx_s *ctx); void (*unload_vulkan) (struct vulkan_ctx_s *ctx); @@ -23,6 +30,10 @@ typedef struct vulkan_ctx_s { struct qfv_device_s *device; struct qfv_swapchain_s *swapchain; VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain + + struct qfv_cmdpool_s *cmdpool; + vulkan_frameset_t frameset; + #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; #include "QF/Vulkan/funclist.h" diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 7fce05272..0699ced5c 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -28,8 +28,10 @@ # include "config.h" #endif -#define NH_DEFINE -#include "vulkan/namehack.h" +#include + +//#define NH_DEFINE +//#include "vulkan/namehack.h" #include "QF/sys.h" @@ -37,6 +39,7 @@ #include "QF/plugin/vid_render.h" #include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/swapchain.h" @@ -53,8 +56,43 @@ static vulkan_ctx_t *vulkan_ctx; static void vulkan_R_Init (void) { - if (vulkan_ctx) - Sys_Quit (); + Vulkan_CreateSwapchain (vulkan_ctx); + Sys_Printf ("R_Init %p %d", vulkan_ctx->swapchain->swapchain, + vulkan_ctx->swapchain->numImages); + for (int32_t i = 0; i < vulkan_ctx->swapchain->numImages; i++) { + Sys_Printf (" %p", vulkan_ctx->swapchain->images[i]); + } + Sys_Printf ("\n"); +} + +static void +vulkan_SCR_UpdateScreen (double time, void (*f)(void), void (**g)(void)) +{ + static int count = 0; + static double startTime; + + if (++count >= 100) { + double currenTime = Sys_DoubleTime (); + double time = currenTime - startTime; + startTime = currenTime; + printf ("%d frames in %g s: %g fps \r", count, time, count / time); + fflush (stdout); + count = 0; + } +} + +static qpic_t * +vulkan_Draw_CachePic (const char *path, qboolean alpha) +{ + return 0; +} + +static qpic_t qpic = { 1, 1, {0} }; + +static qpic_t * +vulkan_Draw_MakePic (int width, int height, const byte *data) +{ + return &qpic; } static vid_model_funcs_t model_funcs = { @@ -84,29 +122,29 @@ static vid_model_funcs_t model_funcs = { }; vid_render_funcs_t vulkan_vid_render_funcs = { - vulkan_Draw_Init, - vulkan_Draw_Character, - vulkan_Draw_String, - vulkan_Draw_nString, - vulkan_Draw_AltString, - vulkan_Draw_ConsoleBackground, - vulkan_Draw_Crosshair, - vulkan_Draw_CrosshairAt, - vulkan_Draw_TileClear, - vulkan_Draw_Fill, - vulkan_Draw_TextBox, - vulkan_Draw_FadeScreen, - vulkan_Draw_BlendScreen, + 0,//vulkan_Draw_Init, + 0,//vulkan_Draw_Character, + 0,//vulkan_Draw_String, + 0,//vulkan_Draw_nString, + 0,//vulkan_Draw_AltString, + 0,//vulkan_Draw_ConsoleBackground, + 0,//vulkan_Draw_Crosshair, + 0,//vulkan_Draw_CrosshairAt, + 0,//vulkan_Draw_TileClear, + 0,//vulkan_Draw_Fill, + 0,//vulkan_Draw_TextBox, + 0,//vulkan_Draw_FadeScreen, + 0,//vulkan_Draw_BlendScreen, vulkan_Draw_CachePic, - vulkan_Draw_UncachePic, + 0,//vulkan_Draw_UncachePic, vulkan_Draw_MakePic, - vulkan_Draw_DestroyPic, - vulkan_Draw_PicFromWad, - vulkan_Draw_Pic, - vulkan_Draw_Picf, - vulkan_Draw_SubPic, + 0,//vulkan_Draw_DestroyPic, + 0,//vulkan_Draw_PicFromWad, + 0,//vulkan_Draw_Pic, + 0,//vulkan_Draw_Picf, + 0,//vulkan_Draw_SubPic, - 0,//vulkan_SCR_UpdateScreen, + vulkan_SCR_UpdateScreen, SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, @@ -152,8 +190,13 @@ vulkan_vid_render_choose_visual (void) { Vulkan_CreateDevice (vulkan_ctx); vulkan_ctx->choose_visual (vulkan_ctx); - Sys_Printf ("vk choose visual %p %p\n", vulkan_ctx->device->dev, - vulkan_ctx->device->queue.queue); + vulkan_ctx->cmdpool = QFV_CreateCommandPool (vulkan_ctx->device, + vulkan_ctx->device->queue.queueFamily, + 0, 0); + Sys_Printf ("vk choose visual %p %p %d %p\n", vulkan_ctx->device->dev, + vulkan_ctx->device->queue.queue, + vulkan_ctx->device->queue.queueFamily, + vulkan_ctx->cmdpool->cmdpool); } static void @@ -161,14 +204,14 @@ vulkan_vid_render_create_context (void) { vulkan_ctx->create_window (vulkan_ctx); vulkan_ctx->surface = vulkan_ctx->create_surface (vulkan_ctx); - Sys_Printf ("vk create context %p\n", vulkan_ctx->surface); - Vulkan_CreateSwapchain (vulkan_ctx); - Sys_Printf ("%p %d", vulkan_ctx->swapchain->swapchain, - vulkan_ctx->swapchain->numImages); - for (int32_t i = 0; i < vulkan_ctx->swapchain->numImages; i++) { - Sys_Printf (" %p", vulkan_ctx->swapchain->images[i]); + vulkan_ctx->frameset.curFrame = 0; + vulkan_ctx->frameset.curImage = -1; // not acquired yet + qfv_fence_t **fences = alloca (2 * sizeof (*fences)); + for (int i = 0; i < 2; i++) { + fences[i]= QFV_CreateFence (vulkan_ctx->device, 1); } - Sys_Printf ("\n"); + vulkan_ctx->frameset.fences = QFV_CreateFenceSet (fences, 2); + Sys_Printf ("vk create context %p\n", vulkan_ctx->surface); } static void @@ -190,6 +233,11 @@ vulkan_vid_render_init (void) static void vulkan_vid_render_shutdown (void) { + for (int i = 0; i < vulkan_ctx->frameset.fences->numFences; i++) { + QFV_DestroyFence (vulkan_ctx->frameset.fences->fences[i]); + } + QFV_DestroyFenceSet (vulkan_ctx->frameset.fences); + QFV_DestroyCommandPool (vulkan_ctx->cmdpool); Vulkan_Shutdown_Common (vulkan_ctx); } From 4b152a4492b500dc06a7c85c48b3cf4d1f61c464 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 00:10:32 +0900 Subject: [PATCH 067/435] Rework semaphore sets --- include/QF/Vulkan/command.h | 3 ++- libs/video/renderer/vulkan/command.c | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index 14eb625ac..7ef36a7f4 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -26,7 +26,8 @@ typedef struct qfv_semaphore_s { typedef struct qfv_semaphoreset_s { struct qfv_device_s *device; - VkSemaphore *semaphores; + qfv_semaphore_t **semaphores; + VkSemaphore *vkSemaphores; VkPipelineStageFlags *stages; int numSemaphores; } qfv_semaphoreset_t; diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index 9f581ded6..f4cf4bc14 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -237,17 +237,23 @@ QFV_CreateSemaphoreSet (qfv_semaphore_t **semaphores, int numSemaphores) qfv_device_t *device = semaphores[0]->device; qfv_semaphoreset_t *semaphoreset; semaphoreset = calloc (1, sizeof (*semaphoreset) + + sizeof (qfv_semaphore_t *) * numSemaphores + sizeof (VkSemaphore) * numSemaphores + sizeof (VkPipelineStageFlags) * numSemaphores); semaphoreset->device = device; - semaphoreset->semaphores = (VkSemaphore *) (semaphoreset + 1); + semaphoreset->vkSemaphores = (VkSemaphore *) (semaphoreset + 1); semaphoreset->stages = (VkPipelineStageFlags *) - &semaphoreset->semaphores[numSemaphores]; + &semaphoreset->vkSemaphores[numSemaphores]; + semaphoreset->semaphores = (qfv_semaphore_t **) (semaphoreset->stages + + numSemaphores); semaphoreset->numSemaphores = numSemaphores; - for (int i = 0; i < numSemaphores; i++) { - semaphoreset->semaphores[i] = semaphores[i]->semaphore; + if (semaphores) { + for (int i = 0; i < numSemaphores; i++) { + semaphoreset->semaphores[i] = semaphores[i]; + semaphoreset->vkSemaphores[i] = semaphores[i]->semaphore; + } } return semaphoreset; } @@ -379,10 +385,10 @@ QFV_QueueSubmit (qfv_queue_t *queue, qfv_semaphoreset_t *waitSemaphores, VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, waitSemaphores->numSemaphores, - waitSemaphores->semaphores, waitSemaphores->stages, + waitSemaphores->vkSemaphores, waitSemaphores->stages, buffers->numBuffers, buffers->vkBuffers, signalSemaphores->numSemaphores, - signalSemaphores->semaphores + signalSemaphores->vkSemaphores }; //FIXME multi-batch return dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, From ce72135e70776d9efe82838f87b5de97049991af Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 00:10:59 +0900 Subject: [PATCH 068/435] Fix incorrect init of command buffer set --- libs/video/renderer/vulkan/command.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index f4cf4bc14..fa671fa5d 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -137,12 +137,15 @@ QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count) cmdbufferset->buffers = (qfv_cmdbuffer_t **) (cmdbufferset + 1); cmdbufferset->vkBuffers = (VkCommandBuffer *) (cmdbufferset->buffers + count); + qfv_cmdbuffer_t *buffer = (qfv_cmdbuffer_t *) (cmdbufferset->vkBuffers + + count); cmdbufferset->cmdpool = pool->cmdpool; cmdbufferset->numBuffers = count; dfunc->vkAllocateCommandBuffers (dev, &allocInfo, cmdbufferset->vkBuffers); for (int i = 0; i < count; i++) { - cmdbufferset->buffers[i]->device = device; - cmdbufferset->buffers[i]->buffer = &cmdbufferset->vkBuffers[i]; + buffer->device = device; + buffer->buffer = &cmdbufferset->vkBuffers[i]; + cmdbufferset->buffers[i] = buffer++; } return cmdbufferset; } From 916e57de3741a7baf9706e74e608c968dbee1491 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 00:50:39 +0900 Subject: [PATCH 069/435] Get the swapchain image switching sort of working The render pass isn't set up yet, so the validation layer is having a fit, but cycling through the swapchain images does seem to be working. --- include/vid_vulkan.h | 3 +- libs/video/renderer/vid_render_vulkan.c | 59 +++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index cd1964ff7..5b9a31daf 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -8,9 +8,10 @@ typedef struct vulkan_frameset_s { int curFrame; // index into fences - int curImage; // index into cmdBuffers and swapchain images struct qfv_fenceset_s *fences; struct qfv_cmdbufferset_s *cmdBuffers; + struct qfv_semaphoreset_s *imageSemaphores; + struct qfv_semaphoreset_s *renderDoneSemaphores; } vulkan_frameset_t; typedef struct vulkan_ctx_s { diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 0699ced5c..de0917310 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -56,7 +56,15 @@ static vulkan_ctx_t *vulkan_ctx; static void vulkan_R_Init (void) { + qfv_cmdbufferset_t *cmdBuffers; Vulkan_CreateSwapchain (vulkan_ctx); + cmdBuffers = QFV_AllocateCommandBuffers (vulkan_ctx->cmdpool, 0, + vulkan_ctx->swapchain->numImages); + vulkan_ctx->frameset.cmdBuffers = cmdBuffers; + for (int i = 0; i < cmdBuffers->numBuffers; i++) { + QFV_BeginCommandBuffer (cmdBuffers->buffers[i], 0, 0, 0, 0); + QFV_EndCommandBuffer (cmdBuffers->buffers[i]); + } Sys_Printf ("R_Init %p %d", vulkan_ctx->swapchain->swapchain, vulkan_ctx->swapchain->numImages); for (int32_t i = 0; i < vulkan_ctx->swapchain->numImages; i++) { @@ -70,6 +78,40 @@ vulkan_SCR_UpdateScreen (double time, void (*f)(void), void (**g)(void)) { static int count = 0; static double startTime; + uint32_t imageIndex = 0; + qfv_devfuncs_t *dfunc = vulkan_ctx->device->funcs; + qfv_queue_t *queue = &vulkan_ctx->device->queue; + vulkan_frameset_t *frameset = &vulkan_ctx->frameset; + + QFV_WaitForFence (frameset->fences->fences[frameset->curFrame], + 2000000000); + QFV_AcquireNextImage (vulkan_ctx->swapchain, + frameset->imageSemaphores->semaphores[frameset->curFrame], + 0, &imageIndex); + + VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, + 1, + &frameset->imageSemaphores->vkSemaphores[frameset->curFrame], + &waitStage, + 1, &frameset->cmdBuffers->vkBuffers[imageIndex], + 1, &frameset->renderDoneSemaphores->vkSemaphores[frameset->curFrame], + }; + QFV_ResetFence (frameset->fences->fences[frameset->curFrame]); + dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, + frameset->fences->vkFences[frameset->curFrame]); + + VkPresentInfoKHR presentInfo = { + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 0, + 1, &frameset->renderDoneSemaphores->vkSemaphores[frameset->curFrame], + 1, &vulkan_ctx->swapchain->swapchain, &imageIndex, + 0 + }; + dfunc->vkQueuePresentKHR (queue->queue, &presentInfo); + + frameset->curFrame++; + frameset->curFrame %= frameset->fences->numFences; if (++count >= 100) { double currenTime = Sys_DoubleTime (); @@ -205,12 +247,19 @@ vulkan_vid_render_create_context (void) vulkan_ctx->create_window (vulkan_ctx); vulkan_ctx->surface = vulkan_ctx->create_surface (vulkan_ctx); vulkan_ctx->frameset.curFrame = 0; - vulkan_ctx->frameset.curImage = -1; // not acquired yet qfv_fence_t **fences = alloca (2 * sizeof (*fences)); + qfv_semaphore_t **imageSems = alloca (2 * sizeof (*imageSems)); + qfv_semaphore_t **renderDoneSems = alloca (2 * sizeof (*renderDoneSems)); for (int i = 0; i < 2; i++) { fences[i]= QFV_CreateFence (vulkan_ctx->device, 1); + imageSems[i] = QFV_CreateSemaphore (vulkan_ctx->device); + renderDoneSems[i] = QFV_CreateSemaphore (vulkan_ctx->device); } vulkan_ctx->frameset.fences = QFV_CreateFenceSet (fences, 2); + vulkan_ctx->frameset.imageSemaphores + = QFV_CreateSemaphoreSet (imageSems, 2); + vulkan_ctx->frameset.renderDoneSemaphores + = QFV_CreateSemaphoreSet (renderDoneSems, 2); Sys_Printf ("vk create context %p\n", vulkan_ctx->surface); } @@ -233,8 +282,12 @@ vulkan_vid_render_init (void) static void vulkan_vid_render_shutdown (void) { - for (int i = 0; i < vulkan_ctx->frameset.fences->numFences; i++) { - QFV_DestroyFence (vulkan_ctx->frameset.fences->fences[i]); + QFV_DeviceWaitIdle (vulkan_ctx->device); + vulkan_frameset_t *frameset = &vulkan_ctx->frameset; + for (int i = 0; i < frameset->fences->numFences; i++) { + QFV_DestroyFence (frameset->fences->fences[i]); + QFV_DestroySemaphore (frameset->imageSemaphores->semaphores[i]); + QFV_DestroySemaphore (frameset->renderDoneSemaphores->semaphores[i]); } QFV_DestroyFenceSet (vulkan_ctx->frameset.fences); QFV_DestroyCommandPool (vulkan_ctx->cmdpool); From e37aba364a6bd71b5252480f6f7663c5457daea5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 12:58:23 +0900 Subject: [PATCH 070/435] Correct an apparent typo Black makes much more sense than Slack, especially if the text is from a quake mod (no idea where, though). --- libs/util/test/test-plist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/util/test/test-plist.c b/libs/util/test/test-plist.c index 20ab1e94e..0335493f2 100644 --- a/libs/util/test/test-plist.c +++ b/libs/util/test/test-plist.c @@ -11,7 +11,7 @@ static const char *test_strings[] = { "of the Shadow cult.\n\n" "For years the Shadow Gate existed in\n" "obscurity but after the cult discovered\n" - "the \3023\354\341\343\353\240\307\341\364\345 in the caves below\n" + "the \302\354\341\343\353\240\307\341\364\345 in the caves below\n" "the empire took notice.\n" "A batallion of Imperial Knights were\n" "sent to the gate to destroy the cult\n" From 0cb04dc49028990091a083332a016394caa556b2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 16:17:21 +0900 Subject: [PATCH 071/435] Add a set of macros for dynamic arrays Includes docs and test cases. --- include/QF/darray.h | 301 +++++++++++++++++++++++++++++++++++ libs/util/test/Makefile.am | 8 +- libs/util/test/test-darray.c | 213 +++++++++++++++++++++++++ 3 files changed, 520 insertions(+), 2 deletions(-) create mode 100644 include/QF/darray.h create mode 100644 libs/util/test/test-darray.c diff --git a/include/QF/darray.h b/include/QF/darray.h new file mode 100644 index 000000000..88792715f --- /dev/null +++ b/include/QF/darray.h @@ -0,0 +1,301 @@ +/* + darray.h + + Dynamic arrays + + Copyright (C) 2020 Bill Currie + + Author: Bill Currie + Date: 2020/02/17 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __pr_type_h +#define __pr_type_h + +/** \defgroup darray Dynamic Arrays + \ingroup utils + + Dynamic array container object +*/ +///@{ + +/** The structure defs for a dynamic array with elements of the given type. + + This is just the defs of a struct delcaration: it is useless on its own. + The intended usage is something like: + + typedef struct dynamic_array_s DARRAY_TYPE(int) dynamic_array_t; + + This allows full flexibility in just how the actual type is used. + + The \a size field is the number of elements currently in the array, and + the \a maxSize field is the number of elements the array can hold without + being resized. + + The \a grow field specifies the number of elements by which \a maxSize is + to grow when the array needs to be resized. Setting this to 0 prevents + resizing and any attempt to do so is a fatal error. + + \param ele_type The type to use for the element array, which is accessed + by the \a a field. + \hideinitializer +*/ +#define DARRAY_TYPE(ele_type) \ + { \ + size_t size; \ + size_t maxSize; \ + size_t grow; \ + ele_type *a; \ + } + +/** Clear the array. + + If the array can grow, its backing will be freed and maxSize and a reset, + otherwise maxSize and a are left untouched. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \hideinitializer +*/ +#define DARRAY_CLEAR(array) \ + do { \ + __auto_type ar = (array); \ + free (ar->a); \ + ar->size = 0; \ + if (ar->grow) { \ + ar->maxSize = 0; \ + ar->a = 0; \ + } \ + } while (0) + +/** Set the size of the array. + + If the new size is greater than maxSize, and the array can grow (grow is + non-zero), then maxSize will be increased to the smallest multiple of grow + greater than or equal to size (ie, maxSize >= size, maxSize % grow == 0). + + Attempting to increase maxSize on an array that cannot grow is an error: + it is assumed that the array struct does not own the backing memory. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param newSize The new size of the array: newly opened slots are + uninitialized, but old slots retain their values. + \hideinitializer +*/ +#define DARRAY_RESIZE(array, newSize) \ + do { \ + __auto_type ar = (array); \ + size_t ns = (newSize); \ + if (__builtin_expect (ns > ar->maxSize, 0)) { \ + if (__builtin_expect (!ar->grow, 0)) { \ + Sys_Error ("Attempt to grow fixed-size darray: %s:%d", \ + __FILE__, __LINE__); \ + } \ + ar->maxSize = ar->grow * ((ns + ar->grow - 1) / ar->grow); \ + ar->a = realloc (ar->a, ar->maxSize * sizeof (*ar->a)); \ + if (__builtin_expect (!ar->a, 0)) { \ + Sys_Error ("failed to realloc darray: %s:%d", \ + __FILE__, __LINE__); \ + } \ + } \ + ar->size = ns; \ + } while (0) + +/** Append a value to the end of the array. + + The array is grown by one and the value written to the newly opened slot. + + If the new array size is greater than maxSize and the array can be grown, + the array backing will be resized to the next multiple of grow. + + Attempting to grow an array that cannot grow is an error: it is assumed + that the array struct does not own the backing memory. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param value The value to be appended to the array. Must be of a type + compatible with that used for creating the array struct. + \return The appended value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_APPEND(array, value) \ + ({ \ + __auto_type ar = (array); \ + __auto_type ob = (value); \ + size_t sz = ar->size; \ + DARRAY_RESIZE (ar, ar->size + 1); \ + ar->a[sz] = ob; \ + }) + +/** Open a hole in the array for bulk copying of data. + + The array is grown by the requested size, opening a hole at the specified + index. Values beyond the index are copied to just after the newly opened + hole. + + If the new array size is greater than maxSize and the array can be grown, + the array backing will be resized to the next multiple of grow. + + Attempting to grow an array that cannot grow is an error: it is assumed + that the array struct does not own the backing memory. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param index The index at which the hole will begin. + \param space The sized of the hole to be opened, in array elements. + \return The *address* of the newly opened hole: can be passed to + memcpy and friends. + + memcpy (DARRAY_OPEN_AT(array, index, size), data, + size * sizeof (*data)); + \hideinitializer +*/ +#define DARRAY_OPEN_AT(array, index, space) \ + ({ \ + __auto_type ar = (array); \ + size_t po = (index); \ + size_t sp = (space); \ + if (__builtin_expect (po > ar->size, 0)) { \ + Sys_Error ("Attempt to insert elements outside darray: " \ + "%s:%d", __FILE__, __LINE__); \ + } \ + DARRAY_RESIZE (ar, ar->size + sp); \ + memmove (&ar->a[po + sp], &ar->a[po], \ + (ar->size - po) * sizeof (*ar->a)); \ + &ar->a[po]; \ + }) + +/** Insert a value into the array at the specified index. + + The array is grown by one at the specified index and the value written + to the newly opened slot. Values beyond the index are copied to just + after the newly opened slot. + + If the new array size is greater than maxSize and the array can be grown, + the array backing will be resized to the next multiple of grow. + + Attempting to grow an array that cannot grow is an error: it is assumed + that the array struct does not own the backing memory. + + Attempting to insert a value beyond one past the end of the array is an + error (inserting at index = size is valid). + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param value The value to be inserted into the array. Must be of a type + compatible with that used for creating the array struct. + \param index The index at which the value will be inserted + \return The inserted value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_INSERT_AT(array, value, index) \ + ({ \ + __auto_type ar = (array); \ + __auto_type ob = (value); \ + *DARRAY_OPEN_AT (ar, index, 1) = ob; \ + }) + +/** Close a segment of an array. + + The values beyond the segment are copied to the beginning of the segment + and the array size reduced by the size of the segment. All but the first + one of the values previously in the segment are lost and gone forever. + + Attempting to close a segment that extends outside the array is an error. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param index The index of the beginning of the segment. + \param count The number of values in the segment. + \return The single value at the beginning of the segment: can be + assigned to another compatible value. + \hideinitializer +*/ +#define DARRAY_CLOSE_AT(array, index, count) \ + ({ \ + __auto_type ar = (array); \ + size_t po = (index); \ + size_t co = (count); \ + if (__builtin_expect (po + co > ar->size \ + || po >= ar->size, 0)) { \ + Sys_Error ("Attempt to remove elements outside darray: " \ + "%s:%d", __FILE__, __LINE__); \ + } \ + __auto_type ob = ar->a[po]; \ + memmove (&ar->a[po], &ar->a[po + co], \ + (ar->size - po - co) * sizeof (ob)); \ + ar->size -= co; \ + ob; \ + }) + +/** Remove a value from an array at the specified index. + + The values beyond the index are moved down to fill the hole left by the + single value and the array size reduced by one. + + Attempting to remove a value from beyond the array is an error. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param index The index of the value to be removed. + \return The removed value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_REMOVE_AT(array, index) \ + ({ \ + __auto_type ar = (array); \ + DARRAY_CLOSE_AT (ar, index, 1); \ + }) + +/** Remove (pop) a value from the end of an array. + + The size of the array size reduced by one. + + Attempting to remove a value from an empty array is an error. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \return The removed value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_REMOVE(array) \ + ({ \ + __auto_type ar = (array); \ + DARRAY_CLOSE_AT (ar, ar->size - 1, 1); \ + }) + +///@} + +#endif//__pr_type_h diff --git a/libs/util/test/Makefile.am b/libs/util/test/Makefile.am index a7bdb5d4e..f6dd4115a 100644 --- a/libs/util/test/Makefile.am +++ b/libs/util/test/Makefile.am @@ -3,8 +3,8 @@ AUTOMAKE_OPTIONS= foreign AM_CPPFLAGS= -I$(top_srcdir)/include check_PROGRAMS= \ - test-bary test-cs test-dq test-half test-mat3 test-mat4 test-plist \ - test-qfs test-quat test-seb test-seg test-set test-vrect + test-bary test-cs test-darray test-dq test-half test-mat3 test-mat4 \ + test-plist test-qfs test-quat test-seb test-seg test-set test-vrect test_bary_SOURCES=test-bary.c test_bary_LDADD=$(top_builddir)/libs/util/libQFutil.la @@ -14,6 +14,10 @@ test_cs_SOURCES=test-cs.c test_cs_LDADD=$(top_builddir)/libs/util/libQFutil.la test_cs_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la +test_darray_SOURCES=test-darray.c +test_darray_LDADD=$(top_builddir)/libs/util/libQFutil.la +test_darray_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la + test_dq_SOURCES=test-dq.c test_dq_LDADD=$(top_builddir)/libs/util/libQFutil.la test_dq_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la diff --git a/libs/util/test/test-darray.c b/libs/util/test/test-darray.c new file mode 100644 index 000000000..59dbad0ab --- /dev/null +++ b/libs/util/test/test-darray.c @@ -0,0 +1,213 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#define remove remove_renamed +#include +#include +#include + +#include "QF/darray.h" +#include "QF/sys.h" +#undef remove + +typedef int (*test_func) (int a, int b); +typedef struct intarray_s DARRAY_TYPE(int) intarray_t; + +intarray_t intarray = {0, 0, 16, 0}; + +static int +append (int val, int b) +{ + return DARRAY_APPEND (&intarray, val); +} + +static int +check_size (int a, int b) +{ + return intarray.size; +} + +static int +check_maxSize (int a, int b) +{ + return intarray.maxSize; +} + +static int +check_grow (int a, int b) +{ + return intarray.grow; +} + +static int +check_maxSizeGrowth (int a, int b) +{ + return intarray.maxSize % intarray.grow; +} + +static int +check_array (int a, int b) +{ + return !!intarray.a; +} + +static int +check_value (int index, int b) +{ + if ((size_t) index >= intarray.size) { + Sys_Error ("indexing beyond array"); + } + return intarray.a[index]; +} + +static int +insert_at (int val, int pos) +{ + return DARRAY_INSERT_AT (&intarray, val, pos); +} + +static int +open_at (int pos, int size) +{ + return DARRAY_OPEN_AT (&intarray, pos, size) - intarray.a; +} + +static const char text[] = "Aloy is an awesome huntress."; +static int +open_at2 (int pos, int size) +{ + memcpy(DARRAY_OPEN_AT (&intarray, pos, size), text, size * sizeof (int)); + return strcmp((char*) (intarray.a + pos), text); +} + +static int +remove_at (int pos, int b) +{ + return DARRAY_REMOVE_AT (&intarray, pos); +} + +static int +remove (int pos, int b) +{ + return DARRAY_REMOVE (&intarray); +} + +static int +close_at (int pos, int size) +{ + return DARRAY_CLOSE_AT (&intarray, pos, size); +} + +static int +clear (int a, int b) +{ + DARRAY_CLEAR (&intarray); + return 0; +} + +static int +resize (int size, int b) +{ + DARRAY_RESIZE (&intarray, size); + return 0; +} + +struct { + test_func test; + int param1, param2; + int test_expect; +} tests[] = { + {check_size, 0, 0, 0}, // confirm array empty but can grow + {check_maxSize, 0, 0, 0}, + {check_grow, 0, 0, 16}, + {check_array, 0, 0, 0}, + {append, 5, 0, 5}, // test first append to emtpty array + {check_size, 0, 0, 1}, + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 16}, + {check_array, 0, 0, 1}, + {check_value, 0, 0, 5}, + {append, 42, 0, 42}, // test a second append + {check_size, 0, 0, 2}, + {check_maxSize, 0, 0, 16}, + {check_value, 0, 0, 5}, + {check_value, 1, 0, 42}, + {insert_at, 69, 1, 69}, // test insertions + {insert_at, 96, 0, 96}, + {check_size, 0, 0, 4}, + {check_maxSize, 0, 0, 16}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 5}, + {check_value, 2, 0, 69}, + {check_value, 3, 0, 42}, + {open_at, 2, 14, 2}, // test opening a large hole + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 18}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 5}, + {check_value, 16, 0, 69}, + {check_value, 17, 0, 42}, + {close_at, 1, 15, 5}, // test block removal + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 3}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 69}, + {check_value, 2, 0, 42}, + {remove, 0, 0, 42}, // test "pop" + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 2}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 69}, + {remove_at, 0, 0, 96}, // test remove at + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 1}, + {check_value, 0, 0, 69}, + {insert_at, 71, 1, 71}, // test insertion at end + {resize, 48, 0, 0}, // test resize bigger + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 48}, + {check_size, 0, 0, 48}, + {check_value, 0, 0, 69}, + {check_value, 1, 0, 71}, + {resize, 24, 0, 0}, // test resize smaller + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 48}, + {check_size, 0, 0, 24}, + {check_value, 0, 0, 69}, + {check_value, 1, 0, 71}, + {open_at2, 1, (sizeof (text) + sizeof (int) - 1) / sizeof (int), 0}, + {check_value, 0, 0, 69}, + {check_value, 1, 0, 0x796f6c41}, + {check_value, 9, 0, 71}, + {clear, 0, 0, 0}, // test clearing + {check_size, 0, 0, 0}, + {check_maxSize, 0, 0, 0}, + {check_array, 0, 0, 0}, +}; +#define num_tests (sizeof (tests) / sizeof (tests[0])) +int test_start_line = __LINE__ - num_tests - 2; + +int +main (int argc, const char **argv) +{ + int res = 0; + + size_t i; + + for (i = 0; i < num_tests; i++) { + if (tests[i].test) { + int test_res; + test_res = tests[i].test (tests[i].param1, tests[i].param2); + if (test_res != tests[i].test_expect) { + res |= 1; + printf ("test %d (line %d) failed\n", (int) i, + (int) i + test_start_line); + printf ("expect: %d\n", tests[i].test_expect); + printf ("got : %d\n", test_res); + continue; + } + } + } + return res; +} From cb70dc7212e176929d43efab5b37e791aaa15ef0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 16:40:12 +0900 Subject: [PATCH 072/435] Fix incorrect include protection --- include/QF/Makefile.am | 2 +- include/QF/darray.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/QF/Makefile.am b/include/QF/Makefile.am index 8bf956359..aa9eaf1f8 100644 --- a/include/QF/Makefile.am +++ b/include/QF/Makefile.am @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = foreign pkgincludedir = $(includedir)/QF nobase_pkginclude_HEADERS = \ alloc.h bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \ - console.h crc.h csqc.h cvar.h dstring.h draw.h gib.h hash.h hl.h \ + console.h crc.h csqc.h cvar.h darray.h dstring.h draw.h gib.h hash.h hl.h \ idparse.h image.h in_event.h info.h input.h iqm.h joystick.h keys.h \ link.h llist.h locs.h mathlib.h mdfour.h mersenne.h model.h modelgen.h \ msg.h object.h pak.h pakfile.h pcx.h png.h plugin.h pr_comp.h pr_debug.h \ diff --git a/include/QF/darray.h b/include/QF/darray.h index 88792715f..0287f958f 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -28,8 +28,8 @@ */ -#ifndef __pr_type_h -#define __pr_type_h +#ifndef __darray_h +#define __darray_h /** \defgroup darray Dynamic Arrays \ingroup utils @@ -298,4 +298,4 @@ ///@} -#endif//__pr_type_h +#endif//__darray_h From 65890dd2fb12e6751bb747221364ed9234f6b543 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 20:27:43 +0900 Subject: [PATCH 073/435] Add a fixed-array allocator Turned out to be very convenient. --- include/QF/darray.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/QF/darray.h b/include/QF/darray.h index 0287f958f..7a4484575 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -67,6 +67,27 @@ ele_type *a; \ } +/** Allocate a fixed-size array using the given allocator + + The allocated array is initilized to be ungrowable, and with both size + and maxSize set to the given size. + + \param array_type Expression acceptable by typeof for determining the + type of the array. + \param array_size The size of the array. + \param alloc Allocator compatible with malloc (eg, alloca). +*/ +#define DARRAY_ALLOCFIXED(array_type, array_size, alloc) \ + ({ \ + __auto_type s = (array_size); \ + typeof (array_type) *ar = alloc (sizeof(*ar) \ + + s * sizeof (*ar->a)); \ + ar->size = ar->maxSize = s; \ + ar->grow = 0; \ + ar->a = (typeof (ar->a)) (ar + 1); \ + ar; \ + }) + /** Clear the array. If the array can grow, its backing will be freed and maxSize and a reset, From 94565c23820960d106c33bff4d25161596ac9470 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 20:29:35 +0900 Subject: [PATCH 074/435] Rework much of the Vulkan array handling So much for all those little wrappers hiding the device. Some survived, but mostly just the bigger things like device, swapchain, etc. --- include/QF/Vulkan/buffer.h | 62 ++-- include/QF/Vulkan/command.h | 125 +------- include/QF/Vulkan/device.h | 5 + include/QF/Vulkan/funclist.h | 1 + include/QF/Vulkan/image.h | 62 ++-- include/QF/Vulkan/instance.h | 2 + include/QF/Vulkan/memory.h | 19 +- include/QF/Vulkan/renderpass.h | 2 +- include/QF/Vulkan/swapchain.h | 10 +- include/vid_vulkan.h | 2 +- libs/video/renderer/vid_render_vulkan.c | 83 ++--- libs/video/renderer/vulkan/buffer.c | 101 ++---- libs/video/renderer/vulkan/command.c | 410 ++---------------------- libs/video/renderer/vulkan/device.c | 21 ++ libs/video/renderer/vulkan/image.c | 118 ++----- libs/video/renderer/vulkan/instance.c | 2 + libs/video/renderer/vulkan/memory.c | 42 +-- libs/video/renderer/vulkan/renderpass.c | 10 +- libs/video/renderer/vulkan/swapchain.c | 42 ++- 19 files changed, 282 insertions(+), 837 deletions(-) diff --git a/include/QF/Vulkan/buffer.h b/include/QF/Vulkan/buffer.h index ef11ae8b7..9346d0466 100644 --- a/include/QF/Vulkan/buffer.h +++ b/include/QF/Vulkan/buffer.h @@ -1,57 +1,43 @@ #ifndef __QF_Vulkan_buffer_h #define __QF_Vulkan_buffer_h -typedef struct qfv_buffer_s { - struct qfv_device_s *device; - VkBuffer buffer; -} qfv_buffer_t; +#include "QF/darray.h" typedef struct qfv_buffertransition_s { - qfv_buffer_t *buffer; + VkBuffer buffer; VkAccessFlags srcAccess; VkAccessFlags dstAccess; - uint32_t srcQueueFamily; - uint32_t dstQueueFamily; - VkDeviceSize offset; - VkDeviceSize size; -} qfv_buffertransition_t; - -typedef struct qfv_bufferbarrierset_s { - struct qfv_device_s *device; - uint32_t numBarriers; - VkBufferMemoryBarrier *barriers; -} qfv_bufferbarrierset_t; - -typedef struct qfv_bufferview_s { - struct qfv_device_s *device; - VkBufferView view; - qfv_buffer_t *buffer; - VkFormat format; + uint32_t srcQueueFamily; + uint32_t dstQueueFamily; VkDeviceSize offset; VkDeviceSize size; -} qfv_bufferview_t; +} qfv_buffertransition_t; + +typedef struct qfv_buffertransitionset_s + DARRAY_TYPE (qfv_buffertransition_t) qfv_buffertransitionset_t; +typedef struct qfv_bufferbarrierset_s + DARRAY_TYPE (VkBufferMemoryBarrier) qfv_bufferbarrierset_t; struct qfv_device_s; -qfv_buffer_t *QFV_CreateBuffer (struct qfv_device_s *device, - VkDeviceSize size, - VkBufferUsageFlags usage); +VkBuffer QFV_CreateBuffer (struct qfv_device_s *device, + VkDeviceSize size, + VkBufferUsageFlags usage); -struct qfv_memory_s *QFV_AllocBufferMemory (qfv_buffer_t *buffer, - VkMemoryPropertyFlags properties, - VkDeviceSize size, VkDeviceSize offset); +VkDeviceMemory QFV_AllocBufferMemory (struct qfv_device_s *device, + VkBuffer buffer, + VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset); -int QFV_BindBufferMemory (qfv_buffer_t *buffer, struct qfv_memory_s *memory, +int QFV_BindBufferMemory (struct qfv_device_s *device, + VkBuffer buffer, VkDeviceMemory object, VkDeviceSize offset); qfv_bufferbarrierset_t * -QFV_CreateBufferTransitionSet (qfv_buffertransition_t **transitions, - int numTransitions); +QFV_CreateBufferTransitions (qfv_buffertransition_t *transitions, + int numTransitions); -qfv_bufferview_t *QFV_CreateBufferView (qfv_buffer_t *buffer, VkFormat format, - VkDeviceSize offset, VkDeviceSize size); - -void QFV_DestroyBufferView (qfv_bufferview_t *view); - -void QFV_DestroyBuffer (qfv_buffer_t *buffer); +VkBufferView QFV_CreateBufferView (struct qfv_device_s *device, + VkBuffer buffer, VkFormat format, + VkDeviceSize offset, VkDeviceSize size); #endif//__QF_Vulkan_buffer_h diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index 7ef36a7f4..046c8b2b3 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -1,128 +1,33 @@ #ifndef __QF_Vulkan_command_h #define __QF_Vulkan_command_h -typedef struct qfv_cmdpool_s { - struct qfv_device_s *device; - VkCommandPool cmdpool; -} qfv_cmdpool_t; +#include "QF/darray.h" -typedef struct qfv_cmdbuffer_s { - struct qfv_device_s *device; - VkCommandBuffer *buffer; -} qfv_cmdbuffer_t; +typedef struct qfv_cmdbufferset_s + DARRAY_TYPE (VkCommandBuffer) qfv_cmdbufferset_t; -typedef struct qfv_cmdbufferset_s { - struct qfv_device_s *device; - qfv_cmdbuffer_t **buffers; - VkCommandBuffer *vkBuffers; - VkCommandPool cmdpool; - int numBuffers; -} qfv_cmdbufferset_t; +typedef struct qfv_semaphoreset_s + DARRAY_TYPE (VkSemaphore) qfv_semaphoreset_t; -typedef struct qfv_semaphore_s { - struct qfv_device_s *device; - VkSemaphore semaphore; -} qfv_semaphore_t; - -typedef struct qfv_semaphoreset_s { - struct qfv_device_s *device; - qfv_semaphore_t **semaphores; - VkSemaphore *vkSemaphores; - VkPipelineStageFlags *stages; - int numSemaphores; -} qfv_semaphoreset_t; - -typedef struct qfv_fence_s { - struct qfv_device_s *device; - VkFence fence; -} qfv_fence_t; - -typedef struct qfv_fenceset_s { - struct qfv_device_s *device; - qfv_fence_t **fences; - VkFence *vkFences; - int numFences; -} qfv_fenceset_t; +typedef struct qfv_fenceset_s + DARRAY_TYPE (VkFence) qfv_fenceset_t; struct qfv_queue_s; -qfv_cmdpool_t *QFV_CreateCommandPool (struct qfv_device_s *device, +struct qfv_device_s; +VkCommandPool QFV_CreateCommandPool (struct qfv_device_s *device, uint32_t queueFamily, int transient, int reset); -int QFV_ResetCommandPool (qfv_cmdpool_t *pool, int release); -void QFV_DestroyCommandPool (qfv_cmdpool_t *pool); -qfv_cmdbufferset_t *QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, +qfv_cmdbufferset_t *QFV_AllocateCommandBuffers (struct qfv_device_s *device, + VkCommandPool pool, int secondary, int count); -void QFV_FreeCommandBuffers (qfv_cmdbufferset_t *buffer); -int QFV_BeginCommandBuffer (qfv_cmdbuffer_t *buffer, int oneTime, - int rpContinue, int simultaneous, - VkCommandBufferInheritanceInfo *inheritanceInfo); -int QFV_EndCommandBuffer (qfv_cmdbuffer_t *buffer); -int QFV_ResetCommandBuffer (qfv_cmdbuffer_t *buffer, int release); -qfv_semaphore_t *QFV_CreateSemaphore (struct qfv_device_s *device); -qfv_semaphoreset_t *QFV_CreateSemaphoreSet (qfv_semaphore_t **semaphores, - int numSemaphores); -void QFV_DestroySemaphore (qfv_semaphore_t *semaphore); -// NOTE: does not destroy semaphores -void QFV_DestroySemaphoreSet (qfv_semaphoreset_t *semaphores); -qfv_fence_t *QFV_CreateFence (struct qfv_device_s *device, int signaled); -qfv_fenceset_t *QFV_CreateFenceSet (qfv_fence_t **fences, int numFences); -void QFV_DestroyFence (qfv_fence_t *fence); -// NOTE: does not destroy fences -void QFV_DestroyFenceSet (qfv_fenceset_t *fenceset); -int QFV_WaitForFences (qfv_fenceset_t *fenceset, int all, uint64_t timeout); -int QFV_WaitForFence (qfv_fence_t *fence, uint64_t timeout); -int QFV_ResetFences (qfv_fenceset_t *fenceset); -int QFV_ResetFence (qfv_fence_t *fence); +VkSemaphore QFV_CreateSemaphore (struct qfv_device_s *device); +VkFence QFV_CreateFence (struct qfv_device_s *device, int signaled); int QFV_QueueSubmit (struct qfv_queue_s *queue, qfv_semaphoreset_t *waitSemaphores, + VkPipelineStageFlags *stages, qfv_cmdbufferset_t *buffers, - qfv_semaphoreset_t *signalSemaphores, qfv_fence_t *fence); + qfv_semaphoreset_t *signalSemaphores, VkFence fence); int QFV_QueueWaitIdle (struct qfv_queue_s *queue); -struct qfv_memorybarrierset_s; -struct qfv_bufferbarrierset_s; -struct qfv_imagebarrierset_s; -void QFV_CmdPipelineBarrier (qfv_cmdbuffer_t *cmdBuffer, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - VkDependencyFlags dependencyFlags, - struct qfv_memorybarrierset_s *memBarriers, - struct qfv_bufferbarrierset_s *buffBarriers, - struct qfv_imagebarrierset_s *imgBarriers); - -struct qfv_buffer_s; -struct qfv_image_s; -struct qfv_renderpass_s; -struct qfv_framebuffer_s; -void QFV_CmdCopyBuffer (qfv_cmdbuffer_t *cmdBuffer, - struct qfv_buffer_s *src, struct qfv_buffer_s *dst, - VkBufferCopy *regions, uint32_t numRegions); -void QFV_CmdCopyBufferToImage (qfv_cmdbuffer_t *cmdBuffer, - struct qfv_buffer_s *src, - struct qfv_image_s *dst, - VkImageLayout layout, - VkBufferImageCopy *regions, - uint32_t numRegions); -void QFV_CmdCopyImageToBuffer (qfv_cmdbuffer_t *cmdBuffer, - struct qfv_image_s *src, - VkImageLayout layout, - struct qfv_buffer_s *dst, - VkBufferImageCopy *regions, - uint32_t numRegions); -void QFV_CmdBeginRenderPass (qfv_cmdbuffer_t *cmdBuffer, - struct qfv_renderpass_s *renderPass, - struct qfv_framebuffer_s *framebuffer, - VkRect2D renderArea, - uint32_t numClearValues, - VkClearValue *clearValues, - VkSubpassContents subpassContents); -void QFV_CmdNextSubpass (qfv_cmdbuffer_t *cmdBuffer, - VkSubpassContents subpassContents); -void QFV_CmdEndRenderPass (qfv_cmdbuffer_t *cmdBuffer); -struct qfv_pipeline_s; -void QFV_CmdBindPipeline (qfv_cmdbuffer_t *cmdBuffer, - VkPipelineBindPoint bindPoint, - struct qfv_pipeline_s *pipeline); - #endif//__QF_Vulkan_command_h diff --git a/include/QF/Vulkan/device.h b/include/QF/Vulkan/device.h index c05b2ba7e..2ebc7b1d9 100644 --- a/include/QF/Vulkan/device.h +++ b/include/QF/Vulkan/device.h @@ -31,4 +31,9 @@ qfv_device_t *QFV_CreateDevice (struct vulkan_ctx_s *ctx, void QFV_DestroyDevice (qfv_device_t *device); int QFV_DeviceWaitIdle (qfv_device_t *device); +VkFormat QFV_FindSupportedFormat (qfv_device_t *device, VkImageTiling tiling, + VkFormatFeatureFlags features, + int numCandidates, + const VkFormat *candidates); + #endif//__QF_Vulkan_device_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 5bacf29eb..426b0fa62 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -31,6 +31,7 @@ INSTANCE_LEVEL_VULKAN_FUNCTION (vkDestroyInstance) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceLayerProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumerateDeviceExtensionProperties) INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceMemoryProperties) +INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceFormatProperties) #undef INSTANCE_LEVEL_VULKAN_FUNCTION diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index 4258fe2e0..8db6ee632 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -1,13 +1,13 @@ #ifndef __QF_Vulkan_image_h #define __QF_Vulkan_image_h -typedef struct qfv_image_s { - struct qfv_device_s *device; - VkImage image; -} qfv_image_t; +#include "QF/darray.h" + +typedef struct qfv_imageset_s DARRAY_TYPE (VkImage) qfv_imageset_t; +typedef struct qfv_imageviewset_s DARRAY_TYPE (VkImageView) qfv_imageviewset_t; typedef struct qfv_imagetransition_s { - qfv_image_t *image; + VkImage image; VkAccessFlags srcAccess; VkAccessFlags dstAccess; VkImageLayout oldLayout; @@ -17,48 +17,32 @@ typedef struct qfv_imagetransition_s { VkImageAspectFlags aspect; } qfv_imagetransition_t; -typedef struct qfv_imagebarrierset_s { - struct qfv_device_s *device; - uint32_t numBarriers; - VkImageMemoryBarrier *barriers; -} qfv_imagebarrierset_t; - -typedef struct qfv_imageview_s { - struct qfv_device_s *device; - VkImageView view; - qfv_image_t *image; - VkImageViewType type; - VkFormat format; - VkImageAspectFlags aspect; -} qfv_imageview_t; +typedef struct qfv_imagetransitionset_s + DARRAY_TYPE (qfv_imagetransition_t) qfv_imagetransitionset_t; +typedef struct qfv_imagebarrierset_s + DARRAY_TYPE (VkImageMemoryBarrier) qfv_imagebarrierset_t; struct qfv_device_s; -qfv_image_t *QFV_CreateImage (struct qfv_device_s *device, int cubemap, - VkImageType type, - VkFormat format, - VkExtent3D size, - uint32_t num_mipmaps, - uint32_t num_layers, - VkSampleCountFlagBits samples, - VkImageUsageFlags usage_scenarios); +VkImage QFV_CreateImage (struct qfv_device_s *device, int cubemap, + VkImageType type, + VkFormat format, + VkExtent3D size, + uint32_t num_mipmaps, + uint32_t num_layers, + VkSampleCountFlagBits samples, + VkImageUsageFlags usage_scenarios); -struct qfv_memory_s *QFV_AllocImageMemory (qfv_image_t *image, +VkDeviceMemory QFV_AllocImageMemory (struct qfv_device_s *device, + VkImage image, VkMemoryPropertyFlags properties, VkDeviceSize size, VkDeviceSize offset); -int QFV_BindImageMemory (qfv_image_t *image, struct qfv_memory_s *memory, - VkDeviceSize offset); - qfv_imagebarrierset_t * -QFV_CreateImageTransitionSet (qfv_imagetransition_t **transitions, +QFV_CreateImageTransitionSet (qfv_imagetransition_t *transitions, int numTransitions); -qfv_imageview_t *QFV_CreateImageView (qfv_image_t *image, VkImageViewType type, - VkFormat format, - VkImageAspectFlags aspect); - -void QFV_DestroyImageView (qfv_imageview_t *view); - -void QFV_DestroyImage (qfv_image_t *image); +VkImageView QFV_CreateImageView (struct qfv_device_s *device, + VkImage image, VkImageViewType type, + VkFormat format, VkImageAspectFlags aspect); #endif//__QF_Vulkan_image_h diff --git a/include/QF/Vulkan/instance.h b/include/QF/Vulkan/instance.h index 6c393d140..0cf5b2226 100644 --- a/include/QF/Vulkan/instance.h +++ b/include/QF/Vulkan/instance.h @@ -37,7 +37,9 @@ typedef struct qfv_instfuncs_s { } qfv_instfuncs_t; typedef struct qfv_physdev_s { + struct qfv_instance_s *instance; VkPhysicalDevice dev; + VkPhysicalDeviceProperties properties; VkPhysicalDeviceMemoryProperties memory_properties; } qfv_physdev_t; diff --git a/include/QF/Vulkan/memory.h b/include/QF/Vulkan/memory.h index 55b87f6c6..91885d31b 100644 --- a/include/QF/Vulkan/memory.h +++ b/include/QF/Vulkan/memory.h @@ -1,21 +1,22 @@ #ifndef __QF_Vulkan_memory_h #define __QF_Vulkan_memory_h -typedef struct qfv_memory_s { - struct qfv_device_s *device; - VkDeviceMemory object; -} qfv_memory_t; +#include "QF/darray.h" typedef struct qfv_mappedmemrange_s { - qfv_memory_t *memory; + VkDeviceMemory object; VkDeviceSize offset; VkDeviceSize size; } qfv_mappedmemrange_t; -void QFV_FreeMemory (qfv_memory_t *memory); -void *QFV_MapMemory (qfv_memory_t *memory, +typedef struct qfv_mappedmemrangeset_s + DARRAY_TYPE (qfv_mappedmemrange_t) qfv_mappedmemrangeset_t; + +struct qfv_device_s; + +void *QFV_MapMemory (struct qfv_device_s *device, VkDeviceMemory object, VkDeviceSize offset, VkDeviceSize size); -void QFV_UnmapMemory (qfv_memory_t *memory); -void QFV_FlushMemory (qfv_mappedmemrange_t *ranges, uint32_t numRanges); +void QFV_FlushMemory (struct qfv_device_s *device, + qfv_mappedmemrangeset_t *ranges); #endif//__QF_Vulkan_memory_h diff --git a/include/QF/Vulkan/renderpass.h b/include/QF/Vulkan/renderpass.h index c8fdc2965..3dd4acc63 100644 --- a/include/QF/Vulkan/renderpass.h +++ b/include/QF/Vulkan/renderpass.h @@ -63,7 +63,7 @@ struct qfv_imageview_s; qfv_framebuffer_t * QFV_CreateFramebuffer (qfv_renderpass_t *renderPass, uint32_t numAttachments, - struct qfv_imageview_s **attachments, + VkImageView *attachments, uint32_t width, uint32_t height, uint32_t layers); void QFV_DestroyFramebuffer (qfv_framebuffer_t *framebuffer); diff --git a/include/QF/Vulkan/swapchain.h b/include/QF/Vulkan/swapchain.h index 1a9abb896..9d04b35e4 100644 --- a/include/QF/Vulkan/swapchain.h +++ b/include/QF/Vulkan/swapchain.h @@ -5,8 +5,11 @@ typedef struct qfv_swapchain_s { struct qfv_device_s *device; VkSurfaceKHR surface; VkSwapchainKHR swapchain; + VkFormat format; + VkExtent2D extent; int32_t numImages; - VkImage *images; + struct qfv_imageset_s *images; + struct qfv_imageviewset_s *imageViews; } qfv_swapchain_t; struct vulkan_ctx_s; @@ -15,8 +18,7 @@ qfv_swapchain_t *QFV_CreateSwapchain (struct vulkan_ctx_s *ctx, void QFV_DestroySwapchain (qfv_swapchain_t *swapchain); struct qfv_semaphore_s; struct qfv_fence_s; -int QFV_AcquireNextImage (qfv_swapchain_t *swapchain, - struct qfv_semaphore_s *semaphore, - struct qfv_fence_s *fence, uint32_t *imageIndex); +int QFV_AcquireNextImage (qfv_swapchain_t *swapchain, VkSemaphore semaphore, + VkFence fence, uint32_t *imageIndex); #endif//__QF_Vulkan_swapchain_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 5b9a31daf..77718ab9c 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -32,7 +32,7 @@ typedef struct vulkan_ctx_s { struct qfv_swapchain_s *swapchain; VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain - struct qfv_cmdpool_s *cmdpool; + VkCommandPool cmdpool; vulkan_frameset_t frameset; #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index de0917310..0373867de 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -33,6 +33,7 @@ //#define NH_DEFINE //#include "vulkan/namehack.h" +#include "QF/darray.h" #include "QF/sys.h" #include "QF/plugin/general.h" @@ -41,6 +42,7 @@ #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/swapchain.h" @@ -56,19 +58,24 @@ static vulkan_ctx_t *vulkan_ctx; static void vulkan_R_Init (void) { + qfv_device_t *device = vulkan_ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; qfv_cmdbufferset_t *cmdBuffers; + Vulkan_CreateSwapchain (vulkan_ctx); - cmdBuffers = QFV_AllocateCommandBuffers (vulkan_ctx->cmdpool, 0, + cmdBuffers = QFV_AllocateCommandBuffers (device, vulkan_ctx->cmdpool, 0, vulkan_ctx->swapchain->numImages); vulkan_ctx->frameset.cmdBuffers = cmdBuffers; - for (int i = 0; i < cmdBuffers->numBuffers; i++) { - QFV_BeginCommandBuffer (cmdBuffers->buffers[i], 0, 0, 0, 0); - QFV_EndCommandBuffer (cmdBuffers->buffers[i]); + VkCommandBufferBeginInfo beginInfo + = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + for (size_t i = 0; i < cmdBuffers->size; i++) { + dfunc->vkBeginCommandBuffer (cmdBuffers->a[i], &beginInfo); + dfunc->vkEndCommandBuffer (cmdBuffers->a[i]); } Sys_Printf ("R_Init %p %d", vulkan_ctx->swapchain->swapchain, vulkan_ctx->swapchain->numImages); for (int32_t i = 0; i < vulkan_ctx->swapchain->numImages; i++) { - Sys_Printf (" %p", vulkan_ctx->swapchain->images[i]); + Sys_Printf (" %p", vulkan_ctx->swapchain->images->a[i]); } Sys_Printf ("\n"); } @@ -79,39 +86,42 @@ vulkan_SCR_UpdateScreen (double time, void (*f)(void), void (**g)(void)) static int count = 0; static double startTime; uint32_t imageIndex = 0; - qfv_devfuncs_t *dfunc = vulkan_ctx->device->funcs; + qfv_device_t *device = vulkan_ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + VkDevice dev = device->dev; qfv_queue_t *queue = &vulkan_ctx->device->queue; vulkan_frameset_t *frameset = &vulkan_ctx->frameset; - QFV_WaitForFence (frameset->fences->fences[frameset->curFrame], - 2000000000); + dfunc->vkWaitForFences (dev, 1, & frameset->fences->a[frameset->curFrame], + VK_TRUE, 2000000000); QFV_AcquireNextImage (vulkan_ctx->swapchain, - frameset->imageSemaphores->semaphores[frameset->curFrame], + frameset->imageSemaphores->a[frameset->curFrame], 0, &imageIndex); - VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkPipelineStageFlags waitStage + = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, 1, - &frameset->imageSemaphores->vkSemaphores[frameset->curFrame], + &frameset->imageSemaphores->a[frameset->curFrame], &waitStage, - 1, &frameset->cmdBuffers->vkBuffers[imageIndex], - 1, &frameset->renderDoneSemaphores->vkSemaphores[frameset->curFrame], + 1, &frameset->cmdBuffers->a[imageIndex], + 1, &frameset->renderDoneSemaphores->a[frameset->curFrame], }; - QFV_ResetFence (frameset->fences->fences[frameset->curFrame]); + dfunc->vkResetFences (dev, 1, &frameset->fences->a[frameset->curFrame]); dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, - frameset->fences->vkFences[frameset->curFrame]); + frameset->fences->a[frameset->curFrame]); VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 0, - 1, &frameset->renderDoneSemaphores->vkSemaphores[frameset->curFrame], + 1, &frameset->renderDoneSemaphores->a[frameset->curFrame], 1, &vulkan_ctx->swapchain->swapchain, &imageIndex, 0 }; dfunc->vkQueuePresentKHR (queue->queue, &presentInfo); frameset->curFrame++; - frameset->curFrame %= frameset->fences->numFences; + frameset->curFrame %= frameset->fences->size; if (++count >= 100) { double currenTime = Sys_DoubleTime (); @@ -238,7 +248,7 @@ vulkan_vid_render_choose_visual (void) Sys_Printf ("vk choose visual %p %p %d %p\n", vulkan_ctx->device->dev, vulkan_ctx->device->queue.queue, vulkan_ctx->device->queue.queueFamily, - vulkan_ctx->cmdpool->cmdpool); + vulkan_ctx->cmdpool); } static void @@ -247,19 +257,18 @@ vulkan_vid_render_create_context (void) vulkan_ctx->create_window (vulkan_ctx); vulkan_ctx->surface = vulkan_ctx->create_surface (vulkan_ctx); vulkan_ctx->frameset.curFrame = 0; - qfv_fence_t **fences = alloca (2 * sizeof (*fences)); - qfv_semaphore_t **imageSems = alloca (2 * sizeof (*imageSems)); - qfv_semaphore_t **renderDoneSems = alloca (2 * sizeof (*renderDoneSems)); + qfv_fenceset_t *fences = DARRAY_ALLOCFIXED (*fences, 2, malloc); + qfv_semaphoreset_t *imageSems = DARRAY_ALLOCFIXED (*imageSems, 2, malloc); + qfv_semaphoreset_t *renderDoneSems = DARRAY_ALLOCFIXED (*renderDoneSems, 2, + malloc); for (int i = 0; i < 2; i++) { - fences[i]= QFV_CreateFence (vulkan_ctx->device, 1); - imageSems[i] = QFV_CreateSemaphore (vulkan_ctx->device); - renderDoneSems[i] = QFV_CreateSemaphore (vulkan_ctx->device); + fences->a[i]= QFV_CreateFence (vulkan_ctx->device, 1); + imageSems->a[i] = QFV_CreateSemaphore (vulkan_ctx->device); + renderDoneSems->a[i] = QFV_CreateSemaphore (vulkan_ctx->device); } - vulkan_ctx->frameset.fences = QFV_CreateFenceSet (fences, 2); - vulkan_ctx->frameset.imageSemaphores - = QFV_CreateSemaphoreSet (imageSems, 2); - vulkan_ctx->frameset.renderDoneSemaphores - = QFV_CreateSemaphoreSet (renderDoneSems, 2); + vulkan_ctx->frameset.fences = fences; + vulkan_ctx->frameset.imageSemaphores = imageSems; + vulkan_ctx->frameset.renderDoneSemaphores = renderDoneSems; Sys_Printf ("vk create context %p\n", vulkan_ctx->surface); } @@ -282,15 +291,17 @@ vulkan_vid_render_init (void) static void vulkan_vid_render_shutdown (void) { - QFV_DeviceWaitIdle (vulkan_ctx->device); + qfv_device_t *device = vulkan_ctx->device; + qfv_devfuncs_t *df = device->funcs; + VkDevice dev = device->dev; + QFV_DeviceWaitIdle (device); vulkan_frameset_t *frameset = &vulkan_ctx->frameset; - for (int i = 0; i < frameset->fences->numFences; i++) { - QFV_DestroyFence (frameset->fences->fences[i]); - QFV_DestroySemaphore (frameset->imageSemaphores->semaphores[i]); - QFV_DestroySemaphore (frameset->renderDoneSemaphores->semaphores[i]); + for (size_t i = 0; i < frameset->fences->size; i++) { + df->vkDestroyFence (dev, frameset->fences->a[i], 0); + df->vkDestroySemaphore (dev, frameset->imageSemaphores->a[i], 0); + df->vkDestroySemaphore (dev, frameset->renderDoneSemaphores->a[i], 0); } - QFV_DestroyFenceSet (vulkan_ctx->frameset.fences); - QFV_DestroyCommandPool (vulkan_ctx->cmdpool); + df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0); Vulkan_Shutdown_Common (vulkan_ctx); } diff --git a/libs/video/renderer/vulkan/buffer.c b/libs/video/renderer/vulkan/buffer.c index e2d598b81..71b094e68 100644 --- a/libs/video/renderer/vulkan/buffer.c +++ b/libs/video/renderer/vulkan/buffer.c @@ -61,7 +61,7 @@ #include "util.h" -qfv_buffer_t * +VkBuffer QFV_CreateBuffer (qfv_device_t *device, VkDeviceSize size, VkBufferUsageFlags usage) { @@ -73,24 +73,23 @@ QFV_CreateBuffer (qfv_device_t *device, VkDeviceSize size, size, usage, VK_SHARING_MODE_EXCLUSIVE, 0, 0 }; - qfv_buffer_t *buffer = malloc (sizeof (*buffer)); - dfunc->vkCreateBuffer (dev, &createInfo, 0, &buffer->buffer); - buffer->device = device; + VkBuffer buffer; + dfunc->vkCreateBuffer (dev, &createInfo, 0, &buffer); return buffer; } -qfv_memory_t * -QFV_AllocBufferMemory (qfv_buffer_t *buffer, VkMemoryPropertyFlags properties, +VkDeviceMemory +QFV_AllocBufferMemory (qfv_device_t *device, + VkBuffer buffer, VkMemoryPropertyFlags properties, VkDeviceSize size, VkDeviceSize offset) { - qfv_device_t *device = buffer->device; VkDevice dev = device->dev; qfv_physdev_t *physdev = device->physDev; VkPhysicalDeviceMemoryProperties *memprops = &physdev->memory_properties; qfv_devfuncs_t *dfunc = device->funcs; VkMemoryRequirements requirements; - dfunc->vkGetBufferMemoryRequirements (dev, buffer->buffer, &requirements); + dfunc->vkGetBufferMemoryRequirements (dev, buffer, &requirements); size = max (size, offset + requirements.size); VkDeviceMemory object = 0; @@ -112,97 +111,55 @@ QFV_AllocBufferMemory (qfv_buffer_t *buffer, VkMemoryPropertyFlags properties, } } - qfv_memory_t *memory = 0; - - if (object) { - memory = malloc (sizeof (*memory)); - memory->device = device; - memory->object = object; - } - return memory; + return object; } int -QFV_BindBufferMemory (qfv_buffer_t *buffer, qfv_memory_t *memory, +QFV_BindBufferMemory (qfv_device_t *device, + VkBuffer buffer, VkDeviceMemory object, VkDeviceSize offset) { - qfv_device_t *device = buffer->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - VkResult res = dfunc->vkBindBufferMemory (dev, buffer->buffer, - memory->object, offset); + VkResult res = dfunc->vkBindBufferMemory (dev, buffer, object, offset); return res == VK_SUCCESS; } qfv_bufferbarrierset_t * -QFV_CreateBufferTransitionSet (qfv_buffertransition_t **transitions, - int numTransitions) +QFV_CreateBufferTransitions (qfv_buffertransition_t *transitions, + int numTransitions) { - qfv_device_t *device = transitions[0]->buffer->device; - qfv_bufferbarrierset_t *barrierset = malloc (sizeof (*barrierset) - + sizeof (VkBufferMemoryBarrier) * numTransitions); - - barrierset->device = device; - barrierset->numBarriers = numTransitions; - barrierset->barriers = (VkBufferMemoryBarrier *) (barrierset + 1); + qfv_bufferbarrierset_t *barrierset; + barrierset = DARRAY_ALLOCFIXED (*barrierset, numTransitions, malloc); for (int i = 0; i < numTransitions; i++) { - VkBufferMemoryBarrier *barrier = &barrierset->barriers[i]; - barrier->sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - barrier->pNext = 0; - barrier->srcAccessMask = transitions[i]->srcAccess; - barrier->dstAccessMask = transitions[i]->dstAccess; - barrier->srcQueueFamilyIndex = transitions[i]->srcQueueFamily; - barrier->dstQueueFamilyIndex = transitions[i]->dstQueueFamily; - barrier->buffer = transitions[i]->buffer->buffer; - barrier->offset = transitions[i]->offset; - barrier->size = transitions[i]->size; + barrierset->a[i].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + barrierset->a[i].pNext = 0; + barrierset->a[i].srcAccessMask = transitions[i].srcAccess; + barrierset->a[i].dstAccessMask = transitions[i].dstAccess; + barrierset->a[i].srcQueueFamilyIndex = transitions[i].srcQueueFamily; + barrierset->a[i].dstQueueFamilyIndex = transitions[i].dstQueueFamily; + barrierset->a[i].buffer = transitions[i].buffer; + barrierset->a[i].offset = transitions[i].offset; + barrierset->a[i].size = transitions[i].size; } return barrierset; } -qfv_bufferview_t * -QFV_CreateBufferView (qfv_buffer_t *buffer, VkFormat format, +VkBufferView +QFV_CreateBufferView (qfv_device_t *device, VkBuffer buffer, VkFormat format, VkDeviceSize offset, VkDeviceSize size) { - qfv_device_t *device = buffer->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; VkBufferViewCreateInfo createInfo = { VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, 0, 0, - buffer->buffer, format, offset, size, + buffer, format, offset, size, }; - qfv_bufferview_t *view = malloc (sizeof (*view)); - view->device = device; - view->buffer = buffer; - view->format = format; - view->offset = offset; - view->size = size; - dfunc->vkCreateBufferView (dev, &createInfo, 0, &view->view); + VkBufferView view; + dfunc->vkCreateBufferView (dev, &createInfo, 0, &view); return view; } - -void -QFV_DestroyBufferView (qfv_bufferview_t *view) -{ - qfv_device_t *device = view->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyBufferView (dev, view->view, 0); - free (view); -} - -void -QFV_DestroyBuffer (qfv_buffer_t *buffer) -{ - qfv_device_t *device = buffer->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyBuffer (dev, buffer->buffer, 0); - free (buffer); -} diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index fa671fa5d..8ba60ab32 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -64,7 +64,7 @@ #include "util.h" -qfv_cmdpool_t * +VkCommandPool QFV_CreateCommandPool (qfv_device_t *device, uint32_t queueFamily, int transient, int reset) { @@ -82,43 +82,15 @@ QFV_CreateCommandPool (qfv_device_t *device, uint32_t queueFamily, flags, queueFamily }; - qfv_cmdpool_t *cmdpool = malloc (sizeof (*cmdpool)); - dfunc->vkCreateCommandPool (dev, &createInfo, 0, &cmdpool->cmdpool); - cmdpool->device = device; - return cmdpool; -} - -int -QFV_ResetCommandPool (qfv_cmdpool_t *pool, int release) -{ - qfv_device_t *device = pool->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - VkCommandPool cmdpool = pool->cmdpool; - VkCommandPoolResetFlags release_flag = 0; - - if (release) { - release_flag = VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT; - } - - return dfunc->vkResetCommandPool (dev, cmdpool, release_flag) == VK_SUCCESS; -} - -void -QFV_DestroyCommandPool (qfv_cmdpool_t *pool) -{ - qfv_device_t *device = pool->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyCommandPool (dev, pool->cmdpool, 0); - free (pool); + VkCommandPool pool; + dfunc->vkCreateCommandPool (dev, &createInfo, 0, &pool); + return pool; } qfv_cmdbufferset_t * -QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count) +QFV_AllocateCommandBuffers (qfv_device_t *device, VkCommandPool pool, + int secondary, int count) { - qfv_device_t *device = pool->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; uint32_t level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; @@ -127,96 +99,15 @@ QFV_AllocateCommandBuffers (qfv_cmdpool_t *pool, int secondary, int count) } VkCommandBufferAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, - pool->cmdpool, level, count + pool, level, count }; qfv_cmdbufferset_t *cmdbufferset; - cmdbufferset = malloc (sizeof (qfv_cmdbufferset_t) - + count * sizeof (qfv_buffer_t *) - + count * sizeof (qfv_buffer_t) - + count * sizeof (VkCommandBuffer)); - cmdbufferset->buffers = (qfv_cmdbuffer_t **) (cmdbufferset + 1); - cmdbufferset->vkBuffers = (VkCommandBuffer *) (cmdbufferset->buffers - + count); - qfv_cmdbuffer_t *buffer = (qfv_cmdbuffer_t *) (cmdbufferset->vkBuffers - + count); - cmdbufferset->cmdpool = pool->cmdpool; - cmdbufferset->numBuffers = count; - dfunc->vkAllocateCommandBuffers (dev, &allocInfo, cmdbufferset->vkBuffers); - for (int i = 0; i < count; i++) { - buffer->device = device; - buffer->buffer = &cmdbufferset->vkBuffers[i]; - cmdbufferset->buffers[i] = buffer++; - } + cmdbufferset = DARRAY_ALLOCFIXED (*cmdbufferset, count, malloc); + dfunc->vkAllocateCommandBuffers (dev, &allocInfo, cmdbufferset->a); return cmdbufferset; } -void QFV_FreeCommandBuffers (qfv_cmdbufferset_t *bufferset) -{ - qfv_device_t *device = bufferset->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkFreeCommandBuffers (dev, bufferset->cmdpool, - bufferset->numBuffers, - bufferset->vkBuffers); - free (bufferset); -} - -int -QFV_BeginCommandBuffer (qfv_cmdbuffer_t *buffer, int oneTime, int rpContinue, - int simultaneous, - VkCommandBufferInheritanceInfo *inheritanceInfo) -{ - qfv_device_t *device = buffer->device; - qfv_devfuncs_t *dfunc = device->funcs; - VkCommandBuffer buff = *buffer->buffer; - VkCommandBufferUsageFlags usage = 0; - - if (oneTime) { - usage |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - } - if (rpContinue) { - usage |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; - } - if (simultaneous) { - usage |= VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - } - - VkCommandBufferBeginInfo beginInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, - usage, - 0 - }; - - return dfunc->vkBeginCommandBuffer (buff, &beginInfo) == VK_SUCCESS; -} - -int -QFV_EndCommandBuffer (qfv_cmdbuffer_t *buffer) -{ - qfv_device_t *device = buffer->device; - qfv_devfuncs_t *dfunc = device->funcs; - VkCommandBuffer buff = *buffer->buffer; - - return dfunc->vkEndCommandBuffer (buff) == VK_SUCCESS; -} - -int -QFV_ResetCommandBuffer (qfv_cmdbuffer_t *buffer, int release) -{ - qfv_device_t *device = buffer->device; - qfv_devfuncs_t *dfunc = device->funcs; - VkCommandBuffer buff = *buffer->buffer; - VkCommandBufferResetFlags release_flag = 0; - - if (release) { - release_flag = VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT; - } - - return dfunc->vkResetCommandBuffer (buff, release_flag) == VK_SUCCESS; -} - -qfv_semaphore_t * +VkSemaphore QFV_CreateSemaphore (qfv_device_t *device) { VkDevice dev = device->dev; @@ -227,58 +118,12 @@ QFV_CreateSemaphore (qfv_device_t *device) 0 }; - qfv_semaphore_t *semaphore = malloc (sizeof (*semaphore)); - semaphore->device = device; - - dfunc->vkCreateSemaphore (dev, &createInfo, 0, &semaphore->semaphore); + VkSemaphore semaphore; + dfunc->vkCreateSemaphore (dev, &createInfo, 0, &semaphore); return semaphore; } -qfv_semaphoreset_t * -QFV_CreateSemaphoreSet (qfv_semaphore_t **semaphores, int numSemaphores) -{ - qfv_device_t *device = semaphores[0]->device; - qfv_semaphoreset_t *semaphoreset; - semaphoreset = calloc (1, sizeof (*semaphoreset) - + sizeof (qfv_semaphore_t *) * numSemaphores - + sizeof (VkSemaphore) * numSemaphores - + sizeof (VkPipelineStageFlags) * numSemaphores); - - semaphoreset->device = device; - semaphoreset->vkSemaphores = (VkSemaphore *) (semaphoreset + 1); - semaphoreset->stages = (VkPipelineStageFlags *) - &semaphoreset->vkSemaphores[numSemaphores]; - semaphoreset->semaphores = (qfv_semaphore_t **) (semaphoreset->stages - + numSemaphores); - semaphoreset->numSemaphores = numSemaphores; - - if (semaphores) { - for (int i = 0; i < numSemaphores; i++) { - semaphoreset->semaphores[i] = semaphores[i]; - semaphoreset->vkSemaphores[i] = semaphores[i]->semaphore; - } - } - return semaphoreset; -} - -void -QFV_DestroySemaphore (qfv_semaphore_t *semaphore) -{ - qfv_device_t *device = semaphore->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroySemaphore (dev, semaphore->semaphore, 0); - free (semaphore); -} - -void -QFV_DestroySemaphoreSet (qfv_semaphoreset_t *semaphores) -{ - free (semaphores); -} - -qfv_fence_t * +VkFence QFV_CreateFence (qfv_device_t *device, int signaled) { VkDevice dev = device->dev; @@ -289,113 +134,28 @@ QFV_CreateFence (qfv_device_t *device, int signaled) signaled ? VK_FENCE_CREATE_SIGNALED_BIT : 0, }; - qfv_fence_t *fence = malloc (sizeof (*fence)); - fence->device = device; - - dfunc->vkCreateFence (dev, &createInfo, 0, &fence->fence); + VkFence fence; + dfunc->vkCreateFence (dev, &createInfo, 0, &fence); return fence; } -qfv_fenceset_t * -QFV_CreateFenceSet (qfv_fence_t **fences, int numFences) -{ - qfv_fenceset_t *fenceset = malloc (sizeof (*fenceset) - + sizeof (qfv_fence_t) * numFences - + sizeof (VkFence) * numFences); - - fenceset->fences = (qfv_fence_t **) (fenceset + 1); - fenceset->vkFences = (VkFence *) (fenceset->fences + numFences); - fenceset->numFences = numFences; - - if (fences) { - fenceset->device = fences[0]->device; - for (int i = 0; i < numFences; i++) { - fenceset->fences[i] = fences[i]; - fenceset->vkFences[i] = fences[i]->fence; - } - } - return fenceset; -} - -void -QFV_DestroyFence (qfv_fence_t *fence) -{ - qfv_device_t *device = fence->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyFence (dev, fence->fence, 0); - free (fence); -} - -void -QFV_DestroyFenceSet (qfv_fenceset_t *fenceset) -{ - free (fenceset); -} - -int -QFV_WaitForFences (qfv_fenceset_t *fenceset, int all, uint64_t timeout) -{ - qfv_device_t *device = fenceset->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - VkResult res = dfunc->vkWaitForFences (dev, fenceset->numFences, - fenceset->vkFences, all, timeout); - return res == VK_SUCCESS; -} - -int -QFV_WaitForFence (qfv_fence_t *fence, uint64_t timeout) -{ - qfv_device_t *device = fence->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - VkResult res = dfunc->vkWaitForFences (dev, 1, &fence->fence, 1, timeout); - return res == VK_SUCCESS; -} - -int -QFV_ResetFences (qfv_fenceset_t *fenceset) -{ - qfv_device_t *device = fenceset->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - return dfunc->vkResetFences (dev, fenceset->numFences, - fenceset->vkFences) == VK_SUCCESS; -} - -int -QFV_ResetFence (qfv_fence_t *fence) -{ - qfv_device_t *device = fence->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - return dfunc->vkResetFences (dev, 1, &fence->fence) == VK_SUCCESS; -} - int QFV_QueueSubmit (qfv_queue_t *queue, qfv_semaphoreset_t *waitSemaphores, + VkPipelineStageFlags *stages, qfv_cmdbufferset_t *buffers, - qfv_semaphoreset_t *signalSemaphores, qfv_fence_t *fence) + qfv_semaphoreset_t *signalSemaphores, VkFence fence) { qfv_device_t *device = queue->device; qfv_devfuncs_t *dfunc = device->funcs; VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, - waitSemaphores->numSemaphores, - waitSemaphores->vkSemaphores, waitSemaphores->stages, - buffers->numBuffers, buffers->vkBuffers, - signalSemaphores->numSemaphores, - signalSemaphores->vkSemaphores + waitSemaphores->size, waitSemaphores->a, stages, + buffers->size, buffers->a, + signalSemaphores->size, signalSemaphores->a }; //FIXME multi-batch - return dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, - fence->fence) == VK_SUCCESS; + return dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, fence) + == VK_SUCCESS; } int @@ -405,129 +165,3 @@ QFV_QueueWaitIdle (qfv_queue_t *queue) qfv_devfuncs_t *dfunc = device->funcs; return dfunc->vkQueueWaitIdle (queue->queue) == VK_SUCCESS; } - -void -QFV_CmdPipelineBarrier (qfv_cmdbuffer_t *cmdBuffer, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - VkDependencyFlags dependencyFlags, - struct qfv_memorybarrierset_s *memBarrierSet, - qfv_bufferbarrierset_t *buffBarrierSet, - qfv_imagebarrierset_t *imgBarrierSet) -{ - qfv_device_t *device = cmdBuffer->device; - qfv_devfuncs_t *dfunc = device->funcs; - uint32_t numMemBarriers = 0; - VkMemoryBarrier *memBarriers = 0; - uint32_t numBuffBarriers = 0; - VkBufferMemoryBarrier *buffBarriers = 0; - uint32_t numImgBarriers = 0; - VkImageMemoryBarrier *imgBarriers = 0; - - if (buffBarrierSet) { - numBuffBarriers = buffBarrierSet->numBarriers; - buffBarriers = buffBarrierSet->barriers; - } - if (imgBarrierSet) { - numImgBarriers = imgBarrierSet->numBarriers; - imgBarriers = imgBarrierSet->barriers; - } - dfunc->vkCmdPipelineBarrier (*cmdBuffer->buffer, - srcStageMask, dstStageMask, dependencyFlags, - numMemBarriers, memBarriers, - numBuffBarriers, buffBarriers, - numImgBarriers, imgBarriers); -} - -void -QFV_CmdCopyBuffer (qfv_cmdbuffer_t *cmdBuffer, - struct qfv_buffer_s *src, struct qfv_buffer_s *dst, - VkBufferCopy *regions, uint32_t numRegions) -{ - qfv_device_t *device = cmdBuffer->device; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkCmdCopyBuffer (*cmdBuffer->buffer, src->buffer, dst->buffer, - numRegions, regions); -} - -void -QFV_CmdCopyBufferToImage (qfv_cmdbuffer_t *cmdBuffer, - struct qfv_buffer_s *src, - struct qfv_image_s *dst, - VkImageLayout layout, - VkBufferImageCopy *regions, uint32_t numRegions) -{ - qfv_device_t *device = cmdBuffer->device; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkCmdCopyBufferToImage (*cmdBuffer->buffer, src->buffer, dst->image, - layout, numRegions, regions); -} - -void -QFV_CmdCopyImageToBuffer (qfv_cmdbuffer_t *cmdBuffer, - struct qfv_image_s *src, - VkImageLayout layout, - struct qfv_buffer_s *dst, - VkBufferImageCopy *regions, uint32_t numRegions) -{ - qfv_device_t *device = cmdBuffer->device; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkCmdCopyImageToBuffer (*cmdBuffer->buffer, src->image, layout, - dst->buffer, numRegions, regions); -} - -void -QFV_CmdBeginRenderPass (qfv_cmdbuffer_t *cmdBuffer, - qfv_renderpass_t *renderPass, - qfv_framebuffer_t *framebuffer, - VkRect2D renderArea, - uint32_t numClearValues, - VkClearValue *clearValues, - VkSubpassContents subpassContents) -{ - qfv_device_t *device = cmdBuffer->device; - qfv_devfuncs_t *dfunc = device->funcs; - - VkRenderPassBeginInfo beginInfo = { - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 0, - renderPass->renderPass, framebuffer->framebuffer, renderArea, - numClearValues, clearValues, - }; - - dfunc->vkCmdBeginRenderPass (*cmdBuffer->buffer, &beginInfo, - subpassContents); -} - -void -QFV_CmdNextSubpass (qfv_cmdbuffer_t *cmdBuffer, - VkSubpassContents subpassContents) -{ - qfv_device_t *device = cmdBuffer->device; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkCmdNextSubpass (*cmdBuffer->buffer, subpassContents); -} - -void -QFV_CmdEndRenderPass (qfv_cmdbuffer_t *cmdBuffer) -{ - qfv_device_t *device = cmdBuffer->device; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkCmdEndRenderPass (*cmdBuffer->buffer); -} - -void -QFV_CmdBindPipeline (qfv_cmdbuffer_t *cmdBuffer, - VkPipelineBindPoint bindPoint, - qfv_pipeline_t *pipeline) -{ - qfv_device_t *device = cmdBuffer->device; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkCmdBindPipeline (*cmdBuffer->buffer, bindPoint, - pipeline->pipeline); -} diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index 750534f53..0457d0570 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -211,3 +211,24 @@ QFV_DeviceWaitIdle (qfv_device_t *device) qfv_devfuncs_t *dfunc = device->funcs; return dfunc->vkDeviceWaitIdle (device->dev) == VK_SUCCESS; } + +VkFormat +QFV_FindSupportedFormat (qfv_device_t *device, + VkImageTiling tiling, VkFormatFeatureFlags features, + int numCandidates, const VkFormat *candidates) +{ + VkPhysicalDevice pdev = device->physDev->dev; + qfv_instfuncs_t *ifuncs = device->physDev->instance->funcs; + for (int i = 0; i < numCandidates; i++) { + VkFormat format = candidates[i]; + VkFormatProperties props; + ifuncs->vkGetPhysicalDeviceFormatProperties (pdev, format, &props); + if ((tiling == VK_IMAGE_TILING_LINEAR + && (props.linearTilingFeatures & features) == features) + || (tiling == VK_IMAGE_TILING_OPTIMAL + && (props.optimalTilingFeatures & features) == features)) { + return format; + } + } + Sys_Error ("no supported format"); +} diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index 63b836be5..65f0dcdd3 100644 --- a/libs/video/renderer/vulkan/image.c +++ b/libs/video/renderer/vulkan/image.c @@ -61,7 +61,7 @@ #include "util.h" -qfv_image_t * +VkImage QFV_CreateImage (qfv_device_t *device, int cubemap, VkImageType type, VkFormat format, @@ -85,24 +85,23 @@ QFV_CreateImage (qfv_device_t *device, int cubemap, 0, 0, VK_IMAGE_LAYOUT_UNDEFINED, }; - qfv_image_t *image = malloc (sizeof (*image)); - dfunc->vkCreateImage (dev, &createInfo, 0, &image->image); - image->device = device; + VkImage image; + dfunc->vkCreateImage (dev, &createInfo, 0, &image); return image; } -qfv_memory_t * -QFV_AllocImageMemory (qfv_image_t *image, VkMemoryPropertyFlags properties, - VkDeviceSize size, VkDeviceSize offset) +VkDeviceMemory +QFV_AllocImageMemory (qfv_device_t *device, + VkImage image, VkMemoryPropertyFlags properties, + VkDeviceSize size, VkDeviceSize offset) { - qfv_device_t *device = image->device; VkDevice dev = device->dev; qfv_physdev_t *physdev = device->physDev; VkPhysicalDeviceMemoryProperties *memprops = &physdev->memory_properties; qfv_devfuncs_t *dfunc = device->funcs; VkMemoryRequirements requirements; - dfunc->vkGetImageMemoryRequirements (dev, image->image, &requirements); + dfunc->vkGetImageMemoryRequirements (dev, image, &requirements); size = max (size, offset + requirements.size); VkDeviceMemory object = 0; @@ -124,72 +123,48 @@ QFV_AllocImageMemory (qfv_image_t *image, VkMemoryPropertyFlags properties, } } - qfv_memory_t *memory = 0; - - if (object) { - memory = malloc (sizeof (*memory)); - memory->device = device; - memory->object = object; - } - return memory; -} - -int -QFV_BindImageMemory (qfv_image_t *image, qfv_memory_t *memory, - VkDeviceSize offset) -{ - qfv_device_t *device = image->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - VkResult res = dfunc->vkBindImageMemory (dev, image->image, - memory->object, offset); - return res == VK_SUCCESS; + return object; } qfv_imagebarrierset_t * -QFV_CreateImageTransitionSet (qfv_imagetransition_t **transitions, +QFV_CreateImageTransitionSet (qfv_imagetransition_t *transitions, int numTransitions) { - qfv_device_t *device = transitions[0]->image->device; - qfv_imagebarrierset_t *barrierset = malloc (sizeof (*barrierset) - + sizeof (VkImageMemoryBarrier) * numTransitions); - - barrierset->device = device; - barrierset->numBarriers = numTransitions; - barrierset->barriers = (VkImageMemoryBarrier *) (barrierset + 1); + qfv_imagebarrierset_t *barrierset; + barrierset = DARRAY_ALLOCFIXED (*barrierset, numTransitions, malloc); for (int i = 0; i < numTransitions; i++) { - VkImageMemoryBarrier *barrier = &barrierset->barriers[i]; - barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier->pNext = 0; - barrier->srcAccessMask = transitions[i]->srcAccess; - barrier->dstAccessMask = transitions[i]->dstAccess; - barrier->oldLayout = transitions[i]->oldLayout; - barrier->newLayout = transitions[i]->newLayout; - barrier->srcQueueFamilyIndex = transitions[i]->srcQueueFamily; - barrier->dstQueueFamilyIndex = transitions[i]->dstQueueFamily; - barrier->image = transitions[i]->image->image; - barrier->subresourceRange.aspectMask = transitions[i]->aspect; - barrier->subresourceRange.baseMipLevel = 0; - barrier->subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; - barrier->subresourceRange.baseArrayLayer = 0; - barrier->subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + barrierset->a[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrierset->a[i].pNext = 0; + barrierset->a[i].srcAccessMask = transitions[i].srcAccess; + barrierset->a[i].dstAccessMask = transitions[i].dstAccess; + barrierset->a[i].oldLayout = transitions[i].oldLayout; + barrierset->a[i].newLayout = transitions[i].newLayout; + barrierset->a[i].srcQueueFamilyIndex = transitions[i].srcQueueFamily; + barrierset->a[i].dstQueueFamilyIndex = transitions[i].dstQueueFamily; + barrierset->a[i].image = transitions[i].image; + barrierset->a[i].subresourceRange.aspectMask = transitions[i].aspect; + barrierset->a[i].subresourceRange.baseMipLevel = 0; + barrierset->a[i].subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrierset->a[i].subresourceRange.baseArrayLayer = 0; + barrierset->a[i].subresourceRange.layerCount + = VK_REMAINING_ARRAY_LAYERS; } return barrierset; } -qfv_imageview_t * -QFV_CreateImageView (qfv_image_t *image, VkImageViewType type, VkFormat format, +VkImageView +QFV_CreateImageView (qfv_device_t *device, VkImage image, + VkImageViewType type, VkFormat format, VkImageAspectFlags aspect) { - qfv_device_t *device = image->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; VkImageViewCreateInfo createInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 0, 0, - image->image, type, format, + image, type, format, { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, @@ -203,34 +178,7 @@ QFV_CreateImageView (qfv_image_t *image, VkImageViewType type, VkFormat format, } }; - qfv_imageview_t *view = malloc (sizeof (*view)); - view->device = device; - view->image = image; - view->type = type; - view->format = format; - view->aspect = aspect; - dfunc->vkCreateImageView (dev, &createInfo, 0, &view->view); + VkImageView view; + dfunc->vkCreateImageView (dev, &createInfo, 0, &view); return view; } - -void -QFV_DestroyImageView (qfv_imageview_t *view) -{ - qfv_device_t *device = view->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyImageView (dev, view->view, 0); - free (view); -} - -void -QFV_DestroyImage (qfv_image_t *image) -{ - qfv_device_t *device = image->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyImage (dev, image->image, 0); - free (image); -} diff --git a/libs/video/renderer/vulkan/instance.c b/libs/video/renderer/vulkan/instance.c index a744c2608..234236014 100644 --- a/libs/video/renderer/vulkan/instance.c +++ b/libs/video/renderer/vulkan/instance.c @@ -264,7 +264,9 @@ QFV_CreateInstance (vulkan_ctx_t *ctx, for (uint32_t i = 0; i < inst->numDevices; i++) { VkPhysicalDevice physDev = devices[i]; qfv_physdev_t *dev = &inst->devices[i]; + dev->instance = inst; dev->dev = physDev; + ifunc->vkGetPhysicalDeviceProperties (physDev, &dev->properties); ifunc->vkGetPhysicalDeviceMemoryProperties (physDev, &dev->memory_properties); } diff --git a/libs/video/renderer/vulkan/memory.c b/libs/video/renderer/vulkan/memory.c index c18a8144f..9397f4366 100644 --- a/libs/video/renderer/vulkan/memory.c +++ b/libs/video/renderer/vulkan/memory.c @@ -60,54 +60,32 @@ #include "util.h" -void -QFV_FreeMemory (qfv_memory_t *memory) -{ - qfv_device_t *device = memory->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkFreeMemory (dev, memory->object, 0); - free (memory); -} - void * -QFV_MapMemory (qfv_memory_t *memory, VkDeviceSize offset, VkDeviceSize size) +QFV_MapMemory (qfv_device_t *device, VkDeviceMemory object, + VkDeviceSize offset, VkDeviceSize size) { - qfv_device_t *device = memory->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; void *map = 0; - dfunc->vkMapMemory (dev, memory->object, offset, size, 0, &map); + dfunc->vkMapMemory (dev, object, offset, size, 0, &map); return map; } void -QFV_UnmapMemory (qfv_memory_t *memory) +QFV_FlushMemory (qfv_device_t *device, qfv_mappedmemrangeset_t *flushRanges) { - qfv_device_t *device = memory->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkUnmapMemory (dev, memory->object); -} + VkMappedMemoryRange *ranges = alloca(sizeof (*ranges) * flushRanges->size); -void -QFV_FlushMemory (qfv_mappedmemrange_t *flushRanges, uint32_t numFlushRanges) -{ - qfv_device_t *device = flushRanges[0].memory->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - VkMappedMemoryRange *ranges = alloca(sizeof (*ranges) * numFlushRanges); - - for (uint32_t i = 0; i < numFlushRanges; i++) { + for (uint32_t i = 0; i < flushRanges->size; i++) { ranges[i].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; ranges[i].pNext = 0; - ranges[i].memory = flushRanges[i].memory->object; - ranges[i].offset = flushRanges[i].offset; - ranges[i].size = flushRanges[i].size; + ranges[i].memory = flushRanges->a[i].object; + ranges[i].offset = flushRanges->a[i].offset; + ranges[i].size = flushRanges->a[i].size; } - dfunc->vkFlushMappedMemoryRanges (dev, numFlushRanges, ranges); + dfunc->vkFlushMappedMemoryRanges (dev, flushRanges->size, ranges); } diff --git a/libs/video/renderer/vulkan/renderpass.c b/libs/video/renderer/vulkan/renderpass.c index 9c1064192..7a64d10a3 100644 --- a/libs/video/renderer/vulkan/renderpass.c +++ b/libs/video/renderer/vulkan/renderpass.c @@ -105,21 +105,17 @@ QFV_CreateRenderPass (qfv_device_t *device, qfv_framebuffer_t * QFV_CreateFramebuffer (qfv_renderpass_t *renderPass, - uint32_t numAttachments, qfv_imageview_t **attachments, + uint32_t numAttachments, VkImageView *attachments, uint32_t width, uint32_t height, uint32_t layers) { qfv_device_t *device = renderPass->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - VkImageView *views = alloca (numAttachments * sizeof (*views)); - for (uint32_t i = 0; i < numAttachments; i++) { - views[i] = attachments[i]->view; - } - VkFramebufferCreateInfo createInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 0, 0, - renderPass->renderPass, numAttachments, views, width, height, layers, + renderPass->renderPass, numAttachments, attachments, + width, height, layers, }; qfv_framebuffer_t *framebuffer = malloc (sizeof (*framebuffer)); diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c index b32e3b3ed..4ea0a36dc 100644 --- a/libs/video/renderer/vulkan/swapchain.c +++ b/libs/video/renderer/vulkan/swapchain.c @@ -13,6 +13,7 @@ #include "QF/Vulkan/cvars.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/swapchain.h" @@ -84,7 +85,8 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; imageUsage &= surfCaps.supportedUsageFlags; - VkSurfaceTransformFlagBitsKHR surfTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + VkSurfaceTransformFlagBitsKHR surfTransform + = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; uint32_t numFormats; ifuncs->vkGetPhysicalDeviceSurfaceFormatsKHR (physDev, @@ -128,24 +130,31 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) old_swapchain }; - VkDevice device = ctx->device->dev; + VkDevice dev = ctx->device->dev; VkSwapchainKHR swapchain; - dfuncs->vkCreateSwapchainKHR (device, &createInfo, 0, &swapchain); + dfuncs->vkCreateSwapchainKHR (dev, &createInfo, 0, &swapchain); if (old_swapchain != swapchain) { - dfuncs->vkDestroySwapchainKHR (device, old_swapchain, 0); + dfuncs->vkDestroySwapchainKHR (dev, old_swapchain, 0); } - dfuncs->vkGetSwapchainImagesKHR (device, swapchain, &numImages, 0); - qfv_swapchain_t *sc = malloc (sizeof (qfv_swapchain_t) - + numImages * sizeof (VkImage)); + dfuncs->vkGetSwapchainImagesKHR (dev, swapchain, &numImages, 0); + qfv_swapchain_t *sc = malloc (sizeof (qfv_swapchain_t)); sc->device = ctx->device; sc->surface = ctx->surface; sc->swapchain = swapchain; + sc->format = useFormat.format; + sc->extent = imageSize; sc->numImages = numImages; - sc->images = (VkImage *) (sc + 1); - dfuncs->vkGetSwapchainImagesKHR (device, swapchain, &numImages, - sc->images); + sc->images = DARRAY_ALLOCFIXED (qfv_imageset_t, numImages, malloc); + sc->imageViews = DARRAY_ALLOCFIXED (qfv_imageviewset_t, numImages, malloc); + dfuncs->vkGetSwapchainImagesKHR (dev, swapchain, &numImages, sc->images->a); + for (uint32_t i = 0; i < numImages; i++) { + sc->imageViews->a[i] + = QFV_CreateImageView (ctx->device, sc->images->a[i], + VK_IMAGE_VIEW_TYPE_2D, sc->format, + VK_IMAGE_ASPECT_COLOR_BIT); + } return sc; } @@ -155,23 +164,26 @@ QFV_DestroySwapchain (qfv_swapchain_t *swapchain) qfv_device_t *device = swapchain->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; + for (size_t i = 0; i < swapchain->imageViews->size; i++) { + dfunc->vkDestroyImageView (dev, swapchain->imageViews->a[i], 0); + } + free (swapchain->images); + free (swapchain->imageViews); dfunc->vkDestroySwapchainKHR (dev, swapchain->swapchain, 0); free (swapchain); } int -QFV_AcquireNextImage (qfv_swapchain_t *swapchain, qfv_semaphore_t *semaphore, - qfv_fence_t *fence, uint32_t *imageIndex) +QFV_AcquireNextImage (qfv_swapchain_t *swapchain, VkSemaphore semaphore, + VkFence fence, uint32_t *imageIndex) { qfv_device_t *device = swapchain->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; uint64_t timeout = 2000000000; - VkSemaphore sem = semaphore ? semaphore->semaphore : VK_NULL_HANDLE; - VkFence fnc = fence ? fence->fence : VK_NULL_HANDLE; *imageIndex = ~0u; VkResult res = dfunc->vkAcquireNextImageKHR (dev, swapchain->swapchain, - timeout, sem, fnc, + timeout, semaphore, fence, imageIndex); switch (res) { case VK_SUCCESS: From 73fde40cad512c8b6842791ea4aa0a3c017fadd6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 23:30:25 +0900 Subject: [PATCH 075/435] Sanitize some more structs --- include/QF/Vulkan/pipeline.h | 29 +++++------ include/QF/Vulkan/renderpass.h | 56 +++++++-------------- libs/video/renderer/vulkan/pipeline.c | 18 +++---- libs/video/renderer/vulkan/renderpass.c | 67 ++++++++----------------- 4 files changed, 62 insertions(+), 108 deletions(-) diff --git a/include/QF/Vulkan/pipeline.h b/include/QF/Vulkan/pipeline.h index 6a532102b..2120e2317 100644 --- a/include/QF/Vulkan/pipeline.h +++ b/include/QF/Vulkan/pipeline.h @@ -1,6 +1,8 @@ #ifndef __QF_Vulkan_pipeline_h #define __QF_Vulkan_pipeline_h +#include "QF/darray.h" + typedef struct qfv_shadermodule_s { struct qfv_device_s *device; VkShaderModule module; @@ -13,29 +15,24 @@ typedef struct qfv_shaderstageparams_s { const VkSpecializationInfo *specializationInfo; } qfv_shaderstageparams_t; -typedef struct qfv_shaderstageparamsset_s { - uint32_t numParams; - qfv_shaderstageparams_t params[]; -} qfv_shaderstageparamsset_t; +typedef struct qfv_shaderstageparamsset_s + DARRAY_TYPE (qfv_shaderstageparams_t) qfv_shaderstageparamsset_t; #define QFV_AllocShaderParamsSet(num, allocator) \ - allocator (field_offset (qfv_shaderstageparamsset_t, params[num])) + DARRAY_ALLOCFIXED (qfv_shaderstageparamsset_t, num, allocator) -typedef struct qfv_vertexinputbindingset_s { - uint32_t numBindings; - VkVertexInputBindingDescription bindings[]; -} qfv_vertexinputbindingset_t; +typedef struct qfv_vertexinputbindingset_s + DARRAY_TYPE (VkVertexInputBindingDescription) qfv_vertexinputbindingset_t; #define QFV_AllocVertexInputBindingSet(num, allocator) \ - allocator (field_offset (qfv_vertexinputbindingset_t, bindings[num])) + DARRAY_ALLOCFIXED (qfv_vertexinputbindingset_t, num, allocator) -typedef struct qfv_vertexinputattributeset_s { - uint32_t numAttributes; - VkVertexInputAttributeDescription attributes[]; -} qfv_vertexinputattributeset_t; +typedef struct qfv_vertexinputattributeset_s + DARRAY_TYPE (VkVertexInputAttributeDescription) + qfv_vertexinputattributeset_t; #define QFV_AllocVertexInputAttributeSet(num, allocator) \ - allocator (field_offset (qfv_vertexinputattributeset_t, bindings[num])) + DARRAY_ALLOCFIXED (qfv_vertexinputattributeset_t, num, allocator) typedef struct qfv_vertexinputstate_s { qfv_vertexinputbindingset_t *bindings; @@ -168,7 +165,7 @@ typedef struct qfv_graphicspipelinecreateinfo_s { qfv_pipelineblend_t *colorBlendState; qfv_dynamicstateset_t *dynamicState; qfv_pipelinelayout_t *layout; - struct qfv_renderpass_s *renderPass; + VkRenderPass renderPass; uint32_t subpass; qfv_pipeline_t *basePipeline; int32_t basePipelineIndex; diff --git a/include/QF/Vulkan/renderpass.h b/include/QF/Vulkan/renderpass.h index 3dd4acc63..257441ca1 100644 --- a/include/QF/Vulkan/renderpass.h +++ b/include/QF/Vulkan/renderpass.h @@ -1,21 +1,19 @@ #ifndef __QF_Vulkan_renderpass_h #define __QF_Vulkan_renderpass_h -typedef struct qfv_attachmentdescription_s { - uint32_t numAttachments; - VkAttachmentDescription attachments[]; -} qfv_attachmentdescription_t; +#include "QF/darray.h" + +typedef struct qfv_attachmentdescription_s + DARRAY_TYPE (VkAttachmentDescription) qfv_attachmentdescription_t; #define QFV_AllocAttachmentDescription(num, allocator) \ - allocator (field_offset (qfv_attachmentdescription_t, attachments[num])) + DARRAY_ALLOCFIXED (qfv_attachmentdescription_t, num, allocator) -typedef struct qfv_attachmentreference_s { - uint32_t numReferences; - VkAttachmentReference references[]; -} qfv_attachmentreference_t; +typedef struct qfv_attachmentreference_s + DARRAY_TYPE (VkAttachmentReference) qfv_attachmentreference_t; #define QFV_AllocAttachmentReference(num, allocator) \ - allocator (field_offset (qfv_attachmentreference_t, references[num])) + DARRAY_ALLOCFIXED (qfv_attachmentreference_t, num, allocator) typedef struct qfv_subpassparameters_s { VkPipelineBindPoint pipelineBindPoint; @@ -27,46 +25,30 @@ typedef struct qfv_subpassparameters_s { uint32_t *preserveAttachments; } qfv_subpassparameters_t; -typedef struct qfv_subpassparametersset_s { - uint32_t numSubpasses; - qfv_subpassparameters_t subpasses[]; -} qfv_subpassparametersset_t; +typedef struct qfv_subpassparametersset_s + DARRAY_TYPE (qfv_subpassparameters_t) qfv_subpassparametersset_t; #define QFV_AllocSubpassParametersSet(num, allocator) \ - allocator (field_offset (qfv_subpassparametersset_t, subpasses[num])) + DARRAY_ALLOCFIXED (qfv_subpassparametersset_t, num, allocator) -typedef struct qfv_subpassdependency_s { - uint32_t numDependencies; - VkSubpassDependency dependencies[]; -} qfv_subpassdependency_t; +typedef struct qfv_subpassdependency_s + DARRAY_TYPE (VkSubpassDependency) qfv_subpassdependency_t; #define QFV_AllocSubpassDependencies(num, allocator) \ - allocator (field_offset (qfv_subpassdependency_t, dependencies[num])) + DARRAY_ALLOCFIXED (qfv_subpassdependency_t, num, allocator) -typedef struct qfv_renderpass_s { - struct qfv_device_s *device; - VkRenderPass renderPass; -} qfv_renderpass_t; - -typedef struct qfv_framebuffer_s { - struct qfv_device_s *device; - VkFramebuffer framebuffer; -} qfv_framebuffer_t; - -qfv_renderpass_t * +struct qfv_device_s; +VkRenderPass QFV_CreateRenderPass (struct qfv_device_s *device, qfv_attachmentdescription_t *attachments, qfv_subpassparametersset_t *subpasses, qfv_subpassdependency_t *dependencies); -struct qfv_imageview_s; -qfv_framebuffer_t * -QFV_CreateFramebuffer (qfv_renderpass_t *renderPass, +VkFramebuffer +QFV_CreateFramebuffer (struct qfv_device_s *device, + VkRenderPass renderPass, uint32_t numAttachments, VkImageView *attachments, uint32_t width, uint32_t height, uint32_t layers); -void QFV_DestroyFramebuffer (qfv_framebuffer_t *framebuffer); -void QFV_DestroyRenderPass (qfv_renderpass_t *renderPass); - #endif//__QF_Vulkan_renderpass_h diff --git a/libs/video/renderer/vulkan/pipeline.c b/libs/video/renderer/vulkan/pipeline.c index 168ec100d..0dd5f260e 100644 --- a/libs/video/renderer/vulkan/pipeline.c +++ b/libs/video/renderer/vulkan/pipeline.c @@ -205,10 +205,10 @@ vertexInputSCI (qfv_vertexinputstate_t vertexState) { VkPipelineVertexInputStateCreateInfo createInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 0, 0, - vertexState.bindings->numBindings, - vertexState.bindings->bindings, - vertexState.attributes->numAttributes, - vertexState.attributes->attributes, + vertexState.bindings->size, + vertexState.bindings->a, + vertexState.attributes->size, + vertexState.attributes->a, }; return createInfo; } @@ -339,7 +339,7 @@ QFV_CreateGraphicsPipelines (qfv_device_t *device, uint32_t numPipelines = gpciSet->numPipelines; uint32_t stageCount = 0; for (uint32_t i = 0; i < numPipelines; i++) { - stageCount += gpciSet->pipelines[i]->stages->numParams; + stageCount += gpciSet->pipelines[i]->stages->size; } size_t blockSize = numPipelines @@ -377,7 +377,7 @@ QFV_CreateGraphicsPipelines (qfv_device_t *device, = (void *)(pipelineInfos->pColorBlendState + numPipelines); for (uint32_t i = 1; i < gpciSet->numPipelines; i++) { pipelineInfos[i].pStages = pipelineInfos[i - 1].pStages - + gpciSet->pipelines[i - 1]->stages->numParams; + + gpciSet->pipelines[i - 1]->stages->size; pipelineInfos[i].pVertexInputState = pipelineInfos[i - 1].pVertexInputState + 1; pipelineInfos[i].pInputAssemblyState @@ -403,9 +403,9 @@ QFV_CreateGraphicsPipelines (qfv_device_t *device, gci->sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; gci->pNext = 0; gci->flags = ci->flags; - gci->stageCount = ci->stages->numParams; + gci->stageCount = ci->stages->size; for (uint32_t j = 0; j < gci->stageCount; j++) { - ((VkPipelineShaderStageCreateInfo *)gci->pStages)[i] = shaderStageCI (ci->stages->params[j]); + ((VkPipelineShaderStageCreateInfo *)gci->pStages)[i] = shaderStageCI (ci->stages->a[j]); } if (ci->vertexState) { *(VkPipelineVertexInputStateCreateInfo *)gci->pVertexInputState = vertexInputSCI (*ci->vertexState); @@ -453,7 +453,7 @@ QFV_CreateGraphicsPipelines (qfv_device_t *device, gci->pDynamicState = 0; } gci->layout = ci->layout->layout; - gci->renderPass = ci->renderPass->renderPass; + gci->renderPass = ci->renderPass; gci->subpass = ci->subpass; gci->basePipelineHandle = ci->basePipeline->pipeline; gci->basePipelineIndex = ci->basePipelineIndex; diff --git a/libs/video/renderer/vulkan/renderpass.c b/libs/video/renderer/vulkan/renderpass.c index 7a64d10a3..60e279e18 100644 --- a/libs/video/renderer/vulkan/renderpass.c +++ b/libs/video/renderer/vulkan/renderpass.c @@ -1,7 +1,7 @@ /* - descriptor.c + renderpass.c - Vulkan descriptor functions + Vulkan render pass and frame buffer functions Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2020 Bill Currie @@ -62,7 +62,7 @@ #include "util.h" -qfv_renderpass_t * +VkRenderPass QFV_CreateRenderPass (qfv_device_t *device, qfv_attachmentdescription_t *attachments, qfv_subpassparametersset_t *subpassparams, @@ -71,19 +71,19 @@ QFV_CreateRenderPass (qfv_device_t *device, VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - VkSubpassDescription *subpasses = alloca (subpassparams->numSubpasses + VkSubpassDescription *subpasses = alloca (subpassparams->size * sizeof (*subpasses)); - for (uint32_t i = 0; i < subpassparams->numSubpasses; i++) { - qfv_subpassparameters_t *params = &subpassparams->subpasses[i]; + for (uint32_t i = 0; i < subpassparams->size; i++) { + qfv_subpassparameters_t *params = &subpassparams->a[i]; subpasses[i].flags = 0; subpasses[i].pipelineBindPoint = params->pipelineBindPoint; - subpasses[i].inputAttachmentCount = params->inputAttachments->numReferences; - subpasses[i].pInputAttachments = params->inputAttachments->references; - subpasses[i].colorAttachmentCount = params->colorAttachments->numReferences; - subpasses[i].pColorAttachments = params->colorAttachments->references; + subpasses[i].inputAttachmentCount = params->inputAttachments->size; + subpasses[i].pInputAttachments = params->inputAttachments->a; + subpasses[i].colorAttachmentCount = params->colorAttachments->size; + subpasses[i].pColorAttachments = params->colorAttachments->a; if (params->resolveAttachments) { - subpasses[i].pResolveAttachments = params->resolveAttachments->references; + subpasses[i].pResolveAttachments = params->resolveAttachments->a; } subpasses[i].pDepthStencilAttachment = params->depthStencilAttachment; subpasses[i].preserveAttachmentCount = params->numPreserve; @@ -92,56 +92,31 @@ QFV_CreateRenderPass (qfv_device_t *device, VkRenderPassCreateInfo createInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 0, 0, - attachments->numAttachments, attachments->attachments, - subpassparams->numSubpasses, subpasses, - dependencies->numDependencies, dependencies->dependencies, + attachments->size, attachments->a, + subpassparams->size, subpasses, + dependencies->size, dependencies->a, }; - qfv_renderpass_t *renderpass = malloc (sizeof (*renderpass)); - renderpass->device = device; - dfunc->vkCreateRenderPass (dev, &createInfo, 0, &renderpass->renderPass); + VkRenderPass renderpass; + dfunc->vkCreateRenderPass (dev, &createInfo, 0, &renderpass); return renderpass; } -qfv_framebuffer_t * -QFV_CreateFramebuffer (qfv_renderpass_t *renderPass, +VkFramebuffer +QFV_CreateFramebuffer (qfv_device_t *device, VkRenderPass renderPass, uint32_t numAttachments, VkImageView *attachments, uint32_t width, uint32_t height, uint32_t layers) { - qfv_device_t *device = renderPass->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; VkFramebufferCreateInfo createInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 0, 0, - renderPass->renderPass, numAttachments, attachments, + renderPass, numAttachments, attachments, width, height, layers, }; - qfv_framebuffer_t *framebuffer = malloc (sizeof (*framebuffer)); - framebuffer->device = device; - dfunc->vkCreateFramebuffer (dev, &createInfo, 0, &framebuffer->framebuffer); + VkFramebuffer framebuffer; + dfunc->vkCreateFramebuffer (dev, &createInfo, 0, &framebuffer); return framebuffer; } - -void -QFV_DestroyFramebuffer (qfv_framebuffer_t *framebuffer) -{ - qfv_device_t *device = framebuffer->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyFramebuffer (dev, framebuffer->framebuffer, 0); - free (framebuffer); -} - -void -QFV_DestroyRenderPass (qfv_renderpass_t *renderPass) -{ - qfv_device_t *device = renderPass->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyRenderPass (dev, renderPass->renderPass, 0); - free (renderPass); -} From 89d48b56507fa3546b06a131e0daaf2266c6f4b4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 18 Feb 2020 01:03:36 +0900 Subject: [PATCH 076/435] Output first pixels Just clearing the screen to 0xbada55, but the validation layer is quiet. --- include/QF/Vulkan/funclist.h | 1 + libs/video/renderer/vid_render_vulkan.c | 47 +++++++++++++++++++++++++ libs/video/renderer/vulkan/swapchain.c | 1 + 3 files changed, 49 insertions(+) diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 426b0fa62..8ab62852a 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -165,6 +165,7 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBeginRenderPass) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdNextSubpass) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdEndRenderPass) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindPipeline) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdClearColorImage) #undef DEVICE_LEVEL_VULKAN_FUNCTION diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 0373867de..fec8afa24 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -68,8 +68,55 @@ vulkan_R_Init (void) vulkan_ctx->frameset.cmdBuffers = cmdBuffers; VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + VkClearColorValue clearColor = { {0.7294, 0.8549, 0.3333, 1.0} }; + VkImageSubresourceRange image_subresource_range = { + VK_IMAGE_ASPECT_COLOR_BIT, + 0, 1, 0, 1, + }; + VkImageMemoryBarrier pc_barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_MEMORY_READ_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + device->queue.queueFamily, + device->queue.queueFamily, + 0, // filled in later + image_subresource_range + }; + VkImageMemoryBarrier cp_barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_MEMORY_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + device->queue.queueFamily, + device->queue.queueFamily, + 0, // filled in later + image_subresource_range + }; for (size_t i = 0; i < cmdBuffers->size; i++) { + pc_barrier.image = vulkan_ctx->swapchain->images->a[i]; + cp_barrier.image = vulkan_ctx->swapchain->images->a[i]; dfunc->vkBeginCommandBuffer (cmdBuffers->a[i], &beginInfo); + dfunc->vkCmdPipelineBarrier (cmdBuffers->a[i], + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, 0, // memory barriers + 0, 0, // buffer barriers + 1, &pc_barrier); + dfunc->vkCmdClearColorImage (cmdBuffers->a[i], pc_barrier.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &clearColor, 1, + &image_subresource_range); + dfunc->vkCmdPipelineBarrier (cmdBuffers->a[i], + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, + 0, 0, + 0, 0, + 1, &cp_barrier); dfunc->vkEndCommandBuffer (cmdBuffers->a[i]); } Sys_Printf ("R_Init %p %d", vulkan_ctx->swapchain->swapchain, diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c index 4ea0a36dc..b2007953a 100644 --- a/libs/video/renderer/vulkan/swapchain.c +++ b/libs/video/renderer/vulkan/swapchain.c @@ -83,6 +83,7 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) imageSize.width, imageSize.height); VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; imageUsage &= surfCaps.supportedUsageFlags; VkSurfaceTransformFlagBitsKHR surfTransform From 1f4c019abc0381d2120f5d4cf7be214899e90dd7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 18 Feb 2020 14:28:28 +0900 Subject: [PATCH 077/435] Create and destroy color/depth resources --- include/QF/Vulkan/image.h | 10 + include/QF/Vulkan/qf_vid.h | 2 + include/vid_vulkan.h | 8 + libs/video/renderer/vid_render_vulkan.c | 17 +- libs/video/renderer/vulkan/image.c | 10 + .../video/renderer/vulkan/vulkan_vid_common.c | 192 ++++++++++++++++++ 6 files changed, 235 insertions(+), 4 deletions(-) diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index 8db6ee632..edb5e025e 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -6,6 +6,13 @@ typedef struct qfv_imageset_s DARRAY_TYPE (VkImage) qfv_imageset_t; typedef struct qfv_imageviewset_s DARRAY_TYPE (VkImageView) qfv_imageviewset_t; +typedef struct qfv_imageresource_s { + struct qfv_device_s *device; + VkImage image; + VkDeviceMemory object; + VkImageView view; +} qfv_imageresource_t; + typedef struct qfv_imagetransition_s { VkImage image; VkAccessFlags srcAccess; @@ -37,6 +44,9 @@ VkDeviceMemory QFV_AllocImageMemory (struct qfv_device_s *device, VkMemoryPropertyFlags properties, VkDeviceSize size, VkDeviceSize offset); +int QFV_BindImageMemory (struct qfv_device_s *device, VkImage image, + VkDeviceMemory object, VkDeviceSize offset); + qfv_imagebarrierset_t * QFV_CreateImageTransitionSet (qfv_imagetransition_t *transitions, int numTransitions); diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index bfa543c46..26d9d288c 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -36,6 +36,8 @@ #include struct vulkan_ctx_s; +void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx); +void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx); void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx); void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx); void Vulkan_Init_Common (struct vulkan_ctx_s *ctx); diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 77718ab9c..a158f0a77 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -14,6 +14,11 @@ typedef struct vulkan_frameset_s { struct qfv_semaphoreset_s *renderDoneSemaphores; } vulkan_frameset_t; +typedef struct vulkan_renderpass_s { + struct qfv_imageresource_s *colorImage; + struct qfv_imageresource_s *depthImage; +} vulkan_renderpass_t; + typedef struct vulkan_ctx_s { void (*load_vulkan) (struct vulkan_ctx_s *ctx); void (*unload_vulkan) (struct vulkan_ctx_s *ctx); @@ -33,7 +38,10 @@ typedef struct vulkan_ctx_s { VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain VkCommandPool cmdpool; + VkCommandBuffer cmdbuffer; + VkFence fence; // for ctx->cmdbuffer only vulkan_frameset_t frameset; + vulkan_renderpass_t renderpass; #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index fec8afa24..5c0b602d0 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -63,6 +63,7 @@ vulkan_R_Init (void) qfv_cmdbufferset_t *cmdBuffers; Vulkan_CreateSwapchain (vulkan_ctx); + Vulkan_CreateRenderPass (vulkan_ctx); cmdBuffers = QFV_AllocateCommandBuffers (device, vulkan_ctx->cmdpool, 0, vulkan_ctx->swapchain->numImages); vulkan_ctx->frameset.cmdBuffers = cmdBuffers; @@ -139,7 +140,7 @@ vulkan_SCR_UpdateScreen (double time, void (*f)(void), void (**g)(void)) qfv_queue_t *queue = &vulkan_ctx->device->queue; vulkan_frameset_t *frameset = &vulkan_ctx->frameset; - dfunc->vkWaitForFences (dev, 1, & frameset->fences->a[frameset->curFrame], + dfunc->vkWaitForFences (dev, 1, &frameset->fences->a[frameset->curFrame], VK_TRUE, 2000000000); QFV_AcquireNextImage (vulkan_ctx->swapchain, frameset->imageSemaphores->a[frameset->curFrame], @@ -174,7 +175,8 @@ vulkan_SCR_UpdateScreen (double time, void (*f)(void), void (**g)(void)) double currenTime = Sys_DoubleTime (); double time = currenTime - startTime; startTime = currenTime; - printf ("%d frames in %g s: %g fps \r", count, time, count / time); + printf ("%d frames in %g s: %g fps \r", + count, time, count / time); fflush (stdout); count = 0; } @@ -291,7 +293,13 @@ vulkan_vid_render_choose_visual (void) vulkan_ctx->choose_visual (vulkan_ctx); vulkan_ctx->cmdpool = QFV_CreateCommandPool (vulkan_ctx->device, vulkan_ctx->device->queue.queueFamily, - 0, 0); + 0, 1); + __auto_type cmdset = QFV_AllocateCommandBuffers (vulkan_ctx->device, + vulkan_ctx->cmdpool, + 0, 1); + vulkan_ctx->cmdbuffer = cmdset->a[0]; + free (cmdset); + vulkan_ctx->fence = QFV_CreateFence (vulkan_ctx->device, 1); Sys_Printf ("vk choose visual %p %p %d %p\n", vulkan_ctx->device->dev, vulkan_ctx->device->queue.queue, vulkan_ctx->device->queue.queueFamily, @@ -309,7 +317,7 @@ vulkan_vid_render_create_context (void) qfv_semaphoreset_t *renderDoneSems = DARRAY_ALLOCFIXED (*renderDoneSems, 2, malloc); for (int i = 0; i < 2; i++) { - fences->a[i]= QFV_CreateFence (vulkan_ctx->device, 1); + fences->a[i] = QFV_CreateFence (vulkan_ctx->device, 1); imageSems->a[i] = QFV_CreateSemaphore (vulkan_ctx->device); renderDoneSems->a[i] = QFV_CreateSemaphore (vulkan_ctx->device); } @@ -348,6 +356,7 @@ vulkan_vid_render_shutdown (void) df->vkDestroySemaphore (dev, frameset->imageSemaphores->a[i], 0); df->vkDestroySemaphore (dev, frameset->renderDoneSemaphores->a[i], 0); } + df->vkDestroyFence (dev, vulkan_ctx->fence, 0); df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0); Vulkan_Shutdown_Common (vulkan_ctx); } diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index 65f0dcdd3..68decb94a 100644 --- a/libs/video/renderer/vulkan/image.c +++ b/libs/video/renderer/vulkan/image.c @@ -126,6 +126,16 @@ QFV_AllocImageMemory (qfv_device_t *device, return object; } +int +QFV_BindImageMemory (qfv_device_t *device, + VkImage image, VkDeviceMemory object, VkDeviceSize offset) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + VkResult res = dfunc->vkBindImageMemory (dev, image, object, offset); + return res == VK_SUCCESS; +} + qfv_imagebarrierset_t * QFV_CreateImageTransitionSet (qfv_imagetransition_t *transitions, int numTransitions) diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 37fe9c564..4d4160caf 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -51,6 +51,7 @@ #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" +#include "QF/Vulkan/image.h" #include "QF/Vulkan/swapchain.h" #include "compat.h" @@ -116,6 +117,9 @@ Vulkan_Init_Common (vulkan_ctx_t *ctx) void Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) { + if (ctx->renderpass.colorImage) { + Vulkan_DestroyRenderPass (ctx); + } if (ctx->swapchain) { QFV_DestroySwapchain (ctx->swapchain); } @@ -151,3 +155,191 @@ Vulkan_CreateSwapchain (vulkan_ctx_t *ctx) old_swapchain, 0); } } + +typedef struct { + VkPipelineStageFlags src; + VkPipelineStageFlags dst; +} qfv_pipelinestagepair_t; + +//XXX Note: imageLayoutTransitionBarriers, imageLayoutTransitionStages and +// the enum be kept in sync +enum { + qfv_LT_Undefined_to_TransferDst, + qfv_LT_TransferDst_to_ShaderReadOnly, + qfv_LT_Undefined_to_DepthStencil, + qfv_LT_Undefined_to_Color, +}; + +static VkImageMemoryBarrier imageLayoutTransitionBarriers[] = { + // undefined -> transfer dst optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }, + // transfer dst optimal -> shader read only optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }, + // undefined -> depth stencil attachment optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + 0, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT + | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1 } + }, + // undefined -> color attachment optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + 0, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT + | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }, + { /* end of transition barriers */ } +}; + +static qfv_pipelinestagepair_t imageLayoutTransitionStages[] = { + // undefined -> transfer dst optimal + { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT }, + // transfer dst optimal -> shader read only optimal + { VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT }, + // undefined -> depth stencil attachment optimal + { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT }, + // undefined -> color attachment optimal + { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }, +}; + +void +Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *df = device->funcs; + VkCommandBuffer cmd = ctx->cmdbuffer; + qfv_swapchain_t *sc = ctx->swapchain; + + qfv_imageresource_t *colorImage = malloc (sizeof (*colorImage)); + qfv_imageresource_t *depthImage = malloc (sizeof (*depthImage)); + + VkExtent3D extent = {sc->extent.width, sc->extent.height, 1}; + + Sys_MaskPrintf (SYS_VULKAN, "color resource\n"); + colorImage->image + = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, + sc->format, extent, 1, 1, + VK_SAMPLE_COUNT_1_BIT, // FIXME + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT + | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + colorImage->object + = QFV_AllocImageMemory (device, colorImage->image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); + QFV_BindImageMemory (device, colorImage->image, colorImage->object, 0); + colorImage->view + = QFV_CreateImageView (device, colorImage->image, + VK_IMAGE_VIEW_TYPE_2D, + sc->format, VK_IMAGE_ASPECT_COLOR_BIT); + Sys_MaskPrintf (SYS_VULKAN, " image: %p object: %p view:%p\n", + colorImage->image, colorImage->object, colorImage->view); + + Sys_MaskPrintf (SYS_VULKAN, "depth resource\n"); + VkFormat depthFormat = VK_FORMAT_D32_SFLOAT; + depthImage->image + = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, + depthFormat, extent, 1, 1, + VK_SAMPLE_COUNT_1_BIT, // FIXME (for depth?!?) + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + depthImage->object + = QFV_AllocImageMemory (device, depthImage->image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); + QFV_BindImageMemory (device, depthImage->image, depthImage->object, 0); + depthImage->view + = QFV_CreateImageView (device, depthImage->image, + VK_IMAGE_VIEW_TYPE_2D, + depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT); + Sys_MaskPrintf (SYS_VULKAN, " image: %p object: %p view:%p\n", + depthImage->image, depthImage->object, depthImage->view); + + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + + df->vkWaitForFences (dev, 1, &ctx->fence, VK_TRUE, ~0ul); + df->vkResetCommandBuffer (cmd, 0); + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0, + }; + df->vkBeginCommandBuffer (cmd, &beginInfo); + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_Color]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_Color]; + barrier.image = colorImage->image; + + df->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, + 0, 0, + 0, 0, + 1, &barrier); + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_DepthStencil]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_DepthStencil]; + barrier.image = depthImage->image; + if (depthFormat == VK_FORMAT_D32_SFLOAT_S8_UINT + || depthFormat == VK_FORMAT_D24_UNORM_S8_UINT) { + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + + df->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, + 0, 0, + 0, 0, + 1, &barrier); + df->vkEndCommandBuffer (cmd); + + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, + 0, 0, 0, + 1, &cmd, + 0, 0 + }; + df->vkResetFences (dev, 1, &ctx->fence); + df->vkQueueSubmit (device->queue.queue, 1, &submitInfo, ctx->fence); + + ctx->renderpass.colorImage = colorImage; + ctx->renderpass.depthImage = depthImage; +} + +void +Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + VkDevice dev = device->dev; + qfv_devfuncs_t *df = device->funcs; + + df->vkDestroyImageView (dev, ctx->renderpass.colorImage->view, 0); + df->vkDestroyImage (dev, ctx->renderpass.colorImage->image, 0); + df->vkFreeMemory (dev, ctx->renderpass.colorImage->object, 0); + free (ctx->renderpass.colorImage); + ctx->renderpass.colorImage = 0; + + df->vkDestroyImageView (dev, ctx->renderpass.depthImage->view, 0); + df->vkDestroyImage (dev, ctx->renderpass.depthImage->image, 0); + df->vkFreeMemory (dev, ctx->renderpass.depthImage->object, 0); + free (ctx->renderpass.depthImage); + ctx->renderpass.depthImage = 0; +} From ba654b09f7dbe9dbe8b9d1d9311785df9fcbd5f1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 18 Feb 2020 17:18:37 +0900 Subject: [PATCH 078/435] Create and destroy render pass and frame buffers --- include/QF/Vulkan/instance.h | 2 + include/QF/Vulkan/qf_vid.h | 2 + include/QF/Vulkan/renderpass.h | 14 +- include/QF/darray.h | 19 +++ include/vid_vulkan.h | 23 +-- libs/video/renderer/vid_render_vulkan.c | 66 +++------ libs/video/renderer/vulkan/instance.c | 15 ++ libs/video/renderer/vulkan/renderpass.c | 25 +--- .../video/renderer/vulkan/vulkan_vid_common.c | 135 +++++++++++++++++- 9 files changed, 212 insertions(+), 89 deletions(-) diff --git a/include/QF/Vulkan/instance.h b/include/QF/Vulkan/instance.h index 0cf5b2226..4df1827c5 100644 --- a/include/QF/Vulkan/instance.h +++ b/include/QF/Vulkan/instance.h @@ -62,4 +62,6 @@ qfv_instance_t *QFV_CreateInstance (struct vulkan_ctx_s *ctx, const char **extensions); void QFV_DestroyInstance (qfv_instance_t *instance); +VkSampleCountFlagBits QFV_GetMaxSampleCount (qfv_physdev_t *physdev); + #endif // __QF_Vulkan_instance_h diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index 26d9d288c..d7ef64a97 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -36,6 +36,8 @@ #include struct vulkan_ctx_s; +void Vulkan_DestroyFramebuffers (struct vulkan_ctx_s *ctx); +void Vulkan_CreateFramebuffers (struct vulkan_ctx_s *ctx); void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx); void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx); void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx); diff --git a/include/QF/Vulkan/renderpass.h b/include/QF/Vulkan/renderpass.h index 257441ca1..9a197ac70 100644 --- a/include/QF/Vulkan/renderpass.h +++ b/include/QF/Vulkan/renderpass.h @@ -15,18 +15,8 @@ typedef struct qfv_attachmentreference_s #define QFV_AllocAttachmentReference(num, allocator) \ DARRAY_ALLOCFIXED (qfv_attachmentreference_t, num, allocator) -typedef struct qfv_subpassparameters_s { - VkPipelineBindPoint pipelineBindPoint; - qfv_attachmentreference_t *inputAttachments; - qfv_attachmentreference_t *colorAttachments; - qfv_attachmentreference_t *resolveAttachments; - VkAttachmentReference *depthStencilAttachment; - uint32_t numPreserve; - uint32_t *preserveAttachments; -} qfv_subpassparameters_t; - typedef struct qfv_subpassparametersset_s - DARRAY_TYPE (qfv_subpassparameters_t) qfv_subpassparametersset_t; + DARRAY_TYPE (VkSubpassDescription) qfv_subpassparametersset_t; #define QFV_AllocSubpassParametersSet(num, allocator) \ DARRAY_ALLOCFIXED (qfv_subpassparametersset_t, num, allocator) @@ -49,6 +39,6 @@ QFV_CreateFramebuffer (struct qfv_device_s *device, VkRenderPass renderPass, uint32_t numAttachments, VkImageView *attachments, - uint32_t width, uint32_t height, uint32_t layers); + VkExtent2D, uint32_t layers); #endif//__QF_Vulkan_renderpass_h diff --git a/include/QF/darray.h b/include/QF/darray.h index 7a4484575..9f8c9630b 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -88,6 +88,25 @@ ar; \ }) +/** Initialized the array. + + The array will be initialized to be empty but with grow set to the + specifed value. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param growSize Number of elements by which the array is to grow when + required. + \hideinitializer +*/ +#define DARRAY_INIT(array, growSize) \ + do { \ + __auto_type ar = (array); \ + ar->size = ar->maxSize = 0; \ + ar->grow = (growSize); \ + } while (0) + /** Clear the array. If the array can grow, its backing will be freed and maxSize and a reset, diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index a158f0a77..2675d3036 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -6,19 +6,25 @@ #endif #include -typedef struct vulkan_frameset_s { - int curFrame; // index into fences - struct qfv_fenceset_s *fences; - struct qfv_cmdbufferset_s *cmdBuffers; - struct qfv_semaphoreset_s *imageSemaphores; - struct qfv_semaphoreset_s *renderDoneSemaphores; -} vulkan_frameset_t; +#include "QF/darray.h" typedef struct vulkan_renderpass_s { + VkRenderPass renderpass; struct qfv_imageresource_s *colorImage; struct qfv_imageresource_s *depthImage; } vulkan_renderpass_t; +typedef struct vulkan_framebuffer_s { + VkFramebuffer framebuffer; + VkFence fence; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderDoneSemaphore; + VkCommandBuffer cmdBuffer; +} vulkan_framebuffer_t; + +typedef struct vulkan_framebufferset_s + DARRAY_TYPE (vulkan_framebuffer_t) vulkan_framebufferset_t; + typedef struct vulkan_ctx_s { void (*load_vulkan) (struct vulkan_ctx_s *ctx); void (*unload_vulkan) (struct vulkan_ctx_s *ctx); @@ -40,8 +46,9 @@ typedef struct vulkan_ctx_s { VkCommandPool cmdpool; VkCommandBuffer cmdbuffer; VkFence fence; // for ctx->cmdbuffer only - vulkan_frameset_t frameset; vulkan_renderpass_t renderpass; + size_t curFrame; + vulkan_framebufferset_t framebuffers; #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 5c0b602d0..ce6863753 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -60,13 +60,11 @@ vulkan_R_Init (void) { qfv_device_t *device = vulkan_ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - qfv_cmdbufferset_t *cmdBuffers; Vulkan_CreateSwapchain (vulkan_ctx); Vulkan_CreateRenderPass (vulkan_ctx); - cmdBuffers = QFV_AllocateCommandBuffers (device, vulkan_ctx->cmdpool, 0, - vulkan_ctx->swapchain->numImages); - vulkan_ctx->frameset.cmdBuffers = cmdBuffers; + Vulkan_CreateFramebuffers (vulkan_ctx); + VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; VkClearColorValue clearColor = { {0.7294, 0.8549, 0.3333, 1.0} }; @@ -96,29 +94,30 @@ vulkan_R_Init (void) 0, // filled in later image_subresource_range }; - for (size_t i = 0; i < cmdBuffers->size; i++) { + for (size_t i = 0; i < vulkan_ctx->framebuffers.size; i++) { + __auto_type framebuffer = &vulkan_ctx->framebuffers.a[i]; pc_barrier.image = vulkan_ctx->swapchain->images->a[i]; cp_barrier.image = vulkan_ctx->swapchain->images->a[i]; - dfunc->vkBeginCommandBuffer (cmdBuffers->a[i], &beginInfo); - dfunc->vkCmdPipelineBarrier (cmdBuffers->a[i], + dfunc->vkBeginCommandBuffer (framebuffer->cmdBuffer, &beginInfo); + dfunc->vkCmdPipelineBarrier (framebuffer->cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, // memory barriers 0, 0, // buffer barriers 1, &pc_barrier); - dfunc->vkCmdClearColorImage (cmdBuffers->a[i], pc_barrier.image, + dfunc->vkCmdClearColorImage (framebuffer->cmdBuffer, pc_barrier.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &image_subresource_range); - dfunc->vkCmdPipelineBarrier (cmdBuffers->a[i], + dfunc->vkCmdPipelineBarrier (framebuffer->cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, 0, 0, 0, 1, &cp_barrier); - dfunc->vkEndCommandBuffer (cmdBuffers->a[i]); + dfunc->vkEndCommandBuffer (framebuffer->cmdBuffer); } Sys_Printf ("R_Init %p %d", vulkan_ctx->swapchain->swapchain, vulkan_ctx->swapchain->numImages); @@ -138,38 +137,38 @@ vulkan_SCR_UpdateScreen (double time, void (*f)(void), void (**g)(void)) qfv_devfuncs_t *dfunc = device->funcs; VkDevice dev = device->dev; qfv_queue_t *queue = &vulkan_ctx->device->queue; - vulkan_frameset_t *frameset = &vulkan_ctx->frameset; - dfunc->vkWaitForFences (dev, 1, &frameset->fences->a[frameset->curFrame], - VK_TRUE, 2000000000); + __auto_type framebuffer + = &vulkan_ctx->framebuffers.a[vulkan_ctx->curFrame]; + + dfunc->vkWaitForFences (dev, 1, &framebuffer->fence, VK_TRUE, 2000000000); QFV_AcquireNextImage (vulkan_ctx->swapchain, - frameset->imageSemaphores->a[frameset->curFrame], - 0, &imageIndex); + framebuffer->imageAvailableSemaphore, + 0, &imageIndex); VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, 1, - &frameset->imageSemaphores->a[frameset->curFrame], + &framebuffer->imageAvailableSemaphore, &waitStage, - 1, &frameset->cmdBuffers->a[imageIndex], - 1, &frameset->renderDoneSemaphores->a[frameset->curFrame], + 1, &framebuffer->cmdBuffer, + 1, &framebuffer->renderDoneSemaphore, }; - dfunc->vkResetFences (dev, 1, &frameset->fences->a[frameset->curFrame]); - dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, - frameset->fences->a[frameset->curFrame]); + dfunc->vkResetFences (dev, 1, &framebuffer->fence); + dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, framebuffer->fence); VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 0, - 1, &frameset->renderDoneSemaphores->a[frameset->curFrame], + 1, &framebuffer->renderDoneSemaphore, 1, &vulkan_ctx->swapchain->swapchain, &imageIndex, 0 }; dfunc->vkQueuePresentKHR (queue->queue, &presentInfo); - frameset->curFrame++; - frameset->curFrame %= frameset->fences->size; + vulkan_ctx->curFrame++; + vulkan_ctx->curFrame %= vulkan_ctx->framebuffers.size; if (++count >= 100) { double currenTime = Sys_DoubleTime (); @@ -311,19 +310,6 @@ vulkan_vid_render_create_context (void) { vulkan_ctx->create_window (vulkan_ctx); vulkan_ctx->surface = vulkan_ctx->create_surface (vulkan_ctx); - vulkan_ctx->frameset.curFrame = 0; - qfv_fenceset_t *fences = DARRAY_ALLOCFIXED (*fences, 2, malloc); - qfv_semaphoreset_t *imageSems = DARRAY_ALLOCFIXED (*imageSems, 2, malloc); - qfv_semaphoreset_t *renderDoneSems = DARRAY_ALLOCFIXED (*renderDoneSems, 2, - malloc); - for (int i = 0; i < 2; i++) { - fences->a[i] = QFV_CreateFence (vulkan_ctx->device, 1); - imageSems->a[i] = QFV_CreateSemaphore (vulkan_ctx->device); - renderDoneSems->a[i] = QFV_CreateSemaphore (vulkan_ctx->device); - } - vulkan_ctx->frameset.fences = fences; - vulkan_ctx->frameset.imageSemaphores = imageSems; - vulkan_ctx->frameset.renderDoneSemaphores = renderDoneSems; Sys_Printf ("vk create context %p\n", vulkan_ctx->surface); } @@ -350,12 +336,6 @@ vulkan_vid_render_shutdown (void) qfv_devfuncs_t *df = device->funcs; VkDevice dev = device->dev; QFV_DeviceWaitIdle (device); - vulkan_frameset_t *frameset = &vulkan_ctx->frameset; - for (size_t i = 0; i < frameset->fences->size; i++) { - df->vkDestroyFence (dev, frameset->fences->a[i], 0); - df->vkDestroySemaphore (dev, frameset->imageSemaphores->a[i], 0); - df->vkDestroySemaphore (dev, frameset->renderDoneSemaphores->a[i], 0); - } df->vkDestroyFence (dev, vulkan_ctx->fence, 0); df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0); Vulkan_Shutdown_Common (vulkan_ctx); diff --git a/libs/video/renderer/vulkan/instance.c b/libs/video/renderer/vulkan/instance.c index 234236014..4d23b5a75 100644 --- a/libs/video/renderer/vulkan/instance.c +++ b/libs/video/renderer/vulkan/instance.c @@ -36,6 +36,7 @@ #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/input.h" +#include "QF/mathlib.h" #include "QF/qargs.h" #include "QF/quakefs.h" #include "QF/sys.h" @@ -284,3 +285,17 @@ QFV_DestroyInstance (qfv_instance_t *instance) instance->funcs->vkDestroyInstance (instance->instance, 0); free (instance); } + +VkSampleCountFlagBits +QFV_GetMaxSampleCount (qfv_physdev_t *physdev) +{ + VkSampleCountFlagBits maxSamples = VK_SAMPLE_COUNT_64_BIT; + VkSampleCountFlagBits counts; + counts = min (physdev->properties.limits.framebufferColorSampleCounts, + physdev->properties.limits.framebufferDepthSampleCounts); + while (maxSamples && maxSamples > counts) { + maxSamples >>= 1; + } + Sys_MaskPrintf (SYS_VULKAN, "Max samples: %x\n", maxSamples); + return maxSamples; +} diff --git a/libs/video/renderer/vulkan/renderpass.c b/libs/video/renderer/vulkan/renderpass.c index 60e279e18..e61005278 100644 --- a/libs/video/renderer/vulkan/renderpass.c +++ b/libs/video/renderer/vulkan/renderpass.c @@ -71,29 +71,10 @@ QFV_CreateRenderPass (qfv_device_t *device, VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - VkSubpassDescription *subpasses = alloca (subpassparams->size - * sizeof (*subpasses)); - - for (uint32_t i = 0; i < subpassparams->size; i++) { - qfv_subpassparameters_t *params = &subpassparams->a[i]; - subpasses[i].flags = 0; - subpasses[i].pipelineBindPoint = params->pipelineBindPoint; - subpasses[i].inputAttachmentCount = params->inputAttachments->size; - subpasses[i].pInputAttachments = params->inputAttachments->a; - subpasses[i].colorAttachmentCount = params->colorAttachments->size; - subpasses[i].pColorAttachments = params->colorAttachments->a; - if (params->resolveAttachments) { - subpasses[i].pResolveAttachments = params->resolveAttachments->a; - } - subpasses[i].pDepthStencilAttachment = params->depthStencilAttachment; - subpasses[i].preserveAttachmentCount = params->numPreserve; - subpasses[i].pPreserveAttachments = params->preserveAttachments; - } - VkRenderPassCreateInfo createInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 0, 0, attachments->size, attachments->a, - subpassparams->size, subpasses, + subpassparams->size, subpassparams->a, dependencies->size, dependencies->a, }; @@ -105,7 +86,7 @@ QFV_CreateRenderPass (qfv_device_t *device, VkFramebuffer QFV_CreateFramebuffer (qfv_device_t *device, VkRenderPass renderPass, uint32_t numAttachments, VkImageView *attachments, - uint32_t width, uint32_t height, uint32_t layers) + VkExtent2D extent, uint32_t layers) { VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; @@ -113,7 +94,7 @@ QFV_CreateFramebuffer (qfv_device_t *device, VkRenderPass renderPass, VkFramebufferCreateInfo createInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 0, 0, renderPass, numAttachments, attachments, - width, height, layers, + extent.width, extent.height, layers, }; VkFramebuffer framebuffer; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 4d4160caf..151f6ea55 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -50,8 +50,10 @@ #include "QF/vid.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/device.h" +#include "QF/Vulkan/command.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/image.h" +#include "QF/Vulkan/renderpass.h" #include "QF/Vulkan/swapchain.h" #include "compat.h" @@ -117,6 +119,9 @@ Vulkan_Init_Common (vulkan_ctx_t *ctx) void Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) { + if (ctx->framebuffers.size) { + Vulkan_DestroyFramebuffers (ctx); + } if (ctx->renderpass.colorImage) { Vulkan_DestroyRenderPass (ctx); } @@ -241,11 +246,13 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) VkExtent3D extent = {sc->extent.width, sc->extent.height, 1}; + VkSampleCountFlagBits msaaSamples + = QFV_GetMaxSampleCount (device->physDev); + Sys_MaskPrintf (SYS_VULKAN, "color resource\n"); colorImage->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, - sc->format, extent, 1, 1, - VK_SAMPLE_COUNT_1_BIT, // FIXME + sc->format, extent, 1, 1, msaaSamples, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); colorImage->object @@ -263,8 +270,7 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) VkFormat depthFormat = VK_FORMAT_D32_SFLOAT; depthImage->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, - depthFormat, extent, 1, 1, - VK_SAMPLE_COUNT_1_BIT, // FIXME (for depth?!?) + depthFormat, extent, 1, 1, msaaSamples, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); depthImage->object = QFV_AllocImageMemory (device, depthImage->image, @@ -322,6 +328,72 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) ctx->renderpass.colorImage = colorImage; ctx->renderpass.depthImage = depthImage; + + __auto_type attachments = QFV_AllocAttachmentDescription (3, alloca); + __auto_type attachmentRefs = QFV_AllocAttachmentReference (3, alloca); + + // color attachment + attachments->a[0].flags = 0; + attachments->a[0].format = sc->format; + attachments->a[0].samples = msaaSamples; + attachments->a[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments->a[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments->a[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments->a[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments->a[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachments->a[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachmentRefs->a[0].attachment = 0; + attachmentRefs->a[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + // depth attachment + attachments->a[1].flags = 0; + attachments->a[1].format = depthFormat; + attachments->a[1].samples = msaaSamples; + attachments->a[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments->a[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments->a[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments->a[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments->a[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachments->a[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachmentRefs->a[1].attachment = 1; + attachmentRefs->a[1].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + // resolve attachment + attachments->a[2].flags = 0; + attachments->a[2].format = sc->format; + attachments->a[2].samples = VK_SAMPLE_COUNT_1_BIT; + attachments->a[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments->a[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments->a[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments->a[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments->a[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachments->a[2].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + attachmentRefs->a[2].attachment = 2; + attachmentRefs->a[2].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + __auto_type subpasses = QFV_AllocSubpassParametersSet (1, alloca); + subpasses->a[0].flags = 0; + subpasses->a[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpasses->a[0].inputAttachmentCount = 0; + subpasses->a[0].pInputAttachments = 0; + subpasses->a[0].colorAttachmentCount = 1; + subpasses->a[0].pColorAttachments = &attachmentRefs->a[0]; + subpasses->a[0].pResolveAttachments = &attachmentRefs->a[2]; + subpasses->a[0].pDepthStencilAttachment = &attachmentRefs->a[1]; + subpasses->a[0].preserveAttachmentCount = 0; + subpasses->a[0].pPreserveAttachments = 0; + + __auto_type depenencies = QFV_AllocSubpassDependencies (1, alloca); + depenencies->a[0].srcSubpass = VK_SUBPASS_EXTERNAL; + depenencies->a[0].dstSubpass = 0; + depenencies->a[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + depenencies->a[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + depenencies->a[0].srcAccessMask = 0; + depenencies->a[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + depenencies->a[0].dependencyFlags = 0; + + ctx->renderpass.renderpass = QFV_CreateRenderPass (device, attachments, + subpasses, depenencies); } void @@ -331,6 +403,8 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) VkDevice dev = device->dev; qfv_devfuncs_t *df = device->funcs; + df->vkDestroyRenderPass (dev, ctx->renderpass.renderpass, 0); + df->vkDestroyImageView (dev, ctx->renderpass.colorImage->view, 0); df->vkDestroyImage (dev, ctx->renderpass.colorImage->image, 0); df->vkFreeMemory (dev, ctx->renderpass.colorImage->object, 0); @@ -343,3 +417,56 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) free (ctx->renderpass.depthImage); ctx->renderpass.depthImage = 0; } + +void +Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + VkCommandPool cmdpool = ctx->cmdpool; + qfv_swapchain_t *sc = ctx->swapchain; + VkRenderPass renderpass = ctx->renderpass.renderpass; + + if (!ctx->framebuffers.grow) { + DARRAY_INIT (&ctx->framebuffers, 4); + } + + DARRAY_RESIZE (&ctx->framebuffers, sc->numImages); + + __auto_type attachments = DARRAY_ALLOCFIXED (qfv_imageviewset_t, 3, + alloca); + attachments->a[0] = ctx->renderpass.colorImage->view; + attachments->a[1] = ctx->renderpass.depthImage->view; + + __auto_type cmdBuffers + = QFV_AllocateCommandBuffers (device, cmdpool, 0, + ctx->framebuffers.size); + + for (size_t i = 0; i < ctx->framebuffers.size; i++) { + attachments->a[2] = sc->imageViews->a[i]; + __auto_type frame = &ctx->framebuffers.a[i]; + frame->framebuffer = QFV_CreateFramebuffer (device, renderpass, + attachments->size, + attachments->a, + sc->extent, 1); + frame->fence = QFV_CreateFence (device, 1); + frame->imageAvailableSemaphore = QFV_CreateSemaphore (device); + frame->renderDoneSemaphore = QFV_CreateSemaphore (device); + frame->cmdBuffer = cmdBuffers->a[i]; + } +} + +void +Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *df = device->funcs; + VkDevice dev = device->dev; + + for (size_t i = 0; i < ctx->framebuffers.size; i++) { + __auto_type frame = &ctx->framebuffers.a[i]; + df->vkDestroyFence (dev, frame->fence, 0); + df->vkDestroySemaphore (dev, frame->imageAvailableSemaphore, 0); + df->vkDestroySemaphore (dev, frame->renderDoneSemaphore, 0); + df->vkDestroyFramebuffer (dev, frame->framebuffer, 0); + } +} From 0a0035e5e5e7771e28563684dbea1d34f2043e55 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 18 Feb 2020 17:48:22 +0900 Subject: [PATCH 079/435] Use the render pass to clear the window Very satisfying to get to this point. --- libs/video/renderer/vid_render_vulkan.c | 63 +++++-------------- .../video/renderer/vulkan/vulkan_vid_common.c | 4 +- 2 files changed, 20 insertions(+), 47 deletions(-) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index ce6863753..85181547c 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -65,58 +65,29 @@ vulkan_R_Init (void) Vulkan_CreateRenderPass (vulkan_ctx); Vulkan_CreateFramebuffers (vulkan_ctx); + qfv_swapchain_t *sc = vulkan_ctx->swapchain; + VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - VkClearColorValue clearColor = { {0.7294, 0.8549, 0.3333, 1.0} }; - VkImageSubresourceRange image_subresource_range = { - VK_IMAGE_ASPECT_COLOR_BIT, - 0, 1, 0, 1, + VkClearValue clearValues[3] = { + { { {0.7294, 0.8549, 0.3333, 1.0} } }, + { { {1.0, 0.0} } }, + { { {0, 0, 0, 0} } }, + }; + VkRenderPassBeginInfo renderPassInfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 0, + vulkan_ctx->renderpass.renderpass, 0, + { {0, 0}, sc->extent }, + 2, clearValues }; - VkImageMemoryBarrier pc_barrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_MEMORY_READ_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - device->queue.queueFamily, - device->queue.queueFamily, - 0, // filled in later - image_subresource_range - }; - VkImageMemoryBarrier cp_barrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_MEMORY_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - device->queue.queueFamily, - device->queue.queueFamily, - 0, // filled in later - image_subresource_range - }; for (size_t i = 0; i < vulkan_ctx->framebuffers.size; i++) { __auto_type framebuffer = &vulkan_ctx->framebuffers.a[i]; - pc_barrier.image = vulkan_ctx->swapchain->images->a[i]; - cp_barrier.image = vulkan_ctx->swapchain->images->a[i]; dfunc->vkBeginCommandBuffer (framebuffer->cmdBuffer, &beginInfo); - dfunc->vkCmdPipelineBarrier (framebuffer->cmdBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, 0, // memory barriers - 0, 0, // buffer barriers - 1, &pc_barrier); - dfunc->vkCmdClearColorImage (framebuffer->cmdBuffer, pc_barrier.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - &clearColor, 1, - &image_subresource_range); - dfunc->vkCmdPipelineBarrier (framebuffer->cmdBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - 0, - 0, 0, - 0, 0, - 1, &cp_barrier); + renderPassInfo.framebuffer = framebuffer->framebuffer; + dfunc->vkCmdBeginRenderPass (framebuffer->cmdBuffer, &renderPassInfo, + VK_SUBPASS_CONTENTS_INLINE); + + dfunc->vkCmdEndRenderPass (framebuffer->cmdBuffer); dfunc->vkEndCommandBuffer (framebuffer->cmdBuffer); } Sys_Printf ("R_Init %p %d", vulkan_ctx->swapchain->swapchain, diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 151f6ea55..882aede78 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -362,7 +362,7 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) attachments->a[2].flags = 0; attachments->a[2].format = sc->format; attachments->a[2].samples = VK_SAMPLE_COUNT_1_BIT; - attachments->a[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments->a[2].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachments->a[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachments->a[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachments->a[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; @@ -469,4 +469,6 @@ Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx) df->vkDestroySemaphore (dev, frame->renderDoneSemaphore, 0); df->vkDestroyFramebuffer (dev, frame->framebuffer, 0); } + + DARRAY_CLEAR (&ctx->framebuffers); } From c740dea2120d24723c97efc84f80e5fd43a40427 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 18 Feb 2020 19:44:40 +0900 Subject: [PATCH 080/435] Use the correct constant for "infinity" --- libs/video/renderer/vulkan/vulkan_vid_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 882aede78..452a74eb8 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -286,7 +286,7 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) VkImageMemoryBarrier barrier; qfv_pipelinestagepair_t stages; - df->vkWaitForFences (dev, 1, &ctx->fence, VK_TRUE, ~0ul); + df->vkWaitForFences (dev, 1, &ctx->fence, VK_TRUE, ~0ull); df->vkResetCommandBuffer (cmd, 0); VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, From 264c4ccdacff051bffca85f1a97e5ca0907b048c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 18 Feb 2020 21:18:03 +0900 Subject: [PATCH 081/435] Sanitize descriptors I'm sure it will end soon, I think pipelines is the end of it. --- include/QF/Vulkan/descriptor.h | 144 +++++------------- libs/video/renderer/vulkan/descriptor.c | 193 +++--------------------- libs/video/renderer/vulkan/pipeline.c | 12 +- 3 files changed, 63 insertions(+), 286 deletions(-) diff --git a/include/QF/Vulkan/descriptor.h b/include/QF/Vulkan/descriptor.h index 48a1cd92d..6dd09bff4 100644 --- a/include/QF/Vulkan/descriptor.h +++ b/include/QF/Vulkan/descriptor.h @@ -1,132 +1,62 @@ #ifndef __QF_Vulkan_descriptor_h #define __QF_Vulkan_descriptor_h -typedef struct qfv_sampler_s { - struct qfv_device_s *device; - VkSampler sampler; -} qfv_sampler_t; +#include "QF/darray.h" -typedef struct qfv_bindingset_s { - int numBindings; - VkDescriptorSetLayoutBinding bindings[]; -} qfv_bindingset_t; +typedef struct qfv_bindingset_s + DARRAY_TYPE (VkDescriptorSetLayoutBinding) qfv_bindingset_t; -typedef struct qfv_descriptorsetlayout_s { - struct qfv_device_s *device; - VkDescriptorSetLayout layout; -} qfv_descriptorsetlayout_t; - -typedef struct qfv_descriptorsetlayoutset_s { - uint32_t numLayouts; - qfv_descriptorsetlayout_t *layouts[]; -} qfv_descriptorsetlayoutset_t; +typedef struct qfv_descriptorsetlayoutset_s + DARRAY_TYPE (VkDescriptorSetLayout) qfv_descriptorsetlayoutset_t; #define QFV_AllocDescriptorSetLayoutSet(num, allocator) \ - allocator (field_offset (qfv_descriptorsetlayoutset_t, layouts[num])) + DARRAY_ALLOCFIXED (qfv_descriptorsetlayoutset_t, num, allocator) +typedef struct qfv_descriptorsets_s + DARRAY_TYPE (VkDescriptorSet) qfv_descriptorsets_t; -typedef struct qfv_descriptorpool_s { - struct qfv_device_s *device; - VkDescriptorPool pool; -} qfv_descriptorpool_t; +#define QFV_AllocDescriptorSets(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_descriptorsets_t, num, allocator) -typedef struct qfv_descriptorset_s { - struct qfv_device_s *device; - qfv_descriptorpool_t *pool; - VkDescriptorSet set; -} qfv_descriptorset_t; +typedef struct qfv_writedescriptorsets_s + DARRAY_TYPE (VkWriteDescriptorSet) qfv_writedescriptorsets_t; -typedef struct qfv_imagedescriptorinfo_s { - qfv_descriptorset_t *descriptorset; - uint32_t binding; - uint32_t arrayElement; - VkDescriptorType type; - uint32_t numInfo; - VkDescriptorImageInfo infos[]; -} qfv_imagedescriptorinfo_t; +#define QFV_AllocWriteDescriptorSets(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_writedescriptorsets_t, num, allocator) -typedef struct qfv_bufferdescriptorinfo_s { - qfv_descriptorset_t *descriptorset; - uint32_t binding; - uint32_t arrayElement; - VkDescriptorType type; - uint32_t numInfo; - VkDescriptorBufferInfo infos[]; -} qfv_bufferdescriptorinfo_t; +typedef struct qfv_copydescriptorsets_s + DARRAY_TYPE (VkCopyDescriptorSet) qfv_copydescriptorsets_t; -typedef struct qfv_texelbufferdescriptorinfo_s { - qfv_descriptorset_t *descriptorset; - uint32_t binding; - uint32_t arrayElement; - VkDescriptorType type; - uint32_t numInfo; - VkBufferView infos[]; -} qfv_texelbufferdescriptorinfo_t; +#define QFV_AllocCopyDescriptorSets(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_descriptorsetlayoutset_t, num, allocator) -typedef struct qfv_copydescriptorinfo_s { - qfv_descriptorset_t *dstSet; - uint32_t dstBinding; - uint32_t dstArrayElement; - qfv_descriptorset_t *srcSet; - uint32_t srcBinding; - uint32_t srcArrayElement; - uint32_t descriptorCount; -} qfv_copydescriptorinfo_t; +struct qfv_device_s; -qfv_sampler_t *QFV_CreateSampler (struct qfv_device_s *device, - VkFilter magFilter, VkFilter minFilter, - VkSamplerMipmapMode mipmapMode, - VkSamplerAddressMode addressModeU, - VkSamplerAddressMode addressModeV, - VkSamplerAddressMode addressModeW, - float mipLodBias, - VkBool32 anisotryEnable, float maxAnisotropy, - VkBool32 compareEnable, VkCompareOp compareOp, - float minLod, float maxLod, - VkBorderColor borderColor, - VkBool32 unnormalizedCoordinates); +VkSampler QFV_CreateSampler (struct qfv_device_s *device, + VkFilter magFilter, VkFilter minFilter, + VkSamplerMipmapMode mipmapMode, + VkSamplerAddressMode addressModeU, + VkSamplerAddressMode addressModeV, + VkSamplerAddressMode addressModeW, + float mipLodBias, + VkBool32 anisotryEnable, float maxAnisotropy, + VkBool32 compareEnable, VkCompareOp compareOp, + float minLod, float maxLod, + VkBorderColor borderColor, + VkBool32 unnormalizedCoordinates); -qfv_bindingset_t *QFV_CreateBindingSet (int numBindings); -void QFV_DestroyBindingSet (qfv_bindingset_t *bindingset); - -qfv_descriptorsetlayout_t * +VkDescriptorSetLayout QFV_CreateDescriptorSetLayout (struct qfv_device_s *device, qfv_bindingset_t *bindings); -qfv_descriptorpool_t * +VkDescriptorPool QFV_CreateDescriptorPool (struct qfv_device_s *device, VkDescriptorPoolCreateFlags flags, uint32_t maxSets, qfv_bindingset_t *bindings); -qfv_descriptorset_t * -QFV_AllocateDescriptorSet (qfv_descriptorpool_t *pool, - qfv_descriptorsetlayout_t *layout); - -#define QFV_allocateinfo(type, num, allocator) \ - allocator (field_offset (type, infos[num])) -#define QFV_ImageDescriptorInfo(num, allocator) \ - QFV_allocateinfo(qfv_imagedescriptorinfo_t, num, allocator) -#define QFV_BufferDescriptorInfo(num, allocator) \ - QFV_allocateinfo(qfv_bufferdescriptorinfo_t, num, allocator) -#define QFV_TexelBufferDescriptorInfo(num, allocator) \ - QFV_allocateinfo(qfv_texelbufferdescriptorinfo_t, num, allocator) - -void -QFV_UpdateDescriptorSets (struct qfv_device_s *device, - uint32_t numImageInfos, - qfv_imagedescriptorinfo_t *imageInfos, - uint32_t numBufferInfos, - qfv_bufferdescriptorinfo_t *bufferInfos, - uint32_t numTexelBufferInfos, - qfv_texelbufferdescriptorinfo_t *texelbufferInfos, - uint32_t numCopyInfos, - qfv_copydescriptorinfo_t *copyInfos); - -void QFV_FreeDescriptorSet (qfv_descriptorset_t *set); -void QFV_ResetDescriptorPool (qfv_descriptorpool_t *pool); -void QFV_DestroyDescriptorPool (qfv_descriptorpool_t *pool); -void QFV_DestroyDescriptorSetLayout (qfv_descriptorsetlayout_t *layout); -void QFV_DestroySampler (qfv_sampler_t *sampler); - +qfv_descriptorsets_t * +QFV_AllocateDescriptorSet (struct qfv_device_s *device, + VkDescriptorPool pool, + qfv_descriptorsetlayoutset_t *layouts); #endif//__QF_Vulkan_descriptor_h diff --git a/libs/video/renderer/vulkan/descriptor.c b/libs/video/renderer/vulkan/descriptor.c index cc9cce6d4..7610a8fd9 100644 --- a/libs/video/renderer/vulkan/descriptor.c +++ b/libs/video/renderer/vulkan/descriptor.c @@ -61,7 +61,7 @@ #include "util.h" -qfv_sampler_t * +VkSampler QFV_CreateSampler (qfv_device_t *device, VkFilter magFilter, VkFilter minFilter, VkSamplerMipmapMode mipmapMode, @@ -90,29 +90,12 @@ QFV_CreateSampler (qfv_device_t *device, borderColor, unnormalizedCoordinates, }; - qfv_sampler_t *sampler = malloc (sizeof (*sampler)); - sampler->device = device; - dfunc->vkCreateSampler (dev, &createInfo, 0, &sampler->sampler); + VkSampler sampler; + dfunc->vkCreateSampler (dev, &createInfo, 0, &sampler); return sampler; } -qfv_bindingset_t * -QFV_CreateBindingSet (int numBindings) -{ - qfv_bindingset_t *bindingset; - bindingset = malloc (field_offset (qfv_bindingset_t, - bindings[numBindings])); - bindingset->numBindings = numBindings; - return bindingset; -} - -void -QFV_DestroyBindingSet (qfv_bindingset_t *bindingset) -{ - free (bindingset); -} - -qfv_descriptorsetlayout_t * +VkDescriptorSetLayout QFV_CreateDescriptorSetLayout (qfv_device_t *device, qfv_bindingset_t *bindingset) { @@ -122,12 +105,11 @@ QFV_CreateDescriptorSetLayout (qfv_device_t *device, VkDescriptorSetLayoutCreateInfo createInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 0, 0, - bindingset->numBindings, bindingset->bindings, + bindingset->size, bindingset->a, }; - qfv_descriptorsetlayout_t *layout = malloc (sizeof (layout)); - layout->device = device; - dfunc->vkCreateDescriptorSetLayout (dev, &createInfo, 0, &layout->layout); + VkDescriptorSetLayout layout; + dfunc->vkCreateDescriptorSetLayout (dev, &createInfo, 0, &layout); return layout; } @@ -151,7 +133,7 @@ poolsize_compmare (const void *ele1, const void *ele2, void *unused) } //FIXME not thread-safe -qfv_descriptorpool_t * +VkDescriptorPool QFV_CreateDescriptorPool (qfv_device_t *device, VkDescriptorPoolCreateFlags flags, uint32_t maxSets, qfv_bindingset_t *bindings) @@ -170,8 +152,8 @@ QFV_CreateDescriptorPool (qfv_device_t *device, poolsize_next = poolsize_pool; VkDescriptorPoolSize *ps; - for (int i = 0; i < bindings->numBindings; i++) { - VkDescriptorPoolSize test = { bindings->bindings[i].descriptorType, 0 }; + for (size_t i = 0; i < bindings->size; i++) { + VkDescriptorPoolSize test = { bindings->a[i].descriptorType, 0 }; ps = Hash_FindElement (poolsizes, &test); if (!ps) { ps = poolsize_next++; @@ -183,7 +165,7 @@ QFV_CreateDescriptorPool (qfv_device_t *device, } //XXX is descriptorCount correct? //FIXME assumes only one layout is used with this pool - ps->descriptorCount += bindings->bindings[i].descriptorCount * maxSets; + ps->descriptorCount += bindings->a[i].descriptorCount * maxSets; } VkDescriptorPoolCreateInfo createInfo = { @@ -191,155 +173,26 @@ QFV_CreateDescriptorPool (qfv_device_t *device, flags, maxSets, poolsize_next - poolsize_pool, poolsize_pool, }; - qfv_descriptorpool_t *descriptorpool = malloc (sizeof (descriptorpool)); - descriptorpool->device = device; - dfunc->vkCreateDescriptorPool (dev, &createInfo, 0, &descriptorpool->pool); - return descriptorpool; + VkDescriptorPool pool; + dfunc->vkCreateDescriptorPool (dev, &createInfo, 0, &pool); + return pool; } -qfv_descriptorset_t * -QFV_AllocateDescriptorSet (qfv_descriptorpool_t *pool, - qfv_descriptorsetlayout_t *layout) +qfv_descriptorsets_t * +QFV_AllocateDescriptorSet (qfv_device_t *device, + VkDescriptorPool pool, + qfv_descriptorsetlayoutset_t *layouts) { - qfv_device_t *device = pool->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; VkDescriptorSetAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 0, - pool->pool, 1, &layout->layout, + pool, layouts->size, layouts->a, }; - qfv_descriptorset_t *descriptorset = malloc (sizeof (*descriptorset)); - descriptorset->device = device; - descriptorset->pool = pool; - dfunc->vkAllocateDescriptorSets (dev, &allocateInfo, &descriptorset->set); - return descriptorset; -} - -void -QFV_UpdateDescriptorSets (qfv_device_t *device, - uint32_t numImageInfos, - qfv_imagedescriptorinfo_t *imageInfos, - uint32_t numBufferInfos, - qfv_bufferdescriptorinfo_t *bufferInfos, - uint32_t numTexelBufferInfos, - qfv_texelbufferdescriptorinfo_t *texelbufferInfos, - uint32_t numCopyInfos, - qfv_copydescriptorinfo_t *copyInfos) -{ - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - uint32_t numWrite = 0; - numWrite += numImageInfos; - numWrite += numBufferInfos; - numWrite += numTexelBufferInfos; - VkWriteDescriptorSet *writeSets = alloca (numWrite * sizeof (*writeSets)); - VkWriteDescriptorSet *writeSet = writeSets; - for (uint32_t i = 0; i < numImageInfos; i++, writeSet++) { - writeSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeSet->pNext = 0; - writeSet->dstSet = imageInfos[i].descriptorset->set; - writeSet->dstBinding = imageInfos[i].binding; - writeSet->dstArrayElement = imageInfos[i].arrayElement; - writeSet->descriptorCount = imageInfos[i].numInfo; - writeSet->descriptorType = imageInfos[i].type; - writeSet->pImageInfo = imageInfos[i].infos; - writeSet->pBufferInfo = 0; - writeSet->pTexelBufferView = 0; - } - for (uint32_t i = 0; i < numBufferInfos; i++, writeSet++) { - writeSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeSet->pNext = 0; - writeSet->dstSet = bufferInfos[i].descriptorset->set; - writeSet->dstBinding = bufferInfos[i].binding; - writeSet->dstArrayElement = bufferInfos[i].arrayElement; - writeSet->descriptorCount = bufferInfos[i].numInfo; - writeSet->descriptorType = bufferInfos[i].type; - writeSet->pImageInfo = 0; - writeSet->pBufferInfo = bufferInfos[i].infos; - writeSet->pTexelBufferView = 0; - } - for (uint32_t i = 0; i < numTexelBufferInfos; i++, writeSet++) { - writeSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeSet->pNext = 0; - writeSet->dstSet = bufferInfos[i].descriptorset->set; - writeSet->dstBinding = texelbufferInfos[i].binding; - writeSet->dstArrayElement = texelbufferInfos[i].arrayElement; - writeSet->descriptorCount = texelbufferInfos[i].numInfo; - writeSet->descriptorType = texelbufferInfos[i].type; - writeSet->pImageInfo = 0; - writeSet->pBufferInfo = 0; - writeSet->pTexelBufferView = texelbufferInfos[i].infos; - } - VkCopyDescriptorSet *copySets = alloca (numWrite * sizeof (*copySets)); - VkCopyDescriptorSet *copySet = copySets; - for (uint32_t i = 0; i < numCopyInfos; i++, copySet++) { - copySet->sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET; - copySet->pNext = 0; - copySet->srcSet = copyInfos[i].srcSet->set; - copySet->srcBinding = copyInfos[i].srcBinding; - copySet->srcArrayElement = copyInfos[i].srcArrayElement; - copySet->dstSet = copyInfos[i].dstSet->set; - copySet->dstBinding = copyInfos[i].dstBinding; - copySet->dstArrayElement = copyInfos[i].dstArrayElement; - copySet->descriptorCount = copyInfos[i].descriptorCount; - } - dfunc->vkUpdateDescriptorSets (dev, numWrite, writeSets, - numCopyInfos, copySets); -} - -void -QFV_FreeDescriptorSet (qfv_descriptorset_t *set) -{ - qfv_device_t *device = set->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - VkDescriptorPool pool = set->pool->pool; - - dfunc->vkFreeDescriptorSets (dev, pool, 1, &set->set); -} - -void -QFV_ResetDescriptorPool (qfv_descriptorpool_t *pool) -{ - qfv_device_t *device = pool->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkResetDescriptorPool (dev, pool->pool, 0); -} - -void -QFV_DestroyDescriptorPool (qfv_descriptorpool_t *pool) -{ - qfv_device_t *device = pool->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyDescriptorPool (dev, pool->pool, 0); - free (pool); -} - -void -QFV_DestroyDescriptorSetLayout (qfv_descriptorsetlayout_t *layout) -{ - qfv_device_t *device = layout->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyDescriptorSetLayout (dev, layout->layout, 0); - free (layout); -} - -void -QFV_DestroySampler (qfv_sampler_t *sampler) -{ - qfv_device_t *device = sampler->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroySampler (dev, sampler->sampler, 0); - free (sampler); + __auto_type descriptorsets + = QFV_AllocDescriptorSets (layouts->size, malloc); + dfunc->vkAllocateDescriptorSets (dev, &allocateInfo, descriptorsets->a); + return descriptorsets; } diff --git a/libs/video/renderer/vulkan/pipeline.c b/libs/video/renderer/vulkan/pipeline.c index 0dd5f260e..18babb115 100644 --- a/libs/video/renderer/vulkan/pipeline.c +++ b/libs/video/renderer/vulkan/pipeline.c @@ -154,22 +154,16 @@ QFV_DestroyPipelineCache (qfv_pipelinecache_t *cache) qfv_pipelinelayout_t * QFV_CreatePipelineLayout (qfv_device_t *device, - qfv_descriptorsetlayoutset_t *layoutset, + qfv_descriptorsetlayoutset_t *layouts, qfv_pushconstantrangeset_t *pushConstants) { VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - uint32_t numLayouts = layoutset->numLayouts; - VkDescriptorSetLayout *layouts = alloca (numLayouts * sizeof (*layouts)); - - for (uint32_t i = 0; i < numLayouts; i++) { - layouts[i] = layoutset->layouts[i]->layout; - } - VkPipelineLayoutCreateInfo createInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 0, 0, - numLayouts, layouts, pushConstants->numRanges, pushConstants->ranges, + layouts->size, layouts->a, + pushConstants->numRanges, pushConstants->ranges, }; qfv_pipelinelayout_t *layout = malloc (sizeof (layout)); From ad175d054bfb2fb3cd11b3018deb2d5a8ceb5803 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 18 Feb 2020 22:38:01 +0900 Subject: [PATCH 082/435] Sanitize pipelines wow, talk about doing things the wrong way. I guess that's the problem with following a book targeted for C++: you get all that safety-goat nonsense. --- include/QF/Vulkan/pipeline.h | 164 +++-------- libs/video/renderer/vulkan/pipeline.c | 403 ++------------------------ 2 files changed, 68 insertions(+), 499 deletions(-) diff --git a/include/QF/Vulkan/pipeline.h b/include/QF/Vulkan/pipeline.h index 2120e2317..f77585217 100644 --- a/include/QF/Vulkan/pipeline.h +++ b/include/QF/Vulkan/pipeline.h @@ -3,23 +3,11 @@ #include "QF/darray.h" -typedef struct qfv_shadermodule_s { - struct qfv_device_s *device; - VkShaderModule module; -} qfv_shadermodule_t; +typedef struct qfv_pipelineshaderstateset_s + DARRAY_TYPE (VkPipelineShaderStageCreateInfo) qfv_pipelineshaderstateset_s; -typedef struct qfv_shaderstageparams_s { - VkShaderStageFlagBits stageFlags; - qfv_shadermodule_t *module; - const char *entryPointName; - const VkSpecializationInfo *specializationInfo; -} qfv_shaderstageparams_t; - -typedef struct qfv_shaderstageparamsset_s - DARRAY_TYPE (qfv_shaderstageparams_t) qfv_shaderstageparamsset_t; - -#define QFV_AllocShaderParamsSet(num, allocator) \ - DARRAY_ALLOCFIXED (qfv_shaderstageparamsset_t, num, allocator) +#define QFV_AllocPipelineShaderStageSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_pipelineshaderstateset_s, num, allocator) typedef struct qfv_vertexinputbindingset_s DARRAY_TYPE (VkVertexInputBindingDescription) qfv_vertexinputbindingset_t; @@ -48,21 +36,15 @@ typedef struct qfv_pipelinetessellation_s { uint32_t patchControlPoints; } qfv_pipelinetessellation_t; -typedef struct qfv_viewportset_s { - uint32_t numViewports; - VkViewport viewports[]; -} qfv_viewportset_t; +typedef struct qfv_viewportset_s DARRAY_TYPE (VkViewport) qfv_viewportset_t; #define QFV_AllocViewportSet(num, allocator) \ - allocator (field_offset (qfv_viewportset_t, viewports[num])) + DARRAY_ALLOCFIXED (qfv_viewportset_t, num, allocator) -typedef struct qfv_scissorsset_s { - uint32_t numScissors; - VkRect2D scissors[]; -} qfv_scissorsset_t; +typedef struct qfv_scissorsset_s DARRAY_TYPE (VkRect2D) qfv_scissorsset_t; #define QFV_AllocScissorsSet(num, allocator) \ - allocator (field_offset (qfv_scissorsset_t, scissors[num])) + DARRAY_ALLOCFIXED (qfv_scissorsset_t, num, allocator) typedef struct qfv_viewportinfo_s { qfv_viewportset_t *viewportset; @@ -103,139 +85,73 @@ typedef struct qfv_pipelinedepthandstencil_s { float maxDepthBounds; } qfv_pipelinedepthandstencil_t; -typedef struct qfv_blendattachmentset_s { - uint32_t numAttachments; - VkPipelineColorBlendAttachmentState attachments[]; -} qfv_blendattachmentset_t; +typedef struct qfv_blendattachmentset_s + DARRAY_TYPE (VkPipelineColorBlendAttachmentState) qfv_blendattachmentset_t; #define QFV_AllocBlendAttachmentSet(num, allocator) \ - allocator (field_offset (qfv_blendattachmentset_t, attachments[num])) + DARRAY_ALLOCFIXED (qfv_blendattachmentset_t, num, allocator) -typedef struct qfv_pipelineblend_s { - VkBool32 logicOpEnable; - VkLogicOp logicOp; - qfv_blendattachmentset_t *blendAttachments; - float blendConstants[4]; -} qfv_pipelineblend_t; - -typedef struct qfv_dynamicstateset_s { - uint32_t numStates; - VkDynamicState states[]; -} qfv_dynamicstateset_t; +typedef struct qfv_dynamicstateset_s + DARRAY_TYPE (VkDynamicState) qfv_dynamicstateset_t; #define QFV_AllocDynamicStateSet(num, allocator) \ - allocator (field_offset (qfv_dynamicstateset_t, states[num])) + DARRAY_ALLOCFIXED (qfv_dynamicstateset_t, num, allocator) -typedef struct qfv_pushconstantrangeset_s { - uint32_t numRanges; - VkPushConstantRange ranges[]; -} qfv_pushconstantrangeset_t; +typedef struct qfv_pushconstantrangeset_s + DARRAY_TYPE (VkPushConstantRange) qfv_pushconstantrangeset_t; #define QFV_AllocPushConstantRangeSet(num, allocator) \ - allocator (field_offset (qfv_pushconstantrangeset_t, ranges[num])) + DARRAY_ALLOCFIXED (qfv_pushconstantrangeset_t, num, allocator) -typedef struct qfv_pipelinelayout_s { - struct qfv_device_s *device; - VkPipelineLayout layout; -} qfv_pipelinelayout_t; - -typedef struct qfv_pipeline_s { - struct qfv_device_s *device; - VkPipeline pipeline; -} qfv_pipeline_t; - -typedef struct qfv_pipelineset_s { - uint32_t numPipelines; - qfv_pipeline_t *pipelines[]; -} qfv_pipelineset_t; +typedef struct qfv_pipelineset_s DARRAY_TYPE (VkPipeline) qfv_pipelineset_t; #define QFV_AllocPipelineSet(num, allocator) \ - allocator (field_offset (qfv_pipelineset_t, pipelines[num])) + DARRAY_ALLOCFIXED (qfv_pipelineset_t, num, allocator) -typedef struct qfv_graphicspipelinecreateinfo_s { - VkPipelineCreateFlags flags; - qfv_shaderstageparamsset_t *stages; - qfv_vertexinputstate_t *vertexState; - qfv_pipelineinputassembly_t *inputAssemblyState; - qfv_pipelinetessellation_t *tessellationState; - qfv_viewportinfo_t *viewportState; - qfv_pipelinerasterization_t *rasterizationState; - qfv_pipelinemultisample_t *multisampleState; - qfv_pipelinedepthandstencil_t *depthStencilState; - qfv_pipelineblend_t *colorBlendState; - qfv_dynamicstateset_t *dynamicState; - qfv_pipelinelayout_t *layout; - VkRenderPass renderPass; - uint32_t subpass; - qfv_pipeline_t *basePipeline; - int32_t basePipelineIndex; -} qfv_graphicspipelinecreateinfo_t; - -typedef struct qfv_graphicspipelinecreateinfoset_s { - uint32_t numPipelines; - qfv_graphicspipelinecreateinfo_t *pipelines[]; -} qfv_graphicspipelinecreateinfoset_t; +typedef struct qfv_graphicspipelinecreateinfoset_s + DARRAY_TYPE (VkGraphicsPipelineCreateInfo) + qfv_graphicspipelinecreateinfoset_t; #define QFV_AllocGraphicsPipelineCreateInfoSet(num, allocator) \ - allocator (field_offset (qfv_graphicspipelinecreateinfoset_t, \ - pipelines[num])) + DARRAY_ALLOCFIXED (qfv_graphicspipelinecreateinfoset_t, num, allocator) -typedef struct qfv_computepipelinecreateinfo_s { - VkPipelineCreateFlags flags; - qfv_shaderstageparams_t *stage; - qfv_pipelinelayout_t *layout; - qfv_pipeline_t *basePipeline; - int32_t basePipelineIndex; -} qfv_computepipelinecreateinfo_t; - -typedef struct qfv_computepipelinecreateinfoset_s { - uint32_t numPipelines; - qfv_computepipelinecreateinfo_t *pipelines[]; -} qfv_computepipelinecreateinfoset_t; +typedef struct qfv_computepipelinecreateinfoset_s + DARRAY_TYPE (VkComputePipelineCreateInfo) + qfv_computepipelinecreateinfoset_t; #define QFV_AllocComputePipelineCreateInfoSet(num, allocator) \ - allocator (field_offset (qfv_computepipelinecreateinfoset_t, \ - pipelines[num])) + DARRAY_ALLOCFIXED (qfv_computepipelinecreateinfoset_t, num, allocator) -typedef struct qfv_pipelinecache_s { - struct qfv_device_s *device; - VkPipelineCache cache; -} qfv_pipelinecache_t; - -typedef struct qfv_pipelinecacheset_s { - uint32_t numCaches; - qfv_pipelinecache_t *caches[]; -} qfv_pipelinecacheset_t; +typedef struct qfv_pipelinecacheset_s + DARRAY_TYPE (VkPipelineCache) qfv_pipelinecacheset_t; #define QFV_AllocPipelineCacheSet(num, allocator) \ - allocator (field_offset (qfv_pipelinecacheset_t, caches[num])) + DARRAY_ALLOCFIXED (qfv_pipelinecacheset_t, num, allocator) -qfv_shadermodule_t *QFV_CreateShaderModule (struct qfv_device_s *device, +VkShaderModule QFV_CreateShaderModule (struct qfv_device_s *device, size_t size, const uint32_t *code); -void QFV_DestroyShaderModule (qfv_shadermodule_t *module); struct dstring_s; -qfv_pipelinecache_t *QFV_CreatePipelineCache (struct qfv_device_s *device, - struct dstring_s *cacheData); -struct dstring_s *QFV_GetPipelineCacheData (qfv_pipelinecache_t *cache); -void QFV_MergePipelineCaches (qfv_pipelinecache_t *targetCache, +VkPipelineCache QFV_CreatePipelineCache (struct qfv_device_s *device, + struct dstring_s *cacheData); +struct dstring_s *QFV_GetPipelineCacheData (struct qfv_device_s *device, + VkPipelineCache cache); +void QFV_MergePipelineCaches (struct qfv_device_s *device, + VkPipelineCache targetCache, qfv_pipelinecacheset_t *sourceCaches); -void QFV_DestroyPipelineCache (qfv_pipelinecache_t *cache); struct qfv_descriptorsetlayoutset_s; -qfv_pipelinelayout_t * +VkPipelineLayout QFV_CreatePipelineLayout (struct qfv_device_s *device, struct qfv_descriptorsetlayoutset_s *layouts, qfv_pushconstantrangeset_t *pushConstants); -void QFV_DestroyPipelineLayout (qfv_pipelinelayout_t *layout); qfv_pipelineset_t * QFV_CreateGraphicsPipelines (struct qfv_device_s *device, - qfv_pipelinecache_t *cache, + VkPipelineCache cache, qfv_graphicspipelinecreateinfoset_t *gpciSet); qfv_pipelineset_t * QFV_CreateComputePipelines (struct qfv_device_s *device, - qfv_pipelinecache_t *cache, + VkPipelineCache cache, qfv_computepipelinecreateinfoset_t *cpciSet); -void QFV_DestroyPipeline (qfv_pipeline_t *pipeline); #endif//__QF_Vulkan_pipeline_h diff --git a/libs/video/renderer/vulkan/pipeline.c b/libs/video/renderer/vulkan/pipeline.c index 18babb115..119fbf303 100644 --- a/libs/video/renderer/vulkan/pipeline.c +++ b/libs/video/renderer/vulkan/pipeline.c @@ -64,7 +64,7 @@ #include "util.h" -qfv_shadermodule_t * +VkShaderModule QFV_CreateShaderModule (qfv_device_t *device, size_t size, const uint32_t *code) { @@ -76,24 +76,12 @@ QFV_CreateShaderModule (qfv_device_t *device, size, code, }; - qfv_shadermodule_t *module = malloc (sizeof (*module)); - module->device = device; - dfunc->vkCreateShaderModule (dev, &createInfo, 0, &module->module); + VkShaderModule module; + dfunc->vkCreateShaderModule (dev, &createInfo, 0, &module); return module; } -void -QFV_DestroyShaderModule (qfv_shadermodule_t *module) -{ - qfv_device_t *device = module->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyShaderModule (dev, module->module, 0); - free (module); -} - -qfv_pipelinecache_t * +VkPipelineCache QFV_CreatePipelineCache (qfv_device_t *device, dstring_t *cacheData) { VkDevice dev = device->dev; @@ -104,55 +92,38 @@ QFV_CreatePipelineCache (qfv_device_t *device, dstring_t *cacheData) cacheData->size, cacheData->str, }; - qfv_pipelinecache_t *cache = malloc (sizeof (*cache)); - cache->device = device; - dfunc->vkCreatePipelineCache (dev, &createInfo, 0, &cache->cache); + VkPipelineCache cache; + dfunc->vkCreatePipelineCache (dev, &createInfo, 0, &cache); return cache; } dstring_t * -QFV_GetPipelineCacheData (qfv_pipelinecache_t *cache) +QFV_GetPipelineCacheData (qfv_device_t *device, VkPipelineCache cache) { - qfv_device_t *device = cache->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; dstring_t *cacheData = dstring_new (); - dfunc->vkGetPipelineCacheData (dev, cache->cache, &cacheData->size, 0); + dfunc->vkGetPipelineCacheData (dev, cache, &cacheData->size, 0); dstring_adjust (cacheData); - dfunc->vkGetPipelineCacheData (dev, cache->cache, &cacheData->size, - cacheData->str); + dfunc->vkGetPipelineCacheData (dev, cache, + &cacheData->size, cacheData->str); return cacheData; } void -QFV_MergePipelineCaches (qfv_pipelinecache_t *targetCache, +QFV_MergePipelineCaches (qfv_device_t *device, + VkPipelineCache targetCache, qfv_pipelinecacheset_t *sourceCaches) { - qfv_device_t *device = targetCache->device; VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - VkPipelineCache *srcCaches = alloca (sourceCaches->numCaches - * sizeof (*srcCaches)); - for (uint32_t i = 0; i < sourceCaches->numCaches; i++) { - srcCaches[i] = sourceCaches->caches[i]->cache; - } - dfunc->vkMergePipelineCaches (dev, targetCache->cache, - sourceCaches->numCaches, srcCaches); + dfunc->vkMergePipelineCaches (dev, targetCache, + sourceCaches->size, sourceCaches->a); } -void -QFV_DestroyPipelineCache (qfv_pipelinecache_t *cache) -{ - qfv_device_t *device = cache->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyPipelineCache (dev, cache->cache, 0); -} - -qfv_pipelinelayout_t * +VkPipelineLayout QFV_CreatePipelineLayout (qfv_device_t *device, qfv_descriptorsetlayoutset_t *layouts, qfv_pushconstantrangeset_t *pushConstants) @@ -163,357 +134,39 @@ QFV_CreatePipelineLayout (qfv_device_t *device, VkPipelineLayoutCreateInfo createInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 0, 0, layouts->size, layouts->a, - pushConstants->numRanges, pushConstants->ranges, + pushConstants->size, pushConstants->a, }; - qfv_pipelinelayout_t *layout = malloc (sizeof (layout)); - layout->device = device; - dfunc->vkCreatePipelineLayout (dev, &createInfo, 0, &layout->layout); + VkPipelineLayout layout; + dfunc->vkCreatePipelineLayout (dev, &createInfo, 0, &layout); return layout; } -void -QFV_DestroyPipelineLayout (qfv_pipelinelayout_t *layout) -{ - qfv_device_t *device = layout->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyPipelineLayout (dev, layout->layout, 0); - free (layout); -} - -static VkPipelineShaderStageCreateInfo -shaderStageCI (qfv_shaderstageparams_t params) -{ - VkPipelineShaderStageCreateInfo createInfo = { - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 0, 0, - params.stageFlags, params.module->module, - params.entryPointName, params.specializationInfo, - }; - return createInfo; -} - -static VkPipelineVertexInputStateCreateInfo -vertexInputSCI (qfv_vertexinputstate_t vertexState) -{ - VkPipelineVertexInputStateCreateInfo createInfo = { - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 0, 0, - vertexState.bindings->size, - vertexState.bindings->a, - vertexState.attributes->size, - vertexState.attributes->a, - }; - return createInfo; -} - -static VkPipelineInputAssemblyStateCreateInfo -inputAssemblySCI (qfv_pipelineinputassembly_t inputAssemblyState) -{ - VkPipelineInputAssemblyStateCreateInfo createInfo = { - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 0, 0, - inputAssemblyState.topology, - inputAssemblyState.primativeRestartEnable, - }; - return createInfo; -} - -static VkPipelineTessellationStateCreateInfo -tessellationSCI (qfv_pipelinetessellation_t tessellationState) -{ - VkPipelineTessellationStateCreateInfo createInfo = { - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, 0, 0, - tessellationState.patchControlPoints - }; - return createInfo; -} - -static VkPipelineViewportStateCreateInfo -viewportSCI (qfv_viewportinfo_t viewportState) -{ - VkPipelineViewportStateCreateInfo createInfo = { - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 0, 0, - viewportState.viewportset->numViewports, - viewportState.viewportset->viewports, - viewportState.scissorsset->numScissors, - viewportState.scissorsset->scissors, - }; - return createInfo; -} - -static VkPipelineRasterizationStateCreateInfo -rasterizationSCI (qfv_pipelinerasterization_t rasterizationState) -{ - VkPipelineRasterizationStateCreateInfo createInfo = { - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, 0, 0, - rasterizationState.depthClampEnable, - rasterizationState.rasterizerDiscardEnable, - rasterizationState.polygonMode, - rasterizationState.cullMode, - rasterizationState.frontFace, - rasterizationState.depthBiasEnable, - rasterizationState.depthBiasConstantFactor, - rasterizationState.depthBiasClamp, - rasterizationState.depthBiasSlopeFactor, - rasterizationState.lineWidth, - }; - return createInfo; -} - -static VkPipelineMultisampleStateCreateInfo -multisampleSCI (qfv_pipelinemultisample_t multisampleState) -{ - VkPipelineMultisampleStateCreateInfo createInfo = { - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 0, 0, - multisampleState.rasterizationSamples, - multisampleState.sampleShadingEnable, - multisampleState.minSampleShading, - multisampleState.sampleMask, - multisampleState.alphaToCoverageEnable, - multisampleState.alphaToOneEnable, - }; - return createInfo; -} - -static VkPipelineDepthStencilStateCreateInfo -depthStencilSCI (qfv_pipelinedepthandstencil_t depthStencilState) -{ - VkPipelineDepthStencilStateCreateInfo createInfo = { - VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, 0, 0, - depthStencilState.depthTestEnable, - depthStencilState.depthWriteEnable, - depthStencilState.depthCompareOp, - depthStencilState.depthBoundsTestEnable, - depthStencilState.stencilTestEnable, - depthStencilState.front, - depthStencilState.back, - depthStencilState.minDepthBounds, - depthStencilState.maxDepthBounds, - }; - return createInfo; -} - -static VkPipelineColorBlendStateCreateInfo -colorBlendSCI (qfv_pipelineblend_t colorBlendState) -{ - VkPipelineColorBlendStateCreateInfo createInfo = { - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 0, 0, - colorBlendState.logicOpEnable, - colorBlendState.logicOp, - colorBlendState.blendAttachments->numAttachments, - colorBlendState.blendAttachments->attachments, - { - colorBlendState.blendConstants[0], - colorBlendState.blendConstants[1], - colorBlendState.blendConstants[2], - colorBlendState.blendConstants[3], - }, - }; - return createInfo; -} - -static VkPipelineDynamicStateCreateInfo -dynamicSCI (qfv_dynamicstateset_t *dynamicState) -{ - VkPipelineDynamicStateCreateInfo createInfo = { - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, 0, 0, - dynamicState->numStates, dynamicState->states, - }; - return createInfo; -} - qfv_pipelineset_t * QFV_CreateGraphicsPipelines (qfv_device_t *device, - qfv_pipelinecache_t *cache, + VkPipelineCache cache, qfv_graphicspipelinecreateinfoset_t *gpciSet) { VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - uint32_t numPipelines = gpciSet->numPipelines; - uint32_t stageCount = 0; - for (uint32_t i = 0; i < numPipelines; i++) { - stageCount += gpciSet->pipelines[i]->stages->size; - } + __auto_type pipelines = QFV_AllocPipelineSet (gpciSet->size, malloc); + dfunc->vkCreateGraphicsPipelines (dev, cache, gpciSet->size, gpciSet->a, 0, + pipelines->a); - size_t blockSize = numPipelines - * (sizeof (VkGraphicsPipelineCreateInfo) - + sizeof (VkPipelineVertexInputStateCreateInfo) - + sizeof (VkPipelineInputAssemblyStateCreateInfo) - + sizeof (VkPipelineTessellationStateCreateInfo) - + sizeof (VkPipelineViewportStateCreateInfo) - + sizeof (VkPipelineRasterizationStateCreateInfo) - + sizeof (VkPipelineMultisampleStateCreateInfo) - + sizeof (VkPipelineDepthStencilStateCreateInfo) - + sizeof (VkPipelineColorBlendStateCreateInfo) - + sizeof (VkPipelineDynamicStateCreateInfo)) - + stageCount * sizeof (VkPipelineShaderStageCreateInfo); - VkGraphicsPipelineCreateInfo *pipelineInfos = malloc (blockSize); - - pipelineInfos->pStages = (void *)(pipelineInfos + numPipelines); - pipelineInfos->pVertexInputState - = (void *)(pipelineInfos->pStages + stageCount); - pipelineInfos->pInputAssemblyState - = (void *)(pipelineInfos->pVertexInputState + numPipelines); - pipelineInfos->pTessellationState - = (void *)(pipelineInfos->pInputAssemblyState + numPipelines); - pipelineInfos->pViewportState - = (void *)(pipelineInfos->pTessellationState + numPipelines); - pipelineInfos->pRasterizationState - = (void *)(pipelineInfos->pViewportState + numPipelines); - pipelineInfos->pMultisampleState - = (void *)(pipelineInfos->pRasterizationState + numPipelines); - pipelineInfos->pDepthStencilState - = (void *)(pipelineInfos->pMultisampleState + numPipelines); - pipelineInfos->pColorBlendState - = (void *)(pipelineInfos->pDepthStencilState + numPipelines); - pipelineInfos->pDynamicState - = (void *)(pipelineInfos->pColorBlendState + numPipelines); - for (uint32_t i = 1; i < gpciSet->numPipelines; i++) { - pipelineInfos[i].pStages = pipelineInfos[i - 1].pStages - + gpciSet->pipelines[i - 1]->stages->size; - pipelineInfos[i].pVertexInputState - = pipelineInfos[i - 1].pVertexInputState + 1; - pipelineInfos[i].pInputAssemblyState - = pipelineInfos[i - 1].pInputAssemblyState + 1; - pipelineInfos[i].pTessellationState - = pipelineInfos[i - 1].pTessellationState + 1; - pipelineInfos[i].pViewportState - = pipelineInfos[i - 1].pViewportState + 1; - pipelineInfos[i].pRasterizationState - = pipelineInfos[i - 1].pRasterizationState + 1; - pipelineInfos[i].pMultisampleState - = pipelineInfos[i - 1].pMultisampleState + 1; - pipelineInfos[i].pDepthStencilState - = pipelineInfos[i - 1].pDepthStencilState + 1; - pipelineInfos[i].pColorBlendState - = pipelineInfos[i - 1].pColorBlendState + 1; - pipelineInfos[i].pDynamicState - = pipelineInfos[i - 1].pDynamicState + 1; - } - for (uint32_t i = 0; i < gpciSet->numPipelines; i++) { - VkGraphicsPipelineCreateInfo *gci = pipelineInfos + i; - qfv_graphicspipelinecreateinfo_t *ci = gpciSet->pipelines[i]; - gci->sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - gci->pNext = 0; - gci->flags = ci->flags; - gci->stageCount = ci->stages->size; - for (uint32_t j = 0; j < gci->stageCount; j++) { - ((VkPipelineShaderStageCreateInfo *)gci->pStages)[i] = shaderStageCI (ci->stages->a[j]); - } - if (ci->vertexState) { - *(VkPipelineVertexInputStateCreateInfo *)gci->pVertexInputState = vertexInputSCI (*ci->vertexState); - } else { - gci->pVertexInputState = 0; - } - if (ci->inputAssemblyState) { - *(VkPipelineInputAssemblyStateCreateInfo *)gci->pInputAssemblyState = inputAssemblySCI (*ci->inputAssemblyState); - } else { - gci->pInputAssemblyState = 0; - } - if (ci->tessellationState) { - *(VkPipelineTessellationStateCreateInfo *)gci->pTessellationState = tessellationSCI (*ci->tessellationState); - } else { - gci->pTessellationState = 0; - } - if (ci->viewportState) { - *(VkPipelineViewportStateCreateInfo *)gci->pViewportState = viewportSCI (*ci->viewportState); - } else { - gci->pViewportState = 0; - } - if (ci->rasterizationState) { - *(VkPipelineRasterizationStateCreateInfo *)gci->pRasterizationState = rasterizationSCI (*ci->rasterizationState); - } else { - gci->pRasterizationState = 0; - } - if (ci->multisampleState) { - *(VkPipelineMultisampleStateCreateInfo *)gci->pMultisampleState = multisampleSCI (*ci->multisampleState); - } else { - gci->pMultisampleState = 0; - } - if (ci->depthStencilState) { - *(VkPipelineDepthStencilStateCreateInfo *)gci->pDepthStencilState = depthStencilSCI (*ci->depthStencilState); - } else { - gci->pDepthStencilState = 0; - } - if (ci->colorBlendState) { - *(VkPipelineColorBlendStateCreateInfo *)gci->pColorBlendState = colorBlendSCI (*ci->colorBlendState); - } else { - gci->pColorBlendState = 0; - } - if (ci->dynamicState) { - *(VkPipelineDynamicStateCreateInfo *)gci->pDynamicState = dynamicSCI (ci->dynamicState); - } else { - gci->pDynamicState = 0; - } - gci->layout = ci->layout->layout; - gci->renderPass = ci->renderPass; - gci->subpass = ci->subpass; - gci->basePipelineHandle = ci->basePipeline->pipeline; - gci->basePipelineIndex = ci->basePipelineIndex; - } - - VkPipeline *pipelines = alloca (numPipelines * sizeof (pipelines)); - dfunc->vkCreateGraphicsPipelines (dev, cache->cache, - numPipelines, pipelineInfos, 0, - pipelines); - - qfv_pipelineset_t *pipelineset = QFV_AllocPipelineSet (numPipelines, malloc); - pipelineset->numPipelines = numPipelines; - for (uint32_t i = 0; i < numPipelines; i++) { - pipelineset->pipelines[i] = malloc (sizeof (qfv_pipeline_t)); - pipelineset->pipelines[i]->device = device; - pipelineset->pipelines[i]->pipeline = pipelines[i]; - } - return pipelineset; + return pipelines; } qfv_pipelineset_t * QFV_CreateComputePipelines (qfv_device_t *device, - qfv_pipelinecache_t *cache, + VkPipelineCache cache, qfv_computepipelinecreateinfoset_t *cpciSet) { VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; - uint32_t numPipelines = cpciSet->numPipelines; - - size_t blockSize = numPipelines * (sizeof (VkComputePipelineCreateInfo)); - VkComputePipelineCreateInfo *pipelineInfos = malloc (blockSize); - - for (uint32_t i = 0; i < cpciSet->numPipelines; i++) { - VkComputePipelineCreateInfo *cci = pipelineInfos + i; - qfv_computepipelinecreateinfo_t *ci = cpciSet->pipelines[i]; - cci->sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - cci->pNext = 0; - cci->flags = ci->flags; - cci->stage = shaderStageCI (*ci->stage); - cci->layout = ci->layout->layout; - cci->basePipelineHandle = ci->basePipeline->pipeline; - cci->basePipelineIndex = ci->basePipelineIndex; - } - - VkPipeline *pipelines = alloca (numPipelines * sizeof (pipelines)); - dfunc->vkCreateComputePipelines (dev, cache->cache, - numPipelines, pipelineInfos, 0, - pipelines); - - qfv_pipelineset_t *pipelineset = QFV_AllocPipelineSet (numPipelines, malloc); - pipelineset->numPipelines = numPipelines; - for (uint32_t i = 0; i < numPipelines; i++) { - pipelineset->pipelines[i] = malloc (sizeof (qfv_pipeline_t)); - pipelineset->pipelines[i]->device = device; - pipelineset->pipelines[i]->pipeline = pipelines[i]; - } - return pipelineset; -} - -void -QFV_DestroyPipeline (qfv_pipeline_t *pipeline) -{ - qfv_device_t *device = pipeline->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyPipeline (dev, pipeline->pipeline, 0); + __auto_type pipelines = QFV_AllocPipelineSet (cpciSet->size, malloc); + dfunc->vkCreateComputePipelines (dev, cache, cpciSet->size, cpciSet->a, 0, + pipelines->a); + return pipelines; } From e658c0d5cde846cffa90d4675c37af62592908ce Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 01:28:09 +0900 Subject: [PATCH 083/435] Fix self-referenced enum declarations eg: typedef enum foo { bar = 1, baz = bar, } foo; --- tools/qfcc/source/qc-parse.y | 2 ++ tools/qfcc/source/struct.c | 1 + 2 files changed, 3 insertions(+) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index c34efd0a0..a2bbf1c03 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -553,6 +553,7 @@ optional_enum_list enum_list : '{' enum_init enumerator_list optional_comma '}' { + current_symtab = current_symtab->parent; $$ = finish_enum ($3); } ; @@ -562,6 +563,7 @@ enum_init { $$ = find_enum ($-1); start_enum ($$); + current_symtab = $$->type->t.symtab; } ; diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 358b337f0..800a1aa66 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -201,6 +201,7 @@ add_enum (symbol_t *enm, symbol_t *name, expr_t *val) if (enum_tab->symbols) value = ((symbol_t *)(enum_tab->symtail))->s.value->v.integer_val + 1; if (val) { + convert_name (val); if (!is_constant (val)) error (val, "non-constant initializer"); else if (!is_integer_val (val)) From 501174e14f4dc0a8e2709af0a0fd41ef18bf541a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 01:51:24 +0900 Subject: [PATCH 084/435] Allow unlimited parameters in function declarations However, definitions are still limited to 8 parameters. This allows processing of C headers for type information. --- tools/qfcc/include/function.h | 1 - tools/qfcc/include/type.h | 2 +- tools/qfcc/source/class.c | 9 ++++++--- tools/qfcc/source/cpp.c | 3 --- tools/qfcc/source/function.c | 36 ++++++++++++++++++++--------------- 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/tools/qfcc/include/function.h b/tools/qfcc/include/function.h index 88ea05dc8..209f40026 100644 --- a/tools/qfcc/include/function.h +++ b/tools/qfcc/include/function.h @@ -141,7 +141,6 @@ function_t *build_code_function (struct symbol_s *fsym, struct expr_s *statements); function_t *build_builtin_function (struct symbol_s *sym, struct expr_s *bi_val, int far); -void build_function (function_t *f); void finish_function (function_t *f); void emit_function (function_t *f, struct expr_s *e); int function_parms (function_t *f, byte *parm_size); diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 6944db353..fcb4a808a 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -38,7 +38,7 @@ typedef struct ty_func_s { struct type_s *type; int num_params; - struct type_s *param_types[MAX_PARMS]; + struct type_s **param_types; } ty_func_t; typedef struct ty_fldptr_s { diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index e0d601aa9..b249069c2 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -70,12 +70,14 @@ static hashtab_t *protocol_hash; // these will be built up further type_t type_obj_selector = { ev_invalid, 0, 0, ty_struct}; type_t type_SEL = { ev_pointer, "SEL", 1, ty_none, {{&type_obj_selector}}}; +type_t *IMP_params[] = {&type_id, &type_SEL}; type_t type_IMP = { ev_func, "IMP", 1, ty_none, - {{&type_id, -3, {&type_id, &type_SEL}}}}; + {{&type_id, -3, IMP_params}}}; type_t type_obj_super = { ev_invalid, 0, 0 }; type_t type_SuperPtr = { ev_pointer, 0, 1, ty_none, {{&type_obj_super}}}; +type_t *supermsg_params[] = {&type_SuperPtr, &type_SEL}; type_t type_supermsg = { ev_func, ".supermsg", 1, ty_none, - {{&type_id, -3, {&type_SuperPtr, &type_SEL}}}}; + {{&type_id, -3, supermsg_params}}}; type_t type_obj_method = { ev_invalid, 0, 0, ty_struct }; type_t type_obj_method_description = { ev_invalid, 0, 0, ty_struct }; type_t type_obj_category = { ev_invalid, 0, 0, ty_struct}; @@ -83,8 +85,9 @@ type_t type_obj_ivar = { ev_invalid, 0, 0, ty_struct}; type_t type_obj_module = { ev_invalid, 0, 0, ty_struct}; type_t type_moduleptr = { ev_pointer, 0, 1, ty_none, {{&type_obj_module}}}; +type_t *obj_exec_class_params[] = { &type_moduleptr }; type_t type_obj_exec_class = { ev_func, 0, 1, ty_none, - {{&type_void, 1, { &type_moduleptr }}}}; + {{&type_void, 1, obj_exec_class_params}}}; type_t type_obj_object = {ev_invalid, 0, 0, ty_struct}; type_t type_id = { ev_pointer, "id", 1, ty_none, {{&type_obj_object}}}; diff --git a/tools/qfcc/source/cpp.c b/tools/qfcc/source/cpp.c index 9bea8741d..7e8affb49 100644 --- a/tools/qfcc/source/cpp.c +++ b/tools/qfcc/source/cpp.c @@ -141,9 +141,6 @@ build_cpp_args (const char *in_name, const char *out_name) } } *arg = 0; - //for (arg = cpp_argv; *arg; arg++) - // printf ("%s ", *arg); - //puts (""); } //============================================================================ diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index b150e4baf..884dce1da 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -155,6 +155,7 @@ parse_params (type_t *type, param_t *parms) { param_t *p; type_t *new; + int count; new = new_type (); new->type = ev_func; @@ -163,10 +164,12 @@ parse_params (type_t *type, param_t *parms) new->t.func.num_params = 0; for (p = parms; p; p = p->next) { - if (new->t.func.num_params > MAX_PARMS) { - error (0, "too many params"); - return type; + if (p->type) { + count++; } + } + new->t.func.param_types = malloc (count * sizeof (type_t)); + for (p = parms; p; p = p->next) { if (!p->selector && !p->type && !p->name) { if (p->next) internal_error (0, 0); @@ -581,12 +584,25 @@ begin_function (symbol_t *sym, const char *nicename, symtab_t *parent, return sym->s.func; } +static void +build_function (symbol_t *fsym) +{ + if (fsym->type->t.func.num_params > MAX_PARMS) { + error (0, "too many params"); + } + // FIXME +// f->def->constant = 1; +// f->def->nosave = 1; +// f->def->initialized = 1; +// G_FUNCTION (f->def->ofs) = f->function_num; +} + function_t * build_code_function (symbol_t *fsym, expr_t *state_expr, expr_t *statements) { if (fsym->sy_type != sy_func) // probably in error recovery return 0; - build_function (fsym->s.func); + build_function (fsym); if (state_expr) { state_expr->next = statements; statements = state_expr; @@ -629,7 +645,7 @@ build_builtin_function (symbol_t *sym, expr_t *bi_val, int far) bi = expr_float (bi_val); sym->s.func->builtin = bi; reloc_def_func (sym->s.func, sym->s.func->def); - build_function (sym->s.func); + build_function (sym); finish_function (sym->s.func); // for debug info @@ -638,16 +654,6 @@ build_builtin_function (symbol_t *sym, expr_t *bi_val, int far) return sym->s.func; } -void -build_function (function_t *f) -{ - // FIXME -// f->def->constant = 1; -// f->def->nosave = 1; -// f->def->initialized = 1; -// G_FUNCTION (f->def->ofs) = f->function_num; -} - void finish_function (function_t *f) { From 2f726a497b6e853f7e2c4e0b5c83cb63932841bc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 02:30:50 +0900 Subject: [PATCH 085/435] Fix segfault in unlimited params --- tools/qfcc/source/function.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 884dce1da..4d3a617e9 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -330,8 +330,9 @@ find_function (expr_t *fexpr, expr_t *params) return e; type.t.func.num_params++; } - if (type.t.func.num_params > MAX_PARMS) - return fexpr; + i = type.t.func.num_params * sizeof (type_t); + type.t.func.param_types = alloca(i); + memset (type.t.func.param_types, 0, i); for (i = 0, e = params; e; i++, e = e->next) { type.t.func.param_types[type.t.func.num_params - 1 - i] = get_type (e); if (e->type == ex_error) From d4574111b528155e0e8e14018f36a2992b6598a0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 02:31:16 +0900 Subject: [PATCH 086/435] Replace system defines/includes with qfcc's Right now, it probably works only with modern gcc. --- config.d/qfcc.m4 | 2 +- tools/qfcc/configure.in | 2 +- tools/qfcc/include/cpp.h | 2 ++ tools/qfcc/source/cpp.c | 46 +++++++++++++++++++++++++++++++++---- tools/qfcc/source/options.c | 5 +++- 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/config.d/qfcc.m4 b/config.d/qfcc.m4 index 3e1d87ae7..380e6a31c 100644 --- a/config.d/qfcc.m4 +++ b/config.d/qfcc.m4 @@ -9,7 +9,7 @@ AC_ARG_WITH(cpp, if test "x$cpp_name" != xauto; then CPP_NAME="$cpp_name" else - CPP_NAME="cpp %d -o %o %i" + CPP_NAME="cpp %u %d %s -o %o %i" case "$host_os" in *freebsd*) CPP_NAME="cpp %d %i %o" diff --git a/tools/qfcc/configure.in b/tools/qfcc/configure.in index 21934d623..3c6383d5a 100644 --- a/tools/qfcc/configure.in +++ b/tools/qfcc/configure.in @@ -30,7 +30,7 @@ AC_ARG_WITH(cpp, if test "x$cpp_name" != xauto; then CPP_NAME="$cpp_name" else - CPP_NAME="cpp %d -o %o %i" + CPP_NAME="cpp %u %d %s -o %o %i" case "$target_os" in *bsd*) touch conftest.c diff --git a/tools/qfcc/include/cpp.h b/tools/qfcc/include/cpp.h index 6b599b439..81274c353 100644 --- a/tools/qfcc/include/cpp.h +++ b/tools/qfcc/include/cpp.h @@ -34,6 +34,8 @@ struct dstring_s; void parse_cpp_name (void); +void add_cpp_sysinc (const char *arg); +void add_cpp_undef (const char *arg); void add_cpp_def (const char *arg); void intermediate_file (struct dstring_s *ifile, const char *filename, const char *ext, int local); diff --git a/tools/qfcc/source/cpp.c b/tools/qfcc/source/cpp.c index 7e8affb49..71b42c6d1 100644 --- a/tools/qfcc/source/cpp.c +++ b/tools/qfcc/source/cpp.c @@ -67,11 +67,25 @@ cpp_arg_t *cpp_arg_list; cpp_arg_t **cpp_arg_tail = &cpp_arg_list; cpp_arg_t *cpp_def_list; cpp_arg_t **cpp_def_tail = &cpp_def_list; +cpp_arg_t *cpp_undef_list; +cpp_arg_t **cpp_undef_tail = &cpp_undef_list; +cpp_arg_t *cpp_sysinc_list; +cpp_arg_t **cpp_sysinc_tail = &cpp_sysinc_list; const char **cpp_argv; const char *cpp_name = CPP_NAME; static int cpp_argc = 0; dstring_t *tempname; +static const char ** +append_cpp_args (const char **arg, cpp_arg_t *arg_list) +{ + cpp_arg_t *cpp_arg; + + for (cpp_arg = arg_list; cpp_arg; cpp_arg = cpp_arg->next) + *arg++ = cpp_arg->arg; + return arg; +} + static void add_cpp_arg (const char *arg) { @@ -83,6 +97,28 @@ add_cpp_arg (const char *arg) cpp_argc++; } +void +add_cpp_sysinc (const char *arg) +{ + cpp_arg_t *cpp_arg = malloc (sizeof (cpp_arg_t)); + cpp_arg->next = 0; + cpp_arg->arg = arg; + *cpp_sysinc_tail = cpp_arg; + cpp_sysinc_tail = &(*cpp_sysinc_tail)->next; + cpp_argc++; +} + +void +add_cpp_undef (const char *arg) +{ + cpp_arg_t *cpp_arg = malloc (sizeof (cpp_arg_t)); + cpp_arg->next = 0; + cpp_arg->arg = arg; + *cpp_undef_tail = cpp_arg; + cpp_undef_tail = &(*cpp_undef_tail)->next; + cpp_argc++; +} + void add_cpp_def (const char *arg) { @@ -117,7 +153,6 @@ static void build_cpp_args (const char *in_name, const char *out_name) { cpp_arg_t *cpp_arg; - cpp_arg_t *cpp_def; const char **arg; if (cpp_argv) @@ -126,9 +161,12 @@ build_cpp_args (const char *in_name, const char *out_name) for (arg = cpp_argv, cpp_arg = cpp_arg_list; cpp_arg; cpp_arg = cpp_arg->next) { - if (!strcmp (cpp_arg->arg, "%d")) { - for (cpp_def = cpp_def_list; cpp_def; cpp_def = cpp_def->next) - *arg++ = cpp_def->arg; + if (!strcmp (cpp_arg->arg, "%u")) { + arg = append_cpp_args (arg, cpp_undef_list); + } else if (!strcmp (cpp_arg->arg, "%s")) { + arg = append_cpp_args (arg, cpp_sysinc_list); + } else if (!strcmp (cpp_arg->arg, "%d")) { + arg = append_cpp_args (arg, cpp_def_list); } else if (!strcmp (cpp_arg->arg, "%i")) { *arg++ = in_name; } else if (!strcmp (cpp_arg->arg, "%o")) { diff --git a/tools/qfcc/source/options.c b/tools/qfcc/source/options.c index cfd1e27bf..c3f283e89 100644 --- a/tools/qfcc/source/options.c +++ b/tools/qfcc/source/options.c @@ -299,6 +299,8 @@ DecodeArgs (int argc, char **argv) int c; int saw_E = 0, saw_MD = 0; + add_cpp_undef ("-undef"); + add_cpp_undef ("-nostdinc"); add_cpp_def ("-D__QFCC__=1"); add_cpp_def ("-D__QUAKEC__=1"); @@ -720,7 +722,8 @@ DecodeArgs (int argc, char **argv) // add the default paths if (!options.no_default_paths) { - add_cpp_def (nva ("-I%s", QFCC_INCLUDE_PATH)); + add_cpp_sysinc ("-isystem"); + add_cpp_sysinc (QFCC_INCLUDE_PATH); linker_add_path (QFCC_LIB_PATH); } From 79719babda27b73daf2ff437d0933fab60711e38 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 20 Mar 2020 12:55:23 +0900 Subject: [PATCH 087/435] [util] Fix darray test for gcc purity --- libs/util/test/test-darray.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/util/test/test-darray.c b/libs/util/test/test-darray.c index 59dbad0ab..59d3a2ddc 100644 --- a/libs/util/test/test-darray.c +++ b/libs/util/test/test-darray.c @@ -51,7 +51,7 @@ check_array (int a, int b) return !!intarray.a; } -static int +static int __attribute__((pure)) check_value (int index, int b) { if ((size_t) index >= intarray.size) { From c1ffb05b876c538a4de9914a7f6e1b5bc1192fe9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 25 Jun 2020 16:14:39 +0900 Subject: [PATCH 088/435] Remove dead Makefile.am Forgot this in the merge. --- libs/video/renderer/vulkan/Makefile.am | 35 -------------------------- 1 file changed, 35 deletions(-) delete mode 100644 libs/video/renderer/vulkan/Makefile.am diff --git a/libs/video/renderer/vulkan/Makefile.am b/libs/video/renderer/vulkan/Makefile.am deleted file mode 100644 index 707b6b064..000000000 --- a/libs/video/renderer/vulkan/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -AUTOMAKE_OPTIONS= foreign - -AM_CFLAGS= @PREFER_PIC@ -AM_CPPFLAGS= -I$(top_srcdir)/include -DVK_NO_PROTOTYPES - -vulkan_src = \ - buffer.c \ - command.c \ - descriptor.c \ - device.c \ - image.c \ - instance.c \ - memory.c \ - pipeline.c \ - renderpass.c \ - swapchain.c \ - util.c \ - vulkan_draw.c \ - vulkan_vid_common.c - -noinst_LTLIBRARIES= libvulkan.la -BUILT_SOURCES= $(shader_gen) - -SUFFICES=.frag .vert .fc .vc .slc .glsl -.glsl.slc: - sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ -.frag.fc: - sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ -.vert.vc: - sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ - -libvulkan_la_SOURCES= $(vulkan_src) - -EXTRA_DIST = $(vulkan_src) $(shader_src) namehack.h util.h -CLEANFILES= *.vc *.fc *.slc From c2559c7511d613c2ce80e9fc583c5463ff2df712 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 25 Jun 2020 19:38:33 +0900 Subject: [PATCH 089/435] [qwaq] PR_RunPostLoadFuncs for qwaq-x11 Same issue as for the menus. But now I know why PR_LoadProgsFile is used instead of PR_LoadProgs (at least for qwaq): avoidance of the gamedir restriction (however, the menus are supposed to be restricted). --- ruamoko/qwaq/builtins/qwaq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruamoko/qwaq/builtins/qwaq.c b/ruamoko/qwaq/builtins/qwaq.c index 111af8764..0a8070825 100644 --- a/ruamoko/qwaq/builtins/qwaq.c +++ b/ruamoko/qwaq/builtins/qwaq.c @@ -149,7 +149,7 @@ load_progs (const char *name) pr.zone_size = 1024*1024; PR_LoadProgsFile (&pr, file, size); Qclose (file); - if (!PR_RunLoadFuncs (&pr)) + if (!PR_RunLoadFuncs (&pr) || !PR_RunPostLoadFuncs (&pr)) PR_Error (&pr, "unable to load %s", pr.progs_name); return 1; } From 8f2bc18a4ffc08dc5d29357a8c2b20ccdc252177 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 25 Jun 2020 19:51:40 +0900 Subject: [PATCH 090/435] [build] Fix a merge error Messed up the vulkan headers. --- include/QF/Makemodule.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/QF/Makemodule.am b/include/QF/Makemodule.am index 9c691bddf..5282d5230 100644 --- a/include/QF/Makemodule.am +++ b/include/QF/Makemodule.am @@ -149,12 +149,13 @@ qf_gl_includedir = $(includedir)/QF/GL qf_glsl_includedir = $(includedir)/QF/GLSL qf_math_includedir = $(includedir)/QF/math qf_plugin_includedir = $(includedir)/QF/plugin +qf_vulkan_includedir = $(includedir)/QF/vulkan qf_include_HEADERS = @qfac_include_qf@ qf_gl_include_HEADERS = @qfac_include_qf_gl@ qf_glsl_include_HEADERS = @qfac_include_qf_glsl@ qf_math_include_HEADERS = @qfac_include_qf_math@ qf_plugin_include_HEADERS = @qfac_include_qf_plugin@ -qf_plugin_include_HEADERS = @qfac_include_qf_vulkan@ +qf_vulkan_include_HEADERS = @qfac_include_qf_vulkan@ ruamoko_qf_includedir = $(ruamoko_includedir)/QF ruamoko_qf_include_HEADERS = @qfac_qfcc_include_qf@ From ed42557dd1c0bc8fcd852917cdbb33ec693e6789 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 25 Jun 2020 22:45:12 +0900 Subject: [PATCH 091/435] [qfcc] Reset flowvars for aliased global variables When a global variable is accessed via only an alias in a function the actual def's flowvar would remain in the state it was from the last function that accessed the global normally. This would result in invalid flowvar accesses which can be difficult to reproduce (thus no test case). --- tools/qfcc/source/flow.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index e26bcef1b..86f6dc9d5 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -463,6 +463,15 @@ flow_build_statements (function_t *func) } } +static int flow_def_clear_flowvars (def_t *def, void *data) +{ + if (def->flowvar) { + delete_flowvar (def->flowvar); + } + def->flowvar = 0; + return 0; +} + /** Build an array of all the variables used by a function * * The array exists so variables can be referenced by number and thus used @@ -517,17 +526,26 @@ flow_build_vars (function_t *func) set_iter_t *var_i; flowvar_t *var; - // first, count .return and .param_[0-7] as they are always needed + // First, run through the statements making sure any accessed variables + // have their flowvars reset. Local variables will be fine, but global + // variables make have had flowvars added in a previous function, and it's + // easier to just clear them all. + // This is done before .return and .param so they won't get reset just + // after being counted + for (i = 0; i < func->num_statements; i++) { + s = func->statements[i]; + flow_analyze_statement (s, 0, 0, 0, operands); + for (j = 0; j < FLOW_OPERANDS; j++) { + if (operands[j] && operands[j]->op_type == op_def) { + def_visit_all (operands[j]->o.def, 0, + flow_def_clear_flowvars, 0); + } + } + } + // count .return and .param_[0-7] as they are always needed for (i = 0; i < num_flow_params; i++) { def_t *def = param_symbol (flow_params[i].name)->s.def; - def_t *a; - for (a = def->alias_defs; a; a = a->next) { - if (a->flowvar) { - delete_flowvar (a->flowvar); - a->flowvar = 0; - } - //free_def (def->alias_defs); - } + def_visit_all (def, 0, flow_def_clear_flowvars, 0); flow_params[i].op.o.def = def; num_vars += count_operand (&flow_params[i].op); } From aa8aaaaca9ce36582b0ed04297d5eefa451b8b44 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 26 Jun 2020 10:52:06 +0900 Subject: [PATCH 092/435] [build] Support silent rules for qfcc --- Makefile.am | 14 +++++- ruamoko/cl_menu/Makemodule.am | 2 +- ruamoko/game/Makemodule.am | 2 +- ruamoko/qwaq/Makemodule.am | 4 +- ruamoko/scheme/Makemodule.am | 2 +- tools/qfcc/test/Makemodule.am | 90 +++++++++++++++++------------------ 6 files changed, 62 insertions(+), 52 deletions(-) diff --git a/Makefile.am b/Makefile.am index 9e68af2a5..54ca7be00 100644 --- a/Makefile.am +++ b/Makefile.am @@ -70,6 +70,16 @@ QFCC_DEP=qfcc$(EXEEXT) QFCC=$(top_builddir)/$(QFCC_DEP) GZ=@progs_gz@ +V_QFCC = $(V_QFCC_@AM_V@) +V_QFCC_ = $(V_QFCC_@AM_DEFAULT_V@) +V_QFCC_0 = @echo " QFCC " $@; +V_QFCC_1 = + +V_QFCCLD = $(V_QFCCLD_@AM_V@) +V_QFCCLD_ = $(V_QFCCLD_@AM_DEFAULT_V@) +V_QFCCLD_0 = @echo " QFCCLD " $@; +V_QFCCLD_1 = + QCSYSTEM=--no-default-paths -I$(top_srcdir) -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide QCPPFLAGS=$(QCSYSTEM) @@ -82,12 +92,12 @@ am__mv = mv -f SUFFIXES=.o .r .pas .r.o: - depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(V_QFCC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ $(QCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tqo -c -o $@ $< &&\ sed -i -e '1s@:@: $(QFCC_DEP)@' $$depbase.Tqo &&\ $(am__mv) $$depbase.Tqo $$depbase.Qo .pas.o: - depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(V_QFCC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ $(QCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tqo -c -o $@ $< &&\ sed -i -e '1s@:@: $(QFCC_DEP)@' $$depbase.Tqo &&\ $(am__mv) $$depbase.Tqo $$depbase.Qo diff --git a/ruamoko/cl_menu/Makemodule.am b/ruamoko/cl_menu/Makemodule.am index dfa7635ba..c6c57aa7a 100644 --- a/ruamoko/cl_menu/Makemodule.am +++ b/ruamoko/cl_menu/Makemodule.am @@ -37,7 +37,7 @@ ruamoko_cl_menu_menu_dat_SOURCES=$(ruamoko_menu_src) ruamoko_menu_obj=$(ruamoko_cl_menu_menu_dat_SOURCES:.r=.o) ruamoko_menu_dep=$(call qcautodep,$(ruamoko_cl_menu_menu_dat_SOURCES)) ruamoko/cl_menu/menu.dat$(EXEEXT): $(ruamoko_menu_obj) $(QFCC_DEP) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a ruamoko/gui/libgui.a - $(QLINK) -o $@ $(ruamoko_menu_obj) -Lruamoko/gui -lgui -lcsqc -lr + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_menu_obj) -Lruamoko/gui -lgui -lcsqc -lr include $(ruamoko_menu_dep) # am--include-marker r_depfiles_remade += $(ruamoko_menu_dep) diff --git a/ruamoko/game/Makemodule.am b/ruamoko/game/Makemodule.am index 4063e9a62..576867c27 100644 --- a/ruamoko/game/Makemodule.am +++ b/ruamoko/game/Makemodule.am @@ -9,7 +9,7 @@ ruamoko_game_game_dat_SOURCES=$(ruamoko_game_src) ruamoko_game_obj=$(ruamoko_game_game_dat_SOURCES:.r=.o) ruamoko_game_dep=$(call qcautodep,$(ruamoko_game_game_dat_SOURCES)) ruamoko/game/game.dat$(EXEEXT): $(ruamoko_game_obj) $(QFCC_DEP) ruamoko/lib/libr.a ruamoko/lib/libqw.a - $(QLINK) -o $@ $(ruamoko_game_obj) -lqw -lr + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_game_obj) -lqw -lr include $(ruamoko_game_dep) # am--include-marker r_depfiles_remade += $(ruamoko_game_dep) diff --git a/ruamoko/qwaq/Makemodule.am b/ruamoko/qwaq/Makemodule.am index 149213268..bcb97af94 100644 --- a/ruamoko/qwaq/Makemodule.am +++ b/ruamoko/qwaq/Makemodule.am @@ -89,7 +89,7 @@ ruamoko_qwaq_qwaq_app_dat_SOURCES=$(qwaq_app_dat_src) ruamoko_qwaq_qwaq_app_obj=$(ruamoko_qwaq_qwaq_app_dat_SOURCES:.r=.o) ruamoko_qwaq_qwaq_app_dep=$(call qcautodep,$(ruamoko_qwaq_qwaq_app_dat_SOURCES:.o=.Qo)) ruamoko/qwaq/qwaq-app.dat$(EXEEXT): $(ruamoko_qwaq_qwaq_app_obj) $(QFCC_DEP) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a - $(QLINK) -o $@ $(ruamoko_qwaq_qwaq_app_obj) -lcsqc -lr + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_qwaq_app_obj) -lcsqc -lr include $(ruamoko_qwaq_qwaq_app_dep) # am--include-marker r_depfiles_remade += $(ruamoko_qwaq_qwaq_app_dep) @@ -97,7 +97,7 @@ ruamoko_qwaq_gcd_dat_SOURCES=ruamoko/qwaq/gcd.r ruamoko_qwaq_gcd_obj=$(ruamoko_qwaq_gcd_dat_SOURCES:.r=.o) ruamoko_qwaq_gcd_dep=$(call qcautodep,$(ruamoko_qwaq_gcd_dat_SOURCES:.o=.Qo)) ruamoko/qwaq/gcd.dat$(EXEEXT): $(ruamoko_qwaq_gcd_obj) $(QFCC_DEP) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a - $(QLINK) -o $@ $(ruamoko_qwaq_gcd_obj) -lcsqc -lr + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_qwaq_gcd_obj) -lcsqc -lr include $(ruamoko_qwaq_gcd_dep) # am--include-marker r_depfiles_remade += $(ruamoko_qwaq_gcd_dep) diff --git a/ruamoko/scheme/Makemodule.am b/ruamoko/scheme/Makemodule.am index b3fcfb5d9..8c1d43622 100644 --- a/ruamoko/scheme/Makemodule.am +++ b/ruamoko/scheme/Makemodule.am @@ -45,7 +45,7 @@ ruamoko_scheme_main_dat_SOURCES=$(ruamoko_scheme_src) ruamoko_scheme_main_obj=$(ruamoko_scheme_main_dat_SOURCES:.r=.o) ruamoko_scheme_main_dep=$(call qcautodep,$(ruamoko_scheme_main_dat_SOURCES)) ruamoko/scheme/main.dat$(EXEEXT): $(ruamoko_scheme_main_obj) $(QFCC_DEP) ruamoko/scheme/libscheme.a ruamoko/lib/libcsqc.a ruamoko/lib/libr.a - $(QLINK) -o $@ $(ruamoko_scheme_main_obj) -Lruamoko/scheme -lscheme -lcsqc -lr + $(V_QFCCLD)$(QLINK) -o $@ $(ruamoko_scheme_main_obj) -Lruamoko/scheme -lscheme -lcsqc -lr include $(ruamoko_scheme_main_dep) # am--include-marker r_depfiles_remade += $(ruamoko_scheme_main_dep) diff --git a/tools/qfcc/test/Makemodule.am b/tools/qfcc/test/Makemodule.am index 85f94b800..3eb33892b 100644 --- a/tools/qfcc/test/Makemodule.am +++ b/tools/qfcc/test/Makemodule.am @@ -102,7 +102,7 @@ tools_qfcc_test_address_cast_dat_SOURCES=tools/qfcc/test/address-cast.r address_cast_obj=$(tools_qfcc_test_address_cast_dat_SOURCES:.r=.o) address_cast_dep=$(call qcautodep,$(tools_qfcc_test_address_cast_dat_SOURCES)) tools/qfcc/test/address-cast.dat$(EXEEXT): $(address_cast_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(address_cast_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(address_cast_obj) tools/qfcc/test/address-cast.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(address_cast_dep) # am--include-marker @@ -112,7 +112,7 @@ tools_qfcc_test_alignment_dat_SOURCES=tools/qfcc/test/alignment.r alignment_obj=$(tools_qfcc_test_alignment_dat_SOURCES:.r=.o) alignment_dep=$(call qcautodep,$(tools_qfcc_test_alignment_dat_SOURCES)) tools/qfcc/test/alignment.dat$(EXEEXT): $(alignment_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(alignment_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(alignment_obj) tools/qfcc/test/alignment.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(alignment_dep) # am--include-marker @@ -122,7 +122,7 @@ tools_qfcc_test_anonstruct_dat_SOURCES=tools/qfcc/test/anonstruct.r anonstruct_obj=$(tools_qfcc_test_anonstruct_dat_SOURCES:.r=.o) anonstruct_dep=$(call qcautodep,$(tools_qfcc_test_anonstruct_dat_SOURCES)) tools/qfcc/test/anonstruct.dat$(EXEEXT): $(anonstruct_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(anonstruct_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(anonstruct_obj) tools/qfcc/test/anonstruct.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(anonstruct_dep) # am--include-marker @@ -132,7 +132,7 @@ tools_qfcc_test_assignchain_dat_SOURCES=tools/qfcc/test/assignchain.r assignchain_obj=$(tools_qfcc_test_assignchain_dat_SOURCES:.r=.o) assignchain_dep=$(call qcautodep,$(tools_qfcc_test_assignchain_dat_SOURCES)) tools/qfcc/test/assignchain.dat$(EXEEXT): $(assignchain_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(assignchain_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(assignchain_obj) tools/qfcc/test/assignchain.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(assignchain_dep) # am--include-marker @@ -142,7 +142,7 @@ tools_qfcc_test_chewed_alias_dat_SOURCES=tools/qfcc/test/chewed-alias.r chewed_alias_obj=$(tools_qfcc_test_chewed_alias_dat_SOURCES:.r=.o) chewed_alias_dep=$(call qcautodep,$(tools_qfcc_test_chewed_alias_dat_SOURCES)) tools/qfcc/test/chewed-alias.dat$(EXEEXT): $(chewed_alias_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(chewed_alias_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(chewed_alias_obj) tools/qfcc/test/chewed-alias.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(chewed_alias_dep) # am--include-marker @@ -152,7 +152,7 @@ tools_qfcc_test_chewed_return_dat_SOURCES=tools/qfcc/test/chewed-return.r chewed_return_obj=$(tools_qfcc_test_chewed_return_dat_SOURCES:.r=.o) chewed_return_dep=$(call qcautodep,$(tools_qfcc_test_chewed_return_dat_SOURCES)) tools/qfcc/test/chewed-return.dat$(EXEEXT): $(chewed_return_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(chewed_return_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(chewed_return_obj) tools/qfcc/test/chewed-return.run: $(qfcc_test_run_deps) @TEST_HARNESS_OPTS=--float $(top_srcdir)/tools/qfcc/test/build-run $@ include $(chewed_return_dep) # am--include-marker @@ -162,7 +162,7 @@ tools_qfcc_test_comma_expr_dat_SOURCES=tools/qfcc/test/comma-expr.r comma_expr_obj=$(tools_qfcc_test_comma_expr_dat_SOURCES:.r=.o) comma_expr_dep=$(call qcautodep,$(tools_qfcc_test_comma_expr_dat_SOURCES)) tools/qfcc/test/comma-expr.dat$(EXEEXT): $(comma_expr_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(comma_expr_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(comma_expr_obj) tools/qfcc/test/comma-expr.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(comma_expr_dep) # am--include-marker @@ -172,7 +172,7 @@ tools_qfcc_test_compound_dat_SOURCES=tools/qfcc/test/compound.r compound_obj=$(tools_qfcc_test_compound_dat_SOURCES:.r=.o) compound_dep=$(call qcautodep,$(tools_qfcc_test_compound_dat_SOURCES)) tools/qfcc/test/compound.dat$(EXEEXT): $(compound_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(compound_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(compound_obj) tools/qfcc/test/compound.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(compound_dep) # am--include-marker @@ -182,7 +182,7 @@ tools_qfcc_test_deadbool_dat_SOURCES=tools/qfcc/test/deadbool.r deadbool_obj=$(tools_qfcc_test_deadbool_dat_SOURCES:.r=.o) deadbool_dep=$(call qcautodep,$(tools_qfcc_test_deadbool_dat_SOURCES)) tools/qfcc/test/deadbool.dat$(EXEEXT): $(deadbool_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(deadbool_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(deadbool_obj) tools/qfcc/test/deadbool.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(deadbool_dep) # am--include-marker @@ -192,7 +192,7 @@ tools_qfcc_test_double_dat_SOURCES=tools/qfcc/test/double.r double_obj=$(tools_qfcc_test_double_dat_SOURCES:.r=.o) double_dep=$(call qcautodep,$(tools_qfcc_test_double_dat_SOURCES)) tools/qfcc/test/double.dat$(EXEEXT): $(double_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(double_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(double_obj) tools/qfcc/test/double.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(double_dep) # am--include-marker @@ -202,7 +202,7 @@ tools_qfcc_test_double_alias_dat_SOURCES=tools/qfcc/test/double-alias.r double_alias_obj=$(tools_qfcc_test_double_alias_dat_SOURCES:.r=.o) double_alias_dep=$(call qcautodep,$(tools_qfcc_test_double_alias_dat_SOURCES)) tools/qfcc/test/double-alias.dat$(EXEEXT): $(double_alias_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(double_alias_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(double_alias_obj) tools/qfcc/test/double-alias.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(double_alias_dep) # am--include-marker @@ -245,7 +245,7 @@ tools_qfcc_test_enum_dat_SOURCES=tools/qfcc/test/enum.r enum_obj=$(tools_qfcc_test_enum_dat_SOURCES:.r=.o) enum_dep=$(call qcautodep,$(tools_qfcc_test_enum_dat_SOURCES)) tools/qfcc/test/enum.dat$(EXEEXT): $(enum_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(enum_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(enum_obj) tools/qfcc/test/enum.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(enum_dep) # am--include-marker @@ -255,7 +255,7 @@ tools_qfcc_test_fordecl_dat_SOURCES=tools/qfcc/test/fordecl.r fordecl_obj=$(tools_qfcc_test_fordecl_dat_SOURCES:.r=.o) fordecl_dep=$(call qcautodep,$(tools_qfcc_test_fordecl_dat_SOURCES)) tools/qfcc/test/fordecl.dat$(EXEEXT): $(fordecl_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(fordecl_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(fordecl_obj) tools/qfcc/test/fordecl.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(fordecl_dep) # am--include-marker @@ -265,7 +265,7 @@ tools_qfcc_test_func_expr_dat_SOURCES=tools/qfcc/test/func-expr.r func_expr_obj=$(tools_qfcc_test_func_expr_dat_SOURCES:.r=.o) func_expr_dep=$(call qcautodep,$(tools_qfcc_test_func_expr_dat_SOURCES)) tools/qfcc/test/func-expr.dat$(EXEEXT): $(func_expr_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(func_expr_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(func_expr_obj) tools/qfcc/test/func-expr.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(func_expr_dep) # am--include-marker @@ -275,7 +275,7 @@ tools_qfcc_test_func_expr2_dat_SOURCES=tools/qfcc/test/func-expr2.r func_expr2_obj=$(tools_qfcc_test_func_expr2_dat_SOURCES:.r=.o) func_expr2_dep=$(call qcautodep,$(tools_qfcc_test_func_expr2_dat_SOURCES)) tools/qfcc/test/func-expr2.dat$(EXEEXT): $(func_expr2_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(func_expr2_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(func_expr2_obj) tools/qfcc/test/func-expr2.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(func_expr2_dep) # am--include-marker @@ -285,7 +285,7 @@ tools_qfcc_test_func_static_dat_SOURCES=tools/qfcc/test/func-static.r func_static_obj=$(tools_qfcc_test_func_static_dat_SOURCES:.r=.o) func_static_dep=$(call qcautodep,$(tools_qfcc_test_func_static_dat_SOURCES)) tools/qfcc/test/func-static.dat$(EXEEXT): $(func_static_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(func_static_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(func_static_obj) tools/qfcc/test/func-static.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(func_static_dep) # am--include-marker @@ -295,7 +295,7 @@ tools_qfcc_test_gcd_dat_SOURCES=tools/qfcc/test/gcd.pas gcd_obj=$(tools_qfcc_test_gcd_dat_SOURCES:.pas=.o) gcd_dep=$(call qcautodep,$(tools_qfcc_test_gcd_dat_SOURCES)) tools/qfcc/test/gcd.dat$(EXEEXT): $(gcd_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(gcd_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(gcd_obj) tools/qfcc/test/gcd.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(gcd_dep) # am--include-marker @@ -305,7 +305,7 @@ tools_qfcc_test_infloop_dat_SOURCES=tools/qfcc/test/infloop.r infloop_obj=$(tools_qfcc_test_infloop_dat_SOURCES:.r=.o) infloop_dep=$(call qcautodep,$(tools_qfcc_test_infloop_dat_SOURCES)) tools/qfcc/test/infloop.dat$(EXEEXT): $(infloop_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(infloop_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(infloop_obj) tools/qfcc/test/infloop.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(infloop_dep) # am--include-marker @@ -315,7 +315,7 @@ tools_qfcc_test_ivar_struct_return_dat_SOURCES=tools/qfcc/test/ivar-struct-retur ivar_struct_return_obj=$(tools_qfcc_test_ivar_struct_return_dat_SOURCES:.r=.o) ivar_struct_return_dep=$(call qcautodep,$(tools_qfcc_test_ivar_struct_return_dat_SOURCES)) tools/qfcc/test/ivar-struct-return.dat$(EXEEXT): $(ivar_struct_return_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(ivar_struct_return_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(ivar_struct_return_obj) tools/qfcc/test/ivar-struct-return.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(ivar_struct_return_dep) # am--include-marker @@ -325,7 +325,7 @@ tools_qfcc_test_methodparams_dat_SOURCES=tools/qfcc/test/methodparams.r methodparams_obj=$(tools_qfcc_test_methodparams_dat_SOURCES:.r=.o) methodparams_dep=$(call qcautodep,$(tools_qfcc_test_methodparams_dat_SOURCES)) tools/qfcc/test/methodparams.dat$(EXEEXT): $(methodparams_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(methodparams_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(methodparams_obj) tools/qfcc/test/methodparams.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(methodparams_dep) # am--include-marker @@ -335,7 +335,7 @@ tools_qfcc_test_modulo_dat_SOURCES=tools/qfcc/test/modulo.r modulo_obj=$(tools_qfcc_test_modulo_dat_SOURCES:.r=.o) modulo_dep=$(call qcautodep,$(tools_qfcc_test_modulo_dat_SOURCES)) tools/qfcc/test/modulo.dat$(EXEEXT): $(modulo_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(modulo_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(modulo_obj) tools/qfcc/test/modulo.run: $(qfcc_test_run_deps) @TEST_HARNESS_OPTS=--float $(top_srcdir)/tools/qfcc/test/build-run $@ include $(modulo_dep) # am--include-marker @@ -345,7 +345,7 @@ tools_qfcc_test_nilparamret_dat_SOURCES=tools/qfcc/test/nilparamret.r nilparamret_obj=$(tools_qfcc_test_nilparamret_dat_SOURCES:.r=.o) nilparamret_dep=$(call qcautodep,$(tools_qfcc_test_nilparamret_dat_SOURCES)) tools/qfcc/test/nilparamret.dat$(EXEEXT): $(nilparamret_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(nilparamret_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(nilparamret_obj) tools/qfcc/test/nilparamret.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(nilparamret_dep) # am--include-marker @@ -355,7 +355,7 @@ tools_qfcc_test_overload_dat_SOURCES=tools/qfcc/test/overload.r overload_obj=$(tools_qfcc_test_overload_dat_SOURCES:.r=.o) overload_dep=$(call qcautodep,$(tools_qfcc_test_overload_dat_SOURCES)) tools/qfcc/test/overload.dat$(EXEEXT): $(overload_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(overload_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(overload_obj) tools/qfcc/test/overload.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(overload_dep) # am--include-marker @@ -365,7 +365,7 @@ tools_qfcc_test_paramret_dat_SOURCES=tools/qfcc/test/paramret.r paramret_obj=$(tools_qfcc_test_paramret_dat_SOURCES:.r=.o) paramret_dep=$(call qcautodep,$(tools_qfcc_test_paramret_dat_SOURCES)) tools/qfcc/test/paramret.dat$(EXEEXT): $(paramret_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(paramret_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(paramret_obj) tools/qfcc/test/paramret.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(paramret_dep) # am--include-marker @@ -375,7 +375,7 @@ tools_qfcc_test_quaternion_dat_SOURCES=tools/qfcc/test/quaternion.r quaternion_obj=$(tools_qfcc_test_quaternion_dat_SOURCES:.r=.o) quaternion_dep=$(call qcautodep,$(tools_qfcc_test_quaternion_dat_SOURCES)) tools/qfcc/test/quaternion.dat$(EXEEXT): $(quaternion_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(quaternion_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(quaternion_obj) tools/qfcc/test/quaternion.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(quaternion_dep) # am--include-marker @@ -385,7 +385,7 @@ tools_qfcc_test_return_ivar_dat_SOURCES=tools/qfcc/test/return-ivar.r return_ivar_obj=$(tools_qfcc_test_return_ivar_dat_SOURCES:.r=.o) return_ivar_dep=$(call qcautodep,$(tools_qfcc_test_return_ivar_dat_SOURCES)) tools/qfcc/test/return-ivar.dat$(EXEEXT): $(return_ivar_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(return_ivar_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(return_ivar_obj) tools/qfcc/test/return-ivar.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(return_ivar_dep) # am--include-marker @@ -395,7 +395,7 @@ tools_qfcc_test_sendv_dat_SOURCES=tools/qfcc/test/sendv.r sendv_obj=$(tools_qfcc_test_sendv_dat_SOURCES:.r=.o) sendv_dep=$(call qcautodep,$(tools_qfcc_test_sendv_dat_SOURCES)) tools/qfcc/test/sendv.dat$(EXEEXT): $(sendv_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(sendv_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(sendv_obj) tools/qfcc/test/sendv.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(sendv_dep) # am--include-marker @@ -405,7 +405,7 @@ tools_qfcc_test_state_dat_SOURCES=tools/qfcc/test/state.r state_obj=$(tools_qfcc_test_state_dat_SOURCES:.r=.o) state_dep=$(call qcautodep,$(tools_qfcc_test_state_dat_SOURCES)) tools/qfcc/test/state.dat$(EXEEXT): $(state_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(state_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(state_obj) tools/qfcc/test/state.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(state_dep) # am--include-marker @@ -415,7 +415,7 @@ tools_qfcc_test_struct_init_param_dat_SOURCES=tools/qfcc/test/struct-init-param. struct_init_param_obj=$(tools_qfcc_test_struct_init_param_dat_SOURCES:.r=.o) struct_init_param_dep=$(call qcautodep,$(tools_qfcc_test_struct_init_param_dat_SOURCES)) tools/qfcc/test/struct-init-param.dat$(EXEEXT): $(struct_init_param_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(struct_init_param_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(struct_init_param_obj) tools/qfcc/test/struct-init-param.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(struct_init_param_dep) # am--include-marker @@ -425,7 +425,7 @@ tools_qfcc_test_struct_nil_init_dat_SOURCES=tools/qfcc/test/struct-nil-init.r struct_nil_init_obj=$(tools_qfcc_test_struct_nil_init_dat_SOURCES:.r=.o) struct_nil_init_dep=$(call qcautodep,$(tools_qfcc_test_struct_nil_init_dat_SOURCES)) tools/qfcc/test/struct-nil-init.dat$(EXEEXT): $(struct_nil_init_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(struct_nil_init_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(struct_nil_init_obj) tools/qfcc/test/struct-nil-init.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(struct_nil_init_dep) # am--include-marker @@ -435,7 +435,7 @@ tools_qfcc_test_structarray_dat_SOURCES=tools/qfcc/test/structarray.r structarray_obj=$(tools_qfcc_test_structarray_dat_SOURCES:.r=.o) structarray_dep=$(call qcautodep,$(tools_qfcc_test_structarray_dat_SOURCES)) tools/qfcc/test/structarray.dat$(EXEEXT): $(structarray_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(structarray_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(structarray_obj) tools/qfcc/test/structarray.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(structarray_dep) # am--include-marker @@ -445,7 +445,7 @@ tools_qfcc_test_structlive_dat_SOURCES=tools/qfcc/test/structlive.r structlive_obj=$(tools_qfcc_test_structlive_dat_SOURCES:.r=.o) structlive_dep=$(call qcautodep,$(tools_qfcc_test_structlive_dat_SOURCES)) tools/qfcc/test/structlive.dat$(EXEEXT): $(structlive_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(structlive_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(structlive_obj) tools/qfcc/test/structlive.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(structlive_dep) # am--include-marker @@ -455,7 +455,7 @@ tools_qfcc_test_structptr_dat_SOURCES=tools/qfcc/test/structptr.r structptr_obj=$(tools_qfcc_test_structptr_dat_SOURCES:.r=.o) structptr_dep=$(call qcautodep,$(tools_qfcc_test_structptr_dat_SOURCES)) tools/qfcc/test/structptr.dat$(EXEEXT): $(structptr_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(structptr_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(structptr_obj) tools/qfcc/test/structptr.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(structptr_dep) # am--include-marker @@ -465,7 +465,7 @@ tools_qfcc_test_structstruct_dat_SOURCES=tools/qfcc/test/structstruct.r structstruct_obj=$(tools_qfcc_test_structstruct_dat_SOURCES:.r=.o) structstruct_dep=$(call qcautodep,$(tools_qfcc_test_structstruct_dat_SOURCES)) tools/qfcc/test/structstruct.dat$(EXEEXT): $(structstruct_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(structstruct_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(structstruct_obj) tools/qfcc/test/structstruct.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(structstruct_dep) # am--include-marker @@ -475,7 +475,7 @@ tools_qfcc_test_swap_dat_SOURCES=tools/qfcc/test/swap.r swap_obj=$(tools_qfcc_test_swap_dat_SOURCES:.r=.o) swap_dep=$(call qcautodep,$(tools_qfcc_test_swap_dat_SOURCES)) tools/qfcc/test/swap.dat$(EXEEXT): $(swap_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(swap_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(swap_obj) tools/qfcc/test/swap.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(swap_dep) # am--include-marker @@ -485,7 +485,7 @@ tools_qfcc_test_triangle_dat_SOURCES=tools/qfcc/test/triangle.r triangle_obj=$(tools_qfcc_test_triangle_dat_SOURCES:.r=.o) triangle_dep=$(call qcautodep,$(tools_qfcc_test_triangle_dat_SOURCES)) tools/qfcc/test/triangle.dat$(EXEEXT): $(triangle_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(triangle_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(triangle_obj) tools/qfcc/test/triangle.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ 100000 100000 1.00005 50002.4961 include $(triangle_dep) # am--include-marker @@ -495,7 +495,7 @@ tools_qfcc_test_typedef_dat_SOURCES=tools/qfcc/test/typedef.r typedef_obj=$(tools_qfcc_test_typedef_dat_SOURCES:.r=.o) typedef_dep=$(call qcautodep,$(tools_qfcc_test_typedef_dat_SOURCES)) tools/qfcc/test/typedef.dat$(EXEEXT): $(typedef_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(typedef_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(typedef_obj) tools/qfcc/test/typedef.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(typedef_dep) # am--include-marker @@ -505,7 +505,7 @@ tools_qfcc_test_typelinker_dat_SOURCES=tools/qfcc/test/typelinker_a.r tools/qfcc typelinker_obj=$(tools_qfcc_test_typelinker_dat_SOURCES:.r=.o) typelinker_dep=$(call qcautodep,$(tools_qfcc_test_typelinker_dat_SOURCES)) tools/qfcc/test/typelinker.dat$(EXEEXT): $(typelinker_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(typelinker_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(typelinker_obj) tools/qfcc/test/typelinker.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(typelinker_dep) # am--include-marker @@ -515,7 +515,7 @@ tools_qfcc_test_unaryminus_dat_SOURCES=tools/qfcc/test/unaryminus.r unaryminus_obj=$(tools_qfcc_test_unaryminus_dat_SOURCES:.r=.o) unaryminus_dep=$(call qcautodep,$(tools_qfcc_test_unaryminus_dat_SOURCES)) tools/qfcc/test/unaryminus.dat$(EXEEXT): $(unaryminus_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(unaryminus_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(unaryminus_obj) tools/qfcc/test/unaryminus.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(unaryminus_dep) # am--include-marker @@ -525,7 +525,7 @@ tools_qfcc_test_vecaddr_dat_SOURCES=tools/qfcc/test/vecaddr.r vecaddr_obj=$(tools_qfcc_test_vecaddr_dat_SOURCES:.r=.o) vecaddr_dep=$(call qcautodep,$(tools_qfcc_test_vecaddr_dat_SOURCES)) tools/qfcc/test/vecaddr.dat$(EXEEXT): $(vecaddr_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(vecaddr_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(vecaddr_obj) tools/qfcc/test/vecaddr.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(vecaddr_dep) # am--include-marker @@ -535,7 +535,7 @@ tools_qfcc_test_vecexpr_dat_SOURCES=tools/qfcc/test/vecexpr.r vecexpr_obj=$(tools_qfcc_test_vecexpr_dat_SOURCES:.r=.o) vecexpr_dep=$(call qcautodep,$(tools_qfcc_test_vecexpr_dat_SOURCES)) tools/qfcc/test/vecexpr.dat$(EXEEXT): $(vecexpr_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(vecexpr_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(vecexpr_obj) tools/qfcc/test/vecexpr.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(vecexpr_dep) # am--include-marker @@ -545,7 +545,7 @@ tools_qfcc_test_vecinit_dat_SOURCES=tools/qfcc/test/vecinit.r vecinit_obj=$(tools_qfcc_test_vecinit_dat_SOURCES:.r=.o) vecinit_dep=$(call qcautodep,$(tools_qfcc_test_vecinit_dat_SOURCES)) tools/qfcc/test/vecinit.dat$(EXEEXT): $(vecinit_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(vecinit_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(vecinit_obj) tools/qfcc/test/vecinit.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(vecinit_dep) # am--include-marker @@ -555,7 +555,7 @@ tools_qfcc_test_voidfor_dat_SOURCES=tools/qfcc/test/voidfor.r voidfor_obj=$(tools_qfcc_test_voidfor_dat_SOURCES:.r=.o) voidfor_dep=$(call qcautodep,$(tools_qfcc_test_voidfor_dat_SOURCES)) tools/qfcc/test/voidfor.dat$(EXEEXT): $(voidfor_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(voidfor_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(voidfor_obj) tools/qfcc/test/voidfor.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(voidfor_dep) # am--include-marker @@ -565,7 +565,7 @@ tools_qfcc_test_while_dat_SOURCES=tools/qfcc/test/while.r while_obj=$(tools_qfcc_test_while_dat_SOURCES:.r=.o) while_dep=$(call qcautodep,$(tools_qfcc_test_while_dat_SOURCES)) tools/qfcc/test/while.dat$(EXEEXT): $(while_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(while_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(while_obj) tools/qfcc/test/while.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(while_dep) # am--include-marker @@ -575,7 +575,7 @@ tools_qfcc_test_zerolinker_dat_SOURCES=tools/qfcc/test/zerolinker.r zerolinker_obj=$(tools_qfcc_test_zerolinker_dat_SOURCES:.r=.o) zerolinker_dep=$(call qcautodep,$(tools_qfcc_test_zerolinker_dat_SOURCES)) tools/qfcc/test/zerolinker.dat$(EXEEXT): $(zerolinker_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(zerolinker_obj) + $(V_QFCCLD)$(QLINK) -o $@ $(zerolinker_obj) tools/qfcc/test/zerolinker.run: $(qfcc_test_run_deps) @$(top_srcdir)/tools/qfcc/test/build-run $@ include $(zerolinker_dep) # am--include-marker From 19c75f5e499d569564cf61d95e91cd5cbba589df Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 28 Jun 2020 13:53:11 +0900 Subject: [PATCH 093/435] [vulkan] Clean up QFV_CreateFramebuffer's prototype It now takes qfv_imageviewset_t instead of separate count and VkImageView array. --- include/QF/Vulkan/renderpass.h | 4 ++-- libs/video/renderer/vulkan/renderpass.c | 4 ++-- libs/video/renderer/vulkan/vulkan_vid_common.c | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/QF/Vulkan/renderpass.h b/include/QF/Vulkan/renderpass.h index 9a197ac70..49134c730 100644 --- a/include/QF/Vulkan/renderpass.h +++ b/include/QF/Vulkan/renderpass.h @@ -28,6 +28,7 @@ typedef struct qfv_subpassdependency_s DARRAY_ALLOCFIXED (qfv_subpassdependency_t, num, allocator) struct qfv_device_s; +struct qfv_imageviewset_s; VkRenderPass QFV_CreateRenderPass (struct qfv_device_s *device, qfv_attachmentdescription_t *attachments, @@ -37,8 +38,7 @@ QFV_CreateRenderPass (struct qfv_device_s *device, VkFramebuffer QFV_CreateFramebuffer (struct qfv_device_s *device, VkRenderPass renderPass, - uint32_t numAttachments, - VkImageView *attachments, + struct qfv_imageviewset_s *attachments, VkExtent2D, uint32_t layers); #endif//__QF_Vulkan_renderpass_h diff --git a/libs/video/renderer/vulkan/renderpass.c b/libs/video/renderer/vulkan/renderpass.c index e61005278..40bc095ad 100644 --- a/libs/video/renderer/vulkan/renderpass.c +++ b/libs/video/renderer/vulkan/renderpass.c @@ -85,7 +85,7 @@ QFV_CreateRenderPass (qfv_device_t *device, VkFramebuffer QFV_CreateFramebuffer (qfv_device_t *device, VkRenderPass renderPass, - uint32_t numAttachments, VkImageView *attachments, + qfv_imageviewset_t *attachments, VkExtent2D extent, uint32_t layers) { VkDevice dev = device->dev; @@ -93,7 +93,7 @@ QFV_CreateFramebuffer (qfv_device_t *device, VkRenderPass renderPass, VkFramebufferCreateInfo createInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 0, 0, - renderPass, numAttachments, attachments, + renderPass, attachments->size, attachments->a, extent.width, extent.height, layers, }; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 452a74eb8..68dd2bbe8 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -445,9 +445,8 @@ Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) attachments->a[2] = sc->imageViews->a[i]; __auto_type frame = &ctx->framebuffers.a[i]; frame->framebuffer = QFV_CreateFramebuffer (device, renderpass, - attachments->size, - attachments->a, - sc->extent, 1); + attachments, + sc->extent, 1); frame->fence = QFV_CreateFence (device, 1); frame->imageAvailableSemaphore = QFV_CreateSemaphore (device); frame->renderDoneSemaphore = QFV_CreateSemaphore (device); From 7f96b0fbedb0a5a5e91bd20c9753c26321646898 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 28 Jun 2020 18:30:01 +0900 Subject: [PATCH 094/435] [qwaq] Fix incorrect setting of progs argc/argv --- ruamoko/qwaq/builtins/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ruamoko/qwaq/builtins/main.c b/ruamoko/qwaq/builtins/main.c index da3607c01..931d33337 100644 --- a/ruamoko/qwaq/builtins/main.c +++ b/ruamoko/qwaq/builtins/main.c @@ -223,13 +223,13 @@ spawn_progs (qwaq_thread_t *thread) } PR_PushFrame (pr); - if (thread->args.size > 2) { - pr_argc = thread->args.size - 1; + if (thread->args.size) { + pr_argc = thread->args.size; } pr_argv = PR_Zone_Malloc (pr, (pr_argc + 1) * 4); pr_argv[0] = PR_SetTempString (pr, name); for (i = 1; i < pr_argc; i++) - pr_argv[i] = PR_SetTempString (pr, thread->args.a[1 + i]); + pr_argv[i] = PR_SetTempString (pr, thread->args.a[i]); pr_argv[i] = 0; PR_RESET_PARAMS (pr); From 6d4e370a258f2682c4c90c9a139f42f7579fbadf Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 28 Jun 2020 18:48:38 +0900 Subject: [PATCH 095/435] [ruamoko] Handle 0-length @va_list for va_copy Fixes a progs crash when using vsprintf with no format elements + params. --- libs/ruamoko/rua_runtime.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libs/ruamoko/rua_runtime.c b/libs/ruamoko/rua_runtime.c index 697fc720b..24a8a894d 100644 --- a/libs/ruamoko/rua_runtime.c +++ b/libs/ruamoko/rua_runtime.c @@ -56,8 +56,13 @@ bi_va_copy (progs_t *pr) __auto_type src_list = &G_STRUCT (pr, pr_type_t, src_args->list); size_t parm_size = pr->pr_param_size * sizeof(pr_type_t); size_t size = src_args->count * parm_size; - string_t dst_list_block = PR_AllocTempBlock (pr, size); - __auto_type dst_list = (pr_type_t *) PR_GetString (pr, dst_list_block); + string_t dst_list_block = 0; + pr_type_t *dst_list = 0; + + if (size) { + dst_list_block = PR_AllocTempBlock (pr, size); + dst_list = (pr_type_t *) PR_GetString (pr, dst_list_block); + } memcpy (dst_list, src_list, size); R_PACKED (pr, pr_va_list_t).count = src_args->count; From cf3262991d68ca90ab71518592d45e4768b5d6ac Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 28 Jun 2020 19:08:18 +0900 Subject: [PATCH 096/435] [vulkan] Add a tool for making vulkan enum tables The tables are generated from the enums pulled out of the vulkan headers using a ruamoko program (thanks to its reflection capabilities). They will be used for parsing property lists used to create render passes and pipelines. --- libs/video/renderer/Makemodule.am | 7 + .../video/renderer/vulkan/vkgen/Makemodule.am | 34 ++ libs/video/renderer/vulkan/vkgen/stddef.h | 2 + libs/video/renderer/vulkan/vkgen/stdint.h | 11 + libs/video/renderer/vulkan/vkgen/vkgen.r | 431 ++++++++++++++++++ libs/video/renderer/vulkan/vkgen/vulkan.r | 2 + 6 files changed, 487 insertions(+) create mode 100644 libs/video/renderer/vulkan/vkgen/Makemodule.am create mode 100644 libs/video/renderer/vulkan/vkgen/stddef.h create mode 100644 libs/video/renderer/vulkan/vkgen/stdint.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkgen.r create mode 100644 libs/video/renderer/vulkan/vkgen/vulkan.r diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 65b594549..b1196dc2f 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -1,3 +1,5 @@ +include libs/video/renderer/vulkan/vkgen/Makemodule.am + #lib_LTLIBRARIES += @VID_REND_TARGETS@ plugin_LTLIBRARIES += @vid_render_plugins@ noinst_LTLIBRARIES += libs/video/renderer/libQFrenderer.la @vid_render_static_plugins@ @@ -217,6 +219,11 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/vulkan_draw.c \ libs/video/renderer/vulkan/vulkan_vid_common.c +qwaq_curses = ruamoko/qwaq/qwaq-curses$(EXEEXT) +BUILT_SOURCES += libs/video/renderer/vulkan/vkenum.inc +libs/video/renderer/vulkan/vkenum.inc: $(vkgen) $(qwaq_curses) + $(qwaq_curses) $(vkgen) -- $@ + CLEANFILES += \ libs/video/renderer/glsl/*.vc \ libs/video/renderer/glsl/*.fc \ diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am new file mode 100644 index 000000000..901dea622 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -0,0 +1,34 @@ +vkgen = libs/video/renderer/vulkan/vkgen.dat$(EXEEXT) +noinst_PROGRAMS += $(vkgen) + +vkgen_dat_src= \ + libs/video/renderer/vulkan/vkgen/vkgen.r \ + libs/video/renderer/vulkan/vkgen/vulkan.r + +VKGENFLAGS = -I$(top_srcdir)/libs/video/renderer/vulkan/vkgen + +libs_video_renderer_vulkan_vkgen_dat_SOURCES=$(vkgen_dat_src) +libs_video_renderer_vkgen_obj=$(libs_video_renderer_vulkan_vkgen_dat_SOURCES:.r=.o) +libs_video_renderer_vkgen_dep=$(call qcautodep,$(libs_video_renderer_vulkan_vkgen_dat_SOURCES:.o=.Qo)) +libs/video/renderer/vulkan/vkgen.dat$(EXEEXT): $(libs_video_renderer_vkgen_obj) $(QFCC_DEP) ruamoko/lib/libcsqc.a ruamoko/lib/libr.a + $(V_QFCCLD)$(QLINK) -o $@ $(libs_video_renderer_vkgen_obj) -lcsqc -lr +include $(libs_video_renderer_vkgen_dep) # am--include-marker +r_depfiles_remade += $(libs_video_renderer_vkgen_dep) + +libs/video/renderer/vulkan/vkgen/vkgen.o: $(top_srcdir)/libs/video/renderer/vulkan/vkgen/vkgen.r + $(V_QFCC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(QCOMPILE) ${VKGENFLAGS} -MT $@ -MD -MP -MF $$depbase.Tqo -c -o $@ $< &&\ + sed -i -e '1s@:@: $(QFCC_DEP)@' $$depbase.Tqo &&\ + $(am__mv) $$depbase.Tqo $$depbase.Qo + +libs/video/renderer/vulkan/vkgen/vulkan.o: $(top_srcdir)/libs/video/renderer/vulkan/vkgen/vulkan.r + $(V_QFCC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ + $(QCOMPILE) ${VKGENFLAGS} -MT $@ -MD -MP -MF $$depbase.Tqo -c -o $@ $< &&\ + sed -i -e '1s@:@: $(QFCC_DEP)@' $$depbase.Tqo &&\ + $(am__mv) $$depbase.Tqo $$depbase.Qo + +EXTRA_DIST += \ + libs/video/renderer/vulkan/vkgen/stddef.h \ + libs/video/renderer/vulkan/vkgen/stdint.h +CLEANFILES += \ + libs/video/renderer/vkgen/*.sym diff --git a/libs/video/renderer/vulkan/vkgen/stddef.h b/libs/video/renderer/vulkan/vkgen/stddef.h new file mode 100644 index 000000000..5252efc1d --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/stddef.h @@ -0,0 +1,2 @@ +#define const +#define __attribute__(x) diff --git a/libs/video/renderer/vulkan/vkgen/stdint.h b/libs/video/renderer/vulkan/vkgen/stdint.h new file mode 100644 index 000000000..04fc06933 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/stdint.h @@ -0,0 +1,11 @@ +typedef int uint8_t; +typedef int uint16_t; +typedef int uint32_t; +typedef int uint64_t; +typedef int int8_t; +typedef int int16_t; +typedef int int32_t; +typedef int int64_t; +typedef int size_t; +typedef int long; +typedef int char; diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r new file mode 100644 index 000000000..1400d3fbc --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -0,0 +1,431 @@ +#include +#include +#include +#include +#include +#include + +void printf (string fmt, ...) = #0; + +void fprintf (QFile file, string format, ...) +{ + printf("fprintf %d\n", @args.count); + Qputs (file, vsprintf (format, va_copy (@args))); +} + +typedef void varfunc (qfot_var_t *var); + +string search_names[] = { + "VkGraphicsPipelineCreateInfo", + "VkComputePipelineCreateInfo", +}; +#define numsearch (sizeof (search_names) / sizeof (search_names[0])) +hashtab_t *available_types; +hashtab_t *processed_types; +Array *queue; +Array *output_types; + +QFile output_file; + +@interface Enum: Object +{ + qfot_type_t *type; + int prefix_length; +} +-initWithType: (qfot_type_t *) type; +/** \warning returned string is ephemeral +*/ +-(string) name; +@end + +@implementation Enum +-(void)process +{ + string end = "_MAX_ENUM"; + int len; + string prefix = nil; + + if (str_mid([self name], -8) == "FlagBits") { + end = "_FLAG_BITS_MAX_ENUM"; + } + len = -strlen (end); + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (str_mid (var.name, len) == end) { + // len is negative so +1 consumes 1 more char (_) + prefix = str_hold (str_mid (var.name, 0, len + 1)); + } + } + if (prefix) { + prefix_length = strlen (prefix); + } +} + +-initWithType: (qfot_type_t *) type +{ + if (!(self = [super init])) { + return nil; + } + self.type = type; + [self process]; + return self; +} + +-(string) name +{ + return str_mid(type.strct.tag, 4); +} + +-(void) addToQueue +{ + string name = [self name]; + //printf (" +%s\n", name); + if (!Hash_Find (processed_types, name)) { + Hash_Add (processed_types, (void *) name); + [queue addObject: self]; + } +} + +-(void) writeTable +{ + int strip_bit = 0; + if (str_mid([self name], -8) == "FlagBits") { + strip_bit = 1; + } + + fprintf (output_file, "enumval_t %s_values[] = {\n", [self name]); + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (str_str (var.name, "_MAX_ENUM") >= 0 + || str_str (var.name, "_BEGIN_RANGE") >= 0 + || str_str (var.name, "_END_RANGE") >= 0 + || str_str (var.name, "_RANGE_SIZE") >= 0) { + continue; + } + fprintf (output_file, "\t{\"%s\", %d},\n", var.name, var.offset); + if (prefix_length) { + string shortname = str_mid (var.name, prefix_length); + if (strip_bit) { + int bit_pos = str_str (shortname, "_BIT"); + if (bit_pos >= 0) { + shortname = str_mid (shortname, 0, bit_pos); + } + } + fprintf (output_file, "\t{\"%s\", %d},\n", str_lower(shortname), + var.offset); + } + } + fprintf (output_file, "\t{ }\n"); + fprintf (output_file, "};\n"); +} +@end + +@interface Struct: Object +{ + qfot_type_t *type; +} +-initWithType: (qfot_type_t *) type; +/** \warning returned string is ephemeral +*/ +-(string) name; +-(void) forEachFieldCall: (varfunc) func; +@end + +@implementation Struct +-initWithType: (qfot_type_t *) type +{ + if (!(self = [super init])) { + return nil; + } + self.type = type; + return self; +} + +-(string) name +{ + return str_mid(type.strct.tag, 4); +} + +-(void) forEachFieldCall: (varfunc) func +{ + qfot_struct_t *strct =&type.strct; + + for (int i = 0; i < strct.num_fields; i++) { + func (&strct.fields[i]); + } +} + +-(void) addToQueue +{ + string name = [self name]; + //printf (" +%s\n", name); + if (!Hash_Find (processed_types, name)) { + Hash_Add (processed_types, (void *) name); + [queue addObject: self]; + } +} + +-(void) writeTable +{ + fprintf (output_file, "structfld_t %s_fields[] = {\n", [self name]); + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (var.name == "sType" || var.name == "pNext") { + continue; + } + string type_name = var.type.encoding; + fprintf (output_file, + "\t{\"%s\", field_offset (%s, %s), %s, %s}, // %s\n", + var.name, [self name], var.name, "0", "0", type_name); + } + fprintf (output_file, "\t{ }\n"); + fprintf (output_file, "};\n"); +} +@end + +qfot_type_encodings_t *encodings; + +qfot_type_t * +next_type (qfot_type_t *type) +{ + int size = type.size; + if (!size) + size = 4; + return (qfot_type_t *) ((int *) type + size); +} + +int +type_is_null (qfot_type_t *type) +{ + return type.size == 0; +} + +void print_type (qfot_type_t *type) +{ + printf ("type: %p %d %d %s", type, type.meta, type.size, type.encoding); + switch (type.meta) { + case ty_basic: + printf (" %d", type.type); + switch (type.type) { + case ev_pointer: + case ev_field: + printf (" "); + print_type (type.fldptr.aux_type); + break; + case ev_func: + printf (" %p %d\n", type.func.return_type, + type.func.num_params); + default: + printf ("\n"); + break; + } + break; + case ty_struct: + case ty_union: + case ty_enum: + printf (" %s %d\n", type.strct.tag, type.strct.num_fields); + break; + case ty_array: + printf (" %p %d %d\n", type.array.type, type.array.base, + type.array.size); + break; + case ty_class: + printf (" %s\n", type.class); + break; + case ty_alias: + printf (" %d %s ", type.alias.type, type.alias.name); + print_type (type.alias.aux_type); + break; + } +} + +void struct_func (qfot_var_t *var) +{ + qfot_type_t *alias; + if (var.type.meta == ty_enum) { + printf("%s a\n", var.name); + } else if (var.type.meta == ty_struct) { + printf("%s b\n", var.name); + } else if (var.type.meta == ty_union) { + printf("%s c\n", var.name); + } else if (var.type.meta == ty_alias) { + //printf("%s d\n", var.name); + // typedef fun ;) + alias = var.type.alias.full_type; + if (alias.meta == ty_alias) { + // double(+) typedef + if (alias.alias.name == "VkFlags") { + // enum flag fun :P + string tag = var.type.alias.name; + if (str_mid (tag, -5) == "Flags") { + tag = str_mid (tag, 0, -1) + "Bits"; + id enumObj = (id) Hash_Find (available_types, tag); + if (enumObj) { + [enumObj addToQueue]; + } + } + } else { + if (var.type.alias.name == "VkBool32") { + // drop + } else { + printf ("%s =%s\n", var.name, var.type.alias.name); + } + } + } else if (alias.meta == ty_enum) { + string tag = str_mid(alias.strct.tag, 4); + id enumObj = (id) Hash_Find (available_types, tag); + if (enumObj) { + [enumObj addToQueue]; + } + } else if (alias.meta == ty_basic && alias.type == ev_pointer) { + //printf("e\n"); + qfot_type_t *type = alias.fldptr.aux_type; + if (type.meta == ty_alias) { + id structObj = (id) Hash_Find (available_types, type.alias.name); + //printf (" a:%s %p\n", type.alias.name, structObj); + if (structObj) { + [structObj addToQueue]; + } + } else if (type_is_null (type)) { + // pointer to opaque struct. Probably VK_DEFINE_NON_DISPATCHABLE_HANDLE or VK_DEFINE_HANDLE + //drop + string createInfo = var.type.alias.name + "CreateInfo"; + id structObj = (id) Hash_Find (available_types, createInfo); + if (structObj) { + [structObj addToQueue]; + } else { + //printf(" b:%s\n", var.type.alias.name); + } + } else { + print_type (type); + printf("%s c:%s:%s\n", var.name, var.type.alias.name, pr_type_name[alias.type]); + } + } else if (alias.meta == ty_basic) { + //drop + //printf(" d:%s:%s\n", var.type.alias.name, pr_type_name[alias.type]); + } else if (alias.meta == ty_struct) { + string tag = str_mid(alias.strct.tag, 4); + id structObj = (id) Hash_Find (available_types, tag); + if (structObj) { + [structObj addToQueue]; + } + } else { + printf(" d:%s:%s\n", var.type.alias.name, ty_meta_name[alias.meta]); + } + } else if (var.type.meta == ty_basic && var.type.type == ev_pointer) { + qfot_type_t *type = var.type.fldptr.aux_type; + if (type.meta == ty_struct || type.meta == ty_union) { + printf("%s f\n", var.name); + } else if (type.meta == ty_alias) { + printf("%s --- %s\n", var.name, type.alias.name); + id obj = (id) Hash_Find (available_types, type.alias.name); + if (obj && [obj class] == [Struct class]) { + [obj forEachFieldCall:struct_func]; + } + } else if (type.meta == ty_basic && type.type == ev_void) { + //drop + } else { + printf("%s g\n", var.name); + print_type (var.type); + } + } else { + //drop + //printf(" %s:%s:%s\n", var.name, ty_meta_name[var.type.meta], pr_type_name[var.type.type]); + } +} + +void +scan_types (void) +{ + qfot_type_t *type; + + for (type = encodings.types; + ((int *)type - (int *) encodings.types) < encodings.size; + type = next_type (type)) { + if (!type.size + || (type.meta != ty_enum + && type.meta != ty_struct + && type.meta != ty_union)) { + continue; + } + string tag = str_mid(type.strct.tag, 4); + switch (type.meta) { + case ty_enum: + Hash_Add (available_types, [[Enum alloc] initWithType: type]); + //printf ("+ enum %s\n", tag); + break; + case ty_struct: + case ty_union: + Hash_Add (available_types, [[Struct alloc] initWithType: type]); + //printf ("+ struct %s\n", tag); + break; + case ty_basic: + case ty_array: + case ty_class: + case ty_alias: + break; + } + } +} + +static string +get_string_key (void *str, void *unused) +{ + return (string) str; +} + +static string +get_object_key (void *obj, void *unused) +{ + return [(id)obj name]; +} + +int +main(int argc, string *argv) +{ + encodings = PR_FindGlobal (".type_encodings"); + if (!encodings) { + printf ("Can't find encodings\n"); + return 1; + } + queue = [[Array alloc] init]; + output_types = [[Array alloc] init]; + available_types = Hash_NewTable (127, get_object_key, nil, nil); + processed_types = Hash_NewTable (127, get_string_key, nil, nil); + scan_types (); + + for (int i = 0; + i < sizeof (search_names) / sizeof (search_names[0]); i++) { + id obj = (id) Hash_Find (available_types, search_names[i]); + if (obj && [obj class] == [Struct class]) { + [obj addToQueue]; + } + } + + while ([queue count]) { + id obj = [queue objectAtIndex:0]; + [queue removeObjectAtIndex:0]; + if ([obj class] == [Struct class]) { + [obj forEachFieldCall:struct_func]; + } + [output_types addObject:obj]; + } + + for (int i = 0; i < argc; i++) { + printf ("vkgen %d %s\n", i, argv[i]); + } + + output_file = Qopen (argv[1], "wt"); + for (int i = [output_types count]; i-- > 0; ) { + id obj = [output_types objectAtIndex:i]; + if ([obj name] == "VkStructureType") { + continue; + } + if ([obj class] == [Struct class]) { + continue; + } + [obj writeTable]; + } + Qclose (output_file); + return 0; +} diff --git a/libs/video/renderer/vulkan/vkgen/vulkan.r b/libs/video/renderer/vulkan/vkgen/vulkan.r new file mode 100644 index 000000000..46b720d0c --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vulkan.r @@ -0,0 +1,2 @@ +#define __x86_64__ +#include From 12a35f3912f1008565dc3098aeaa8e279ea47481 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 28 Jun 2020 23:32:38 +0900 Subject: [PATCH 097/435] [build] Put that ar warning to rest --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 54ca7be00..71e429956 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,6 +44,7 @@ noinst_HEADERS = plugin_LTLIBRARIES = RANLIB=touch +ARFLAGS=cr EXTRA_HEADERS = EXTRA_LTLIBRARIES = From f6ea9e4d872b1585e2c1a1864caa3a9618755d79 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 1 Jul 2020 21:47:09 +0900 Subject: [PATCH 098/435] [util] Store source line in plist items The first line of the parsed item is stored and can be retrieved using PL_Line. Line numbers not stored for dictionary keys yet. Will be 0 for any items generated by code rather than parsed from a file or string. --- include/QF/qfplist.h | 8 ++++++++ libs/util/qfplist.c | 24 +++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 7a12b7c4c..a7c73ec44 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -77,6 +77,14 @@ char *PL_WritePropertyList (plitem_t *pl); */ pltype_t PL_Type (plitem_t *item) __attribute__((pure)); +/** Retrieve the line number of an object. + + \param item The object + \return the line number on which the object began, or 0 if not from a + string +*/ +int PL_Line (plitem_t *item) __attribute__((pure)); + /** Retrieve a string from a string object. \param string The string object diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 0bda96e59..04dd32055 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -49,6 +49,7 @@ */ struct plitem_s { pltype_t type; + int line; void *data; }; @@ -176,17 +177,18 @@ PL_NewData (void *data, size_t size) } static plitem_t * -new_string (char *str) +new_string (char *str, int line) { plitem_t *item = PL_NewItem (QFString); item->data = str; + item->line = line; return item; } VISIBLE plitem_t * PL_NewString (const char *str) { - return new_string (strdup (str)); + return new_string (strdup (str), 0); } VISIBLE void @@ -688,6 +690,7 @@ PL_ParsePropertyListItem (pldata_t *pl) case '{': { item = PL_NewDictionary (); + item->line = pl->line; pl->pos++; @@ -767,6 +770,7 @@ PL_ParsePropertyListItem (pldata_t *pl) case '(': { item = PL_NewArray (); + item->line = pl->line; pl->pos++; @@ -812,27 +816,31 @@ PL_ParsePropertyListItem (pldata_t *pl) if (!str) { return NULL; } else { - return PL_NewData (str, len); + item = PL_NewData (str, len); + item->line = pl->line; + return item; } } case '"': { + int line = pl->line; char *str = PL_ParseQuotedString (pl); if (!str) { return NULL; } else { - return new_string (str); + return new_string (str, line); } } default: { + int line = pl->line; char *str = PL_ParseUnquotedString (pl); if (!str) { return NULL; } else { - return new_string (str); + return new_string (str, line); } } } // switch @@ -1038,3 +1046,9 @@ PL_Type (plitem_t *item) { return item->type; } + +VISIBLE int +PL_Line (plitem_t *item) +{ + return item->line; +} From 8bd5f4f201206bf64b03a757963fd8b5a5263a62 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 2 Jul 2020 14:20:46 +0900 Subject: [PATCH 099/435] [util] Add code to parse a dictionary to a struct PL_ParseDictionary itself does only one level, but it takes care of the key-field mappings and property list item type checking leaving the actual parsing to a helper specified by the field. That helper is free to call PL_ParseDictionary recursively. --- include/QF/qfplist.h | 83 ++++++++++++++++++++++++++++ libs/util/qfplist.c | 125 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index a7c73ec44..5d719b840 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -53,6 +53,52 @@ typedef enum { */ typedef struct plitem_s plitem_t; +struct plfield_s; +/** Custom parser for the field. + + With this, custom parsing of any property list object type is + supported. For example, parsing of strings into numeric values, + converting binary objects to images, and deeper parsing of array and + dictionary objects. + + If null, then the default parser for the object type is used: + * QFString: the point to the actual string. The string continues + to be owned by the string object. + * QFBinary: pointer to fixed-size DARRAY_TYPE(byte) (so size isn't + lost) + * QFArray: pointer to fixed-size DARRAY_TYPE(plitem_t *) with the + indivisual objects. The individual objects continue to be owned + by the array object. + * QFDictionary: pointer to the hashtab_t hash table used for the + dictionary object. The hash table continues to be owned by the + dictionary object. + + \param field Pointer to this field item. + \param item The property list item being parsed into the field. + \param data Pointer to the field in the structure being parsed. + \param messages An array object the parser can use to store any + error messages. Messages should be strings, but no + checking is done: it is up to the top-level caller to + parse out the messages. + \return 0 for error, 1 for success. See \a PL_ParseDictionary. +*/ +typedef int (*plparser_t) (const struct plfield_s *field, + const struct plitem_s *item, + void *data, + struct plitem_s *messages); + +/** A field to be parsed from a dictionary item. + + something +*/ +typedef struct plfield_s { + const char *name; ///< matched by dictionary key + size_t offset; ///< the offset of the field within the structure + pltype_t type; ///< the required type of the dictionary object + plparser_t parser; ///< custom parser function + void *data; ///< additional data for \a parser +} plfield_t; + /** Create an in-memory representation of the contents of a property list. \param string the saved plist, as read from a file. @@ -234,6 +280,43 @@ plitem_t *PL_NewString (const char *str); */ void PL_Free (plitem_t *item); +/** Parse a dictionary object into a structure. + + For each key in the dictionary, the corresponding field item is used to + determine how to parse the object associated with that key. Duplicate + field items are ignored: only the first item is used, and no checking is + done. Fields for which there is no key in the dictionary are also ignored, + and the destination is left unmodified. However, keys that have no + corresponding field are treated as errors and a suitable message is added + to the \a messages object. + + When an error occurs (unknown key, incorrect item type (item type does not + match the type specified in the field item) or the field item's \a parser + returns 0), processing continues but the error result is returned. + + Can be used recursively to parse deep hierarchies. + + \param dict The dictionary object to parse + \param fields Array of field items describing the structure. Terminated + by a field item with a null \a name pointer. + \param data Pointer to the structure into which the data will be + parsed. + \param messages Array object supplied by the caller used for storing + messages. The messages may or may not indicate errors (its + contents are not checked). This function itself will add + only string objects. + If there are any errors, suitable messages will be found in + the \a messages object. However, just because there are no + errors doesn't mean that \a messages will remain empty as + a field's \a parser may add other messages. The standard + message format is "[line number]: [message]". If the line + number is 0, then the actual line is unknown (due to the + source item not being parsed from a file or string). + \return 0 if there are any errors, 1 if there are no errors. +*/ +int PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, + void *data, plitem_t *messages); + ///@} #endif//__QF_qfplist_h diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 04dd32055..35f136374 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -38,11 +38,13 @@ #include "qfalloca.h" +#include "QF/darray.h" #include "QF/dstring.h" #include "QF/hash.h" #include "QF/qfplist.h" #include "QF/qtypes.h" #include "QF/sys.h" +#include "QF/va.h" /* Generic property list item. @@ -97,6 +99,13 @@ typedef struct pldata_s { // Unparsed property list string : 10 + (inrange((ch), 'a', 'f') ? ((ch) - 'a') \ : ((ch) - 'A'))) +static const char *pl_types[] = { + "dictionary", + "array", + "biinary", + "string", +}; + static byte quotable_bitmap[32]; static inline int is_quotable (byte x) @@ -1052,3 +1061,119 @@ PL_Line (plitem_t *item) { return item->line; } + +static void __attribute__((format(printf,3,4))) +pl_message (plitem_t *messages, const plitem_t *item, const char *fmt, ...) +{ + va_list args; + dstring_t *string; + + string = dstring_new (); + + va_start (args, fmt); + dvsprintf (string, fmt, args); + va_end (args); + + if (item) { + PL_A_AddObject (messages, + PL_NewString (va ("%d: %s", item->line, string->str))); + } else { + PL_A_AddObject (messages, + PL_NewString (va ("internal: %s", string->str))); + } + dstring_delete (string); +} + +static int +pl_default_parser (const plfield_t *field, const plitem_t *item, void *data, + plitem_t *messages) +{ + switch (field->type) { + case QFDictionary: + { + *(hashtab_t **)data = (hashtab_t *)item->data; + } + return 1; + case QFArray: + { + plarray_t *array = (plarray_t *)item->data; + typedef struct DARRAY_TYPE (plitem_t *) arraydata_t; + arraydata_t *arraydata = DARRAY_ALLOCFIXED(arraydata_t, + array->numvals, + malloc); + memcpy (arraydata->a, array->values, + array->numvals * sizeof (arraydata->a[0])); + } + return 1; + case QFBinary: + { + plbinary_t *binary = (plbinary_t *)item->data; + typedef struct DARRAY_TYPE (byte) bindata_t; + bindata_t *bindata = DARRAY_ALLOCFIXED(bindata_t, + binary->size, malloc); + memcpy (bindata->a, binary->data, binary->size); + *(bindata_t **)data = bindata; + } + return 1; + case QFString: + *(char **)data = (char *)item->data; + return 1; + } + pl_message (messages, 0, "invalid item type: %d", field->type); + return 0; +} + +VISIBLE int +PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, + plitem_t *messages) +{ + void **list, **l; + dictkey_t *current; + int result; + int (*parser) (const plfield_t *, const plitem_t *, void *, + plitem_t *); + + if (dict->type != QFDictionary) { + pl_message (messages, dict, "error: not a dictionary object"); + return 0; + } + + if (!(l = list = Hash_GetList ((hashtab_t *) dict->data))) { + // empty struct: leave as default + return 1; + } + + while ((current = (dictkey_t *) *l++)) { + const plfield_t *f; + for (f = fields; f->name; f++) { + if (strcmp (f->name, current->key) == 0) { + plitem_t *item = current->value; + void *flddata = (byte *)data + f->offset; + + if (f->parser) { + parser = f->parser; + } else { + parser = pl_default_parser; + } + if (item->type != f->type) { + pl_message (messages, item, "error: %s is the wrong type" + " Got %s, expected %s",current->key, + pl_types[f->type], + pl_types[item->type]); + result = 0; + } else { + if (!parser (f, item, flddata, messages)) { + result = 0; + } + } + } + } + if (!f->name) { + pl_message (messages, dict, "error: unknown field %s", + current->key); + result = 0; + } + } + free (list); + return result; +} From 2ca9f80d56cce3aed3fa89d1f0a9ed919d5b6028 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 2 Jul 2020 14:24:39 +0900 Subject: [PATCH 100/435] [vulkan] Split up vkgen It worked as a proof of concept, but as the code itself needs to be a bit smarter, it would be a lot smarter to break up that code to make it easier to work on the individual parts. --- .../video/renderer/vulkan/vkgen/Makemodule.am | 9 +- libs/video/renderer/vulkan/vkgen/vkenum.h | 13 ++ libs/video/renderer/vulkan/vkgen/vkenum.r | 75 ++++++++ libs/video/renderer/vulkan/vkgen/vkgen.h | 18 ++ libs/video/renderer/vulkan/vkgen/vkgen.r | 162 +----------------- libs/video/renderer/vulkan/vkgen/vkstruct.h | 16 ++ libs/video/renderer/vulkan/vkgen/vkstruct.r | 43 +++++ libs/video/renderer/vulkan/vkgen/vktype.h | 18 ++ libs/video/renderer/vulkan/vkgen/vktype.r | 33 ++++ 9 files changed, 228 insertions(+), 159 deletions(-) create mode 100644 libs/video/renderer/vulkan/vkgen/vkenum.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkenum.r create mode 100644 libs/video/renderer/vulkan/vkgen/vkgen.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkstruct.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkstruct.r create mode 100644 libs/video/renderer/vulkan/vkgen/vktype.h create mode 100644 libs/video/renderer/vulkan/vkgen/vktype.r diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am index 901dea622..5eb099c9c 100644 --- a/libs/video/renderer/vulkan/vkgen/Makemodule.am +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -2,7 +2,10 @@ vkgen = libs/video/renderer/vulkan/vkgen.dat$(EXEEXT) noinst_PROGRAMS += $(vkgen) vkgen_dat_src= \ + libs/video/renderer/vulkan/vkgen/vkenum.r \ libs/video/renderer/vulkan/vkgen/vkgen.r \ + libs/video/renderer/vulkan/vkgen/vkstruct.r \ + libs/video/renderer/vulkan/vkgen/vktype.r \ libs/video/renderer/vulkan/vkgen/vulkan.r VKGENFLAGS = -I$(top_srcdir)/libs/video/renderer/vulkan/vkgen @@ -29,6 +32,10 @@ libs/video/renderer/vulkan/vkgen/vulkan.o: $(top_srcdir)/libs/video/renderer/vul EXTRA_DIST += \ libs/video/renderer/vulkan/vkgen/stddef.h \ - libs/video/renderer/vulkan/vkgen/stdint.h + libs/video/renderer/vulkan/vkgen/stdint.h \ + libs/video/renderer/vulkan/vkgen/vkenum.h \ + libs/video/renderer/vulkan/vkgen/vkgen.h \ + libs/video/renderer/vulkan/vkgen/vkstruct.h \ + libs/video/renderer/vulkan/vkgen/vktype.h \ CLEANFILES += \ libs/video/renderer/vkgen/*.sym diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.h b/libs/video/renderer/vulkan/vkgen/vkenum.h new file mode 100644 index 000000000..5deb7ff6f --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkenum.h @@ -0,0 +1,13 @@ +#ifndef __renderer_vulkan_vkgen_vkenum_h +#define __renderer_vulkan_vkgen_vkenum_h + +#include "vktype.h" + +@interface Enum: Type +{ + int prefix_length; +} +-(void) writeTable; +@end + +#endif//__renderer_vulkan_vkgen_vkenum_h diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.r b/libs/video/renderer/vulkan/vkgen/vkenum.r new file mode 100644 index 000000000..898ef5c58 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkenum.r @@ -0,0 +1,75 @@ +#include + +#include "vkenum.h" +#include "vkgen.h" + +@implementation Enum +-(void)process +{ + string end = "_MAX_ENUM"; + int len; + string prefix = nil; + + if (str_mid([self name], -8) == "FlagBits") { + end = "_FLAG_BITS_MAX_ENUM"; + } + len = -strlen (end); + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (str_mid (var.name, len) == end) { + // len is negative so +1 consumes 1 more char (_) + prefix = str_hold (str_mid (var.name, 0, len + 1)); + } + } + if (prefix) { + prefix_length = strlen (prefix); + } +} + +-initWithType: (qfot_type_t *) type +{ + if (!(self = [super initWithType: type])) { + return nil; + } + [self process]; + return self; +} + +-(string) name +{ + return str_mid(type.strct.tag, 4); +} + +-(void) writeTable +{ + int strip_bit = 0; + if (str_mid([self name], -8) == "FlagBits") { + strip_bit = 1; + } + + fprintf (output_file, "enumval_t %s_values[] = {\n", [self name]); + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (str_str (var.name, "_MAX_ENUM") >= 0 + || str_str (var.name, "_BEGIN_RANGE") >= 0 + || str_str (var.name, "_END_RANGE") >= 0 + || str_str (var.name, "_RANGE_SIZE") >= 0) { + continue; + } + fprintf (output_file, "\t{\"%s\", %d},\n", var.name, var.offset); + if (prefix_length) { + string shortname = str_mid (var.name, prefix_length); + if (strip_bit) { + int bit_pos = str_str (shortname, "_BIT"); + if (bit_pos >= 0) { + shortname = str_mid (shortname, 0, bit_pos); + } + } + fprintf (output_file, "\t{\"%s\", %d},\n", str_lower(shortname), + var.offset); + } + } + fprintf (output_file, "\t{ }\n"); + fprintf (output_file, "};\n"); +} +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.h b/libs/video/renderer/vulkan/vkgen/vkgen.h new file mode 100644 index 000000000..3612a048f --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkgen.h @@ -0,0 +1,18 @@ +#ifndef __renderer_vulkan_vkgen_vkgen_h +#define __renderer_vulkan_vkgen_vkgen_h + +#include +#include +#include +#include + +typedef void varfunc (qfot_var_t *var); + +void printf (string fmt, ...); +void fprintf (QFile file, string format, ...); +extern Array *queue; +extern Array *output_types; +extern QFile output_file; +extern hashtab_t *processed_types; + +#endif//__renderer_vulkan_vkgen_vkgen_h diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r index 1400d3fbc..7ef9f3ff6 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.r +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -5,6 +5,10 @@ #include #include +#include "vkgen.h" +#include "vkstruct.h" +#include "vkenum.h" + void printf (string fmt, ...) = #0; void fprintf (QFile file, string format, ...) @@ -13,8 +17,6 @@ void fprintf (QFile file, string format, ...) Qputs (file, vsprintf (format, va_copy (@args))); } -typedef void varfunc (qfot_var_t *var); - string search_names[] = { "VkGraphicsPipelineCreateInfo", "VkComputePipelineCreateInfo", @@ -27,162 +29,6 @@ Array *output_types; QFile output_file; -@interface Enum: Object -{ - qfot_type_t *type; - int prefix_length; -} --initWithType: (qfot_type_t *) type; -/** \warning returned string is ephemeral -*/ --(string) name; -@end - -@implementation Enum --(void)process -{ - string end = "_MAX_ENUM"; - int len; - string prefix = nil; - - if (str_mid([self name], -8) == "FlagBits") { - end = "_FLAG_BITS_MAX_ENUM"; - } - len = -strlen (end); - for (int i = 0; i < type.strct.num_fields; i++) { - qfot_var_t *var = &type.strct.fields[i]; - if (str_mid (var.name, len) == end) { - // len is negative so +1 consumes 1 more char (_) - prefix = str_hold (str_mid (var.name, 0, len + 1)); - } - } - if (prefix) { - prefix_length = strlen (prefix); - } -} - --initWithType: (qfot_type_t *) type -{ - if (!(self = [super init])) { - return nil; - } - self.type = type; - [self process]; - return self; -} - --(string) name -{ - return str_mid(type.strct.tag, 4); -} - --(void) addToQueue -{ - string name = [self name]; - //printf (" +%s\n", name); - if (!Hash_Find (processed_types, name)) { - Hash_Add (processed_types, (void *) name); - [queue addObject: self]; - } -} - --(void) writeTable -{ - int strip_bit = 0; - if (str_mid([self name], -8) == "FlagBits") { - strip_bit = 1; - } - - fprintf (output_file, "enumval_t %s_values[] = {\n", [self name]); - for (int i = 0; i < type.strct.num_fields; i++) { - qfot_var_t *var = &type.strct.fields[i]; - if (str_str (var.name, "_MAX_ENUM") >= 0 - || str_str (var.name, "_BEGIN_RANGE") >= 0 - || str_str (var.name, "_END_RANGE") >= 0 - || str_str (var.name, "_RANGE_SIZE") >= 0) { - continue; - } - fprintf (output_file, "\t{\"%s\", %d},\n", var.name, var.offset); - if (prefix_length) { - string shortname = str_mid (var.name, prefix_length); - if (strip_bit) { - int bit_pos = str_str (shortname, "_BIT"); - if (bit_pos >= 0) { - shortname = str_mid (shortname, 0, bit_pos); - } - } - fprintf (output_file, "\t{\"%s\", %d},\n", str_lower(shortname), - var.offset); - } - } - fprintf (output_file, "\t{ }\n"); - fprintf (output_file, "};\n"); -} -@end - -@interface Struct: Object -{ - qfot_type_t *type; -} --initWithType: (qfot_type_t *) type; -/** \warning returned string is ephemeral -*/ --(string) name; --(void) forEachFieldCall: (varfunc) func; -@end - -@implementation Struct --initWithType: (qfot_type_t *) type -{ - if (!(self = [super init])) { - return nil; - } - self.type = type; - return self; -} - --(string) name -{ - return str_mid(type.strct.tag, 4); -} - --(void) forEachFieldCall: (varfunc) func -{ - qfot_struct_t *strct =&type.strct; - - for (int i = 0; i < strct.num_fields; i++) { - func (&strct.fields[i]); - } -} - --(void) addToQueue -{ - string name = [self name]; - //printf (" +%s\n", name); - if (!Hash_Find (processed_types, name)) { - Hash_Add (processed_types, (void *) name); - [queue addObject: self]; - } -} - --(void) writeTable -{ - fprintf (output_file, "structfld_t %s_fields[] = {\n", [self name]); - for (int i = 0; i < type.strct.num_fields; i++) { - qfot_var_t *var = &type.strct.fields[i]; - if (var.name == "sType" || var.name == "pNext") { - continue; - } - string type_name = var.type.encoding; - fprintf (output_file, - "\t{\"%s\", field_offset (%s, %s), %s, %s}, // %s\n", - var.name, [self name], var.name, "0", "0", type_name); - } - fprintf (output_file, "\t{ }\n"); - fprintf (output_file, "};\n"); -} -@end - qfot_type_encodings_t *encodings; qfot_type_t * diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.h b/libs/video/renderer/vulkan/vkgen/vkstruct.h new file mode 100644 index 000000000..a8a0df7e9 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.h @@ -0,0 +1,16 @@ +#ifndef __renderer_vulkan_vkgen_vkstruct_h +#define __renderer_vulkan_vkgen_vkstruct_h + +#include + +#include "vkgen.h" +#include "vktype.h" + +@interface Struct: Type +{ +} +-(void) forEachFieldCall: (varfunc) func; +-(void) writeTable; +@end + +#endif//__renderer_vulkan_vkgen_vkstruct_h diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r new file mode 100644 index 000000000..fa5193b11 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include + +#include "vkgen.h" +#include "vkstruct.h" + +@implementation Struct + +-(string) name +{ + return str_mid(type.strct.tag, 4); +} + +-(void) forEachFieldCall: (varfunc) func +{ + qfot_struct_t *strct =&type.strct; + + for (int i = 0; i < strct.num_fields; i++) { + func (&strct.fields[i]); + } +} + +-(void) writeTable +{ + fprintf (output_file, "structfld_t %s_fields[] = {\n", [self name]); + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (var.name == "sType" || var.name == "pNext") { + continue; + } + string type_name = var.type.encoding; + fprintf (output_file, + "\t{\"%s\", field_offset (%s, %s), %s, %s}, // %s\n", + var.name, [self name], var.name, "0", "0", type_name); + } + fprintf (output_file, "\t{ }\n"); + fprintf (output_file, "};\n"); +} +@end diff --git a/libs/video/renderer/vulkan/vkgen/vktype.h b/libs/video/renderer/vulkan/vkgen/vktype.h new file mode 100644 index 000000000..a4ffb83c4 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vktype.h @@ -0,0 +1,18 @@ +#ifndef __renderer_vulkan_vkgen_vktype_h +#define __renderer_vulkan_vkgen_vktype_h + +#include +#include + +@interface Type: Object +{ + qfot_type_t *type; +} +-initWithType: (qfot_type_t *) type; +/** \warning returned string is ephemeral +*/ +-(string) name; +-(void) addToQueue; +@end + +#endif//__renderer_vulkan_vkgen_vktype_h diff --git a/libs/video/renderer/vulkan/vkgen/vktype.r b/libs/video/renderer/vulkan/vkgen/vktype.r new file mode 100644 index 000000000..b3a7bcf2c --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vktype.r @@ -0,0 +1,33 @@ +#include + +#include "vkgen.h" +#include "vktype.h" + +@implementation Type + +-initWithType: (qfot_type_t *) type +{ + if (!(self = [super init])) { + return nil; + } + self.type = type; + return self; +} + +-(string) name +{ + //FIXME extract alias name and return proper type name + return type.encoding; +} + +-(void) addToQueue +{ + string name = [self name]; + //printf (" +%s\n", name); + if (!Hash_Find (processed_types, name)) { + Hash_Add (processed_types, (void *) name); + [queue addObject: self]; + } +} + +@end From 64100efe7837ed50cbabdece17907352e9004cd2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 2 Jul 2020 19:51:47 +0900 Subject: [PATCH 101/435] [qwaq] Fix a typo --- ruamoko/qwaq/builtins/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruamoko/qwaq/builtins/main.c b/ruamoko/qwaq/builtins/main.c index 931d33337..c4c426166 100644 --- a/ruamoko/qwaq/builtins/main.c +++ b/ruamoko/qwaq/builtins/main.c @@ -244,7 +244,7 @@ run_progs (void *data) __auto_type thread = (qwaq_thread_t *) data; spawn_progs (thread); - Sys_Printf ("starthing thread for %s\n", thread->args.a[0]); + Sys_Printf ("starting thread for %s\n", thread->args.a[0]); PR_ExecuteProgram (thread->pr, thread->main_func); PR_PopFrame (thread->pr); From 98795bf60443e0e36d37d23b0a462aa994afc0c5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 3 Jul 2020 21:40:40 +0900 Subject: [PATCH 102/435] [gamecode] Add a comment about returning temp strings --- libs/gamecode/pr_strings.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index 89d5ee60f..e8e1dff85 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -693,6 +693,11 @@ PR_FreeTempStrings (progs_t *pr) PR_Error (pr, "internal string error: %d", __LINE__); if (R_STRING (pr) < 0 && string_index (res, sr) == R_STRING (pr) && pr->pr_depth) { + // It looks like the temp string is being returned. While this + // may be a false positive (just a random integer with the same + // value), it is better to hold onto the temp string a little + // longer than to remove it prematurely. This allows functions + // to return the result of "str a" + "str b" prstack_t *frame = pr->pr_stack + pr->pr_depth - 1; sr->next = frame->tstr; frame->tstr = sr; From 1910941426a2f17a900b463adfd3dd202b669d48 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 3 Jul 2020 21:41:51 +0900 Subject: [PATCH 103/435] [qwaq] Handle key events differently when running Pressing F8 (or n) while the debug target was running would cause it to stop at that point. While it's certainly desirable to stop a runaway target on demand, that should be with a different input. Now, commands that start the target running are ignored while the target is running. No commands for when the target is running have been implemented yet, but the provision is there. --- ruamoko/qwaq/debugger/debugger.h | 1 + ruamoko/qwaq/debugger/debugger.r | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ruamoko/qwaq/debugger/debugger.h b/ruamoko/qwaq/debugger/debugger.h index 9e6c750d2..8694d06c0 100644 --- a/ruamoko/qwaq/debugger/debugger.h +++ b/ruamoko/qwaq/debugger/debugger.h @@ -28,6 +28,7 @@ int onExit; } sub_cond; SEL traceHandler; + int running; Window *source_window; ScrollBar *source_scrollbar; diff --git a/ruamoko/qwaq/debugger/debugger.r b/ruamoko/qwaq/debugger/debugger.r index 2d51e3c60..abd8a326b 100644 --- a/ruamoko/qwaq/debugger/debugger.r +++ b/ruamoko/qwaq/debugger/debugger.r @@ -127,7 +127,7 @@ } static int -proxy_event (Debugger *self, id proxy, qwaq_event_t *event) +proxy_event_stopped (Debugger *self, id proxy, qwaq_event_t *event) { if (event.what == qe_mouseclick && !(event.mouse.buttons & 0x78)) { if (proxy == self.current_file) { @@ -142,6 +142,7 @@ proxy_event (Debugger *self, id proxy, qwaq_event_t *event) self.traceHandler = @selector(traceStep); qdb_set_trace (self.target, 1); self.trace_cond.state = qdb_get_state (self.target); + self.running = 1; qdb_continue (self.target); return 1; case QFK_F8: @@ -150,6 +151,7 @@ proxy_event (Debugger *self, id proxy, qwaq_event_t *event) qdb_set_trace (self.target, 1); self.trace_cond.state = qdb_get_state (self.target); self.trace_cond.depth = qdb_get_stack_depth (self.target); + self.running = 1; qdb_continue (self.target); return 1; } @@ -157,15 +159,28 @@ proxy_event (Debugger *self, id proxy, qwaq_event_t *event) return 0; } +static int +proxy_event_running (Debugger *self, id proxy, qwaq_event_t *event) +{ + return 0; +} + -(void)proxy_event:(id)proxy :(qwaq_event_t *)event { - if (proxy_event (self, proxy, event)) { - event.what = qe_none; + if (running) { + if (proxy_event_running (self, proxy, event)) { + event.what = qe_none; + } + } else { + if (proxy_event_stopped (self, proxy, event)) { + event.what = qe_none; + } } } -stop:(prdebug_t)reason { + running = 0; if (!file_proxy) { [self setup]; } From 225ee0ed3c3cbaf797449a23490e857bd230a98a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 3 Jul 2020 21:46:09 +0900 Subject: [PATCH 104/435] [qwaq] Use an actual condition variable for control I think I wasn't sure at the time whether the simple variable was required for pthread_cond_wait (and friends) to work properly, but it is: the time between the target posting the debug event and the target waiting on the condition variable turns out to sometimes be enough for the debugger to handle the event and signal the target to continue, resulting in the target waiting on a signal that will never come because another debug event will not be sent by the target until AFTER it has exited from the debug handler. --- ruamoko/qwaq/builtins/debug.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ruamoko/qwaq/builtins/debug.c b/ruamoko/qwaq/builtins/debug.c index bb22d35e2..d16ac6f97 100644 --- a/ruamoko/qwaq/builtins/debug.c +++ b/ruamoko/qwaq/builtins/debug.c @@ -59,6 +59,7 @@ typedef struct qwaq_target_s { prdebug_t event; void *param; rwcond_t run_cond; + int run_command; } qwaq_target_t; typedef struct qwaq_debug_s { @@ -130,7 +131,10 @@ qwaq_debug_handler (prdebug_t debug_event, void *param, void *data) Sys_Error ("event queue broke"); } pthread_mutex_lock (&target->run_cond.mut); - pthread_cond_wait (&target->run_cond.rcond, &target->run_cond.mut); + while (!target->run_command) { + pthread_cond_wait (&target->run_cond.rcond, &target->run_cond.mut); + } + target->run_command = 0; pthread_mutex_unlock (&target->run_cond.mut); if (debug_event == prd_runerror || debug_event == prd_error) { pthread_exit (param); @@ -185,6 +189,7 @@ qwaq_target_load (progs_t *pr) target->debugger = qwaq_debug_data; target->handle = target_index (qwaq_debug_data, target); qwaq_init_cond (&target->run_cond); + target->run_command = 0; pr->debug_handler = qwaq_debug_handler; pr->debug_data = target; @@ -280,6 +285,7 @@ qdb_continue (progs_t *pr) qwaq_target_t *target = get_target (debug, __FUNCTION__, handle); pthread_mutex_lock (&target->run_cond.mut); + target->run_command = 1; pthread_cond_signal (&target->run_cond.rcond); pthread_mutex_unlock (&target->run_cond.mut); } From 1914fa27565b68ae6b7193ac41f3ae4f51720a74 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 4 Jul 2020 01:36:46 +0900 Subject: [PATCH 105/435] [qwaq] Use full file path for file search Fixes the memory leak (over 300 editors...) --- ruamoko/qwaq/debugger/debugger.r | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruamoko/qwaq/debugger/debugger.r b/ruamoko/qwaq/debugger/debugger.r index abd8a326b..3acf1707e 100644 --- a/ruamoko/qwaq/debugger/debugger.r +++ b/ruamoko/qwaq/debugger/debugger.r @@ -53,6 +53,7 @@ -(Editor *) find_file:(string) filename { Editor *file; + filename = qdb_get_file_path (target, filename); for (int i = [files count]; i-- > 0; ) { file = [files objectAtIndex: i]; if ([file filename] == filename) { @@ -62,8 +63,7 @@ Rect rect = {{1, 1}, [source_window size]}; rect.extent.width -= 2; rect.extent.height -= 2; - string filepath = qdb_get_file_path (target, filename); - file = [Editor withRect:rect file:filepath]; + file = [Editor withRect:rect file:filename]; [files addObject: file]; return file; } From e4ee5c70e0d8cc8adfeaa3becee78502f3f5c8d2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 4 Jul 2020 01:40:02 +0900 Subject: [PATCH 106/435] [vulkan] Rework vkgen alias handling This is much cleaner and now that all the types are there properly, doing a parser generator should be easier. --- libs/video/renderer/Makemodule.am | 19 ++- .../video/renderer/vulkan/vkgen/Makemodule.am | 2 + libs/video/renderer/vulkan/vkgen/vkalias.h | 11 ++ libs/video/renderer/vulkan/vkgen/vkalias.r | 52 ++++++ libs/video/renderer/vulkan/vkgen/vkenum.r | 10 ++ libs/video/renderer/vulkan/vkgen/vkgen.h | 1 + libs/video/renderer/vulkan/vkgen/vkgen.r | 158 +++++------------- libs/video/renderer/vulkan/vkgen/vkstruct.r | 10 ++ libs/video/renderer/vulkan/vkgen/vktype.h | 7 +- libs/video/renderer/vulkan/vkgen/vktype.r | 64 ++++++- 10 files changed, 209 insertions(+), 125 deletions(-) create mode 100644 libs/video/renderer/vulkan/vkgen/vkalias.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkalias.r diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index b1196dc2f..d6ae44226 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -219,12 +219,25 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/vulkan_draw.c \ libs/video/renderer/vulkan/vulkan_vid_common.c +libs/video/renderer/vulkan/vulkan_vid_common.c: $(vkparse_src) + qwaq_curses = ruamoko/qwaq/qwaq-curses$(EXEEXT) -BUILT_SOURCES += libs/video/renderer/vulkan/vkenum.inc +vkparse_src = \ + libs/video/renderer/vulkan/vkenum.inc \ + libs/video/renderer/vulkan/vkstruct.inc + +V_VKGEN = $(V_VKGEN_@AM_V@) +V_VKGEN_ = $(V_VKGEN_@AM_DEFAULT_V@) +V_VKGEN_0 = @echo " VKGEN " $@; +V_VKGEN_1 = + libs/video/renderer/vulkan/vkenum.inc: $(vkgen) $(qwaq_curses) - $(qwaq_curses) $(vkgen) -- $@ + $(V_VKGEN)$(qwaq_curses) $(vkgen) -- enum $@ +libs/video/renderer/vulkan/vkstruct.inc: $(vkgen) $(qwaq_curses) + $(V_VKGEN)$(qwaq_curses) $(vkgen) -- struct $@ CLEANFILES += \ libs/video/renderer/glsl/*.vc \ libs/video/renderer/glsl/*.fc \ - libs/video/renderer/glsl/*.slc + libs/video/renderer/glsl/*.slc \ + $(vkparse_src) diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am index 5eb099c9c..66971a2c3 100644 --- a/libs/video/renderer/vulkan/vkgen/Makemodule.am +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -2,6 +2,7 @@ vkgen = libs/video/renderer/vulkan/vkgen.dat$(EXEEXT) noinst_PROGRAMS += $(vkgen) vkgen_dat_src= \ + libs/video/renderer/vulkan/vkgen/vkalias.r \ libs/video/renderer/vulkan/vkgen/vkenum.r \ libs/video/renderer/vulkan/vkgen/vkgen.r \ libs/video/renderer/vulkan/vkgen/vkstruct.r \ @@ -33,6 +34,7 @@ libs/video/renderer/vulkan/vkgen/vulkan.o: $(top_srcdir)/libs/video/renderer/vul EXTRA_DIST += \ libs/video/renderer/vulkan/vkgen/stddef.h \ libs/video/renderer/vulkan/vkgen/stdint.h \ + libs/video/renderer/vulkan/vkgen/vkalias.h \ libs/video/renderer/vulkan/vkgen/vkenum.h \ libs/video/renderer/vulkan/vkgen/vkgen.h \ libs/video/renderer/vulkan/vkgen/vkstruct.h \ diff --git a/libs/video/renderer/vulkan/vkgen/vkalias.h b/libs/video/renderer/vulkan/vkgen/vkalias.h new file mode 100644 index 000000000..fadf6619f --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkalias.h @@ -0,0 +1,11 @@ +#ifndef __renderer_vulkan_vkgen_vkalias_h +#define __renderer_vulkan_vkgen_vkalias_h + +#include "vktype.h" + +@interface Alias: Type +{ +} +@end + +#endif//__renderer_vulkan_vkgen_vkalias_h diff --git a/libs/video/renderer/vulkan/vkgen/vkalias.r b/libs/video/renderer/vulkan/vkgen/vkalias.r new file mode 100644 index 000000000..f37396097 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkalias.r @@ -0,0 +1,52 @@ +#include + +#include "vkalias.h" +#include "vkenum.h" +#include "vkgen.h" +#include "vkstruct.h" + +@implementation Alias +-(string) name +{ + return type.alias.name; +} + +-(Type *) resolveType +{ + return [Type findType: type.alias.aux_type]; +} + +-(void)addToQueue +{ + Type *alias = [Type findType:type.alias.full_type]; + string name = [self name]; + + if ([alias name] == "VkFlags") { + if (str_mid (name, -5) == "Flags") { + string tag = str_mid (name, 0, -1) + "Bits"; + id enumObj = [(id) Hash_Find (available_types, tag) resolveType]; + [enumObj addToQueue]; + } + } else if (name == "VkBool32") { + // drop + } else if ([alias class] == [Enum class] + || [alias class] == [Struct class]) { + [alias addToQueue]; + } else if (alias.type.meta == ty_basic && alias.type.type == ev_pointer) { + Type *type = [Type findType:alias.type.fldptr.aux_type]; + if (!type) { + // pointer to opaque struct. Probably VK_DEFINE_NON_DISPATCHABLE_HANDLE or VK_DEFINE_HANDLE + string createInfo = name + "CreateInfo"; + id structObj = (id) Hash_Find (available_types, createInfo); + if (structObj) { + [structObj addToQueue]; + } + } else if ([type class] == [Alias class]) { + type = [type resolveType]; + if ([type class] == [Struct class]) { + [type addToQueue]; + } + } + } +} +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.r b/libs/video/renderer/vulkan/vkgen/vkenum.r index 898ef5c58..10a476432 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.r +++ b/libs/video/renderer/vulkan/vkgen/vkenum.r @@ -40,6 +40,16 @@ return str_mid(type.strct.tag, 4); } +-(void) addToQueue +{ + string name = [self name]; + if (!Hash_Find (processed_types, name)) { + printf (" +%s\n", name); + Hash_Add (processed_types, (void *) name); + [queue addObject: self]; + } +} + -(void) writeTable { int strip_bit = 0; diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.h b/libs/video/renderer/vulkan/vkgen/vkgen.h index 3612a048f..0d488abe8 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.h +++ b/libs/video/renderer/vulkan/vkgen/vkgen.h @@ -14,5 +14,6 @@ extern Array *queue; extern Array *output_types; extern QFile output_file; extern hashtab_t *processed_types; +extern hashtab_t *available_types; #endif//__renderer_vulkan_vkgen_vkgen_h diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r index 7ef9f3ff6..183ba591b 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.r +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -13,7 +13,6 @@ void printf (string fmt, ...) = #0; void fprintf (QFile file, string format, ...) { - printf("fprintf %d\n", @args.count); Qputs (file, vsprintf (format, va_copy (@args))); } @@ -87,97 +86,8 @@ void print_type (qfot_type_t *type) void struct_func (qfot_var_t *var) { - qfot_type_t *alias; - if (var.type.meta == ty_enum) { - printf("%s a\n", var.name); - } else if (var.type.meta == ty_struct) { - printf("%s b\n", var.name); - } else if (var.type.meta == ty_union) { - printf("%s c\n", var.name); - } else if (var.type.meta == ty_alias) { - //printf("%s d\n", var.name); - // typedef fun ;) - alias = var.type.alias.full_type; - if (alias.meta == ty_alias) { - // double(+) typedef - if (alias.alias.name == "VkFlags") { - // enum flag fun :P - string tag = var.type.alias.name; - if (str_mid (tag, -5) == "Flags") { - tag = str_mid (tag, 0, -1) + "Bits"; - id enumObj = (id) Hash_Find (available_types, tag); - if (enumObj) { - [enumObj addToQueue]; - } - } - } else { - if (var.type.alias.name == "VkBool32") { - // drop - } else { - printf ("%s =%s\n", var.name, var.type.alias.name); - } - } - } else if (alias.meta == ty_enum) { - string tag = str_mid(alias.strct.tag, 4); - id enumObj = (id) Hash_Find (available_types, tag); - if (enumObj) { - [enumObj addToQueue]; - } - } else if (alias.meta == ty_basic && alias.type == ev_pointer) { - //printf("e\n"); - qfot_type_t *type = alias.fldptr.aux_type; - if (type.meta == ty_alias) { - id structObj = (id) Hash_Find (available_types, type.alias.name); - //printf (" a:%s %p\n", type.alias.name, structObj); - if (structObj) { - [structObj addToQueue]; - } - } else if (type_is_null (type)) { - // pointer to opaque struct. Probably VK_DEFINE_NON_DISPATCHABLE_HANDLE or VK_DEFINE_HANDLE - //drop - string createInfo = var.type.alias.name + "CreateInfo"; - id structObj = (id) Hash_Find (available_types, createInfo); - if (structObj) { - [structObj addToQueue]; - } else { - //printf(" b:%s\n", var.type.alias.name); - } - } else { - print_type (type); - printf("%s c:%s:%s\n", var.name, var.type.alias.name, pr_type_name[alias.type]); - } - } else if (alias.meta == ty_basic) { - //drop - //printf(" d:%s:%s\n", var.type.alias.name, pr_type_name[alias.type]); - } else if (alias.meta == ty_struct) { - string tag = str_mid(alias.strct.tag, 4); - id structObj = (id) Hash_Find (available_types, tag); - if (structObj) { - [structObj addToQueue]; - } - } else { - printf(" d:%s:%s\n", var.type.alias.name, ty_meta_name[alias.meta]); - } - } else if (var.type.meta == ty_basic && var.type.type == ev_pointer) { - qfot_type_t *type = var.type.fldptr.aux_type; - if (type.meta == ty_struct || type.meta == ty_union) { - printf("%s f\n", var.name); - } else if (type.meta == ty_alias) { - printf("%s --- %s\n", var.name, type.alias.name); - id obj = (id) Hash_Find (available_types, type.alias.name); - if (obj && [obj class] == [Struct class]) { - [obj forEachFieldCall:struct_func]; - } - } else if (type.meta == ty_basic && type.type == ev_void) { - //drop - } else { - printf("%s g\n", var.name); - print_type (var.type); - } - } else { - //drop - //printf(" %s:%s:%s\n", var.name, ty_meta_name[var.type.meta], pr_type_name[var.type.type]); - } + Type *type = [Type findType:var.type]; + [type addToQueue]; } void @@ -188,30 +98,14 @@ scan_types (void) for (type = encodings.types; ((int *)type - (int *) encodings.types) < encodings.size; type = next_type (type)) { - if (!type.size - || (type.meta != ty_enum - && type.meta != ty_struct - && type.meta != ty_union)) { - continue; + if (type.size) { + string tag = str_mid(type.strct.tag, 4); + Type *avail_type = [Type fromType: type]; + if (avail_type) { + Hash_Add (available_types, avail_type); + } } - string tag = str_mid(type.strct.tag, 4); - switch (type.meta) { - case ty_enum: - Hash_Add (available_types, [[Enum alloc] initWithType: type]); - //printf ("+ enum %s\n", tag); - break; - case ty_struct: - case ty_union: - Hash_Add (available_types, [[Struct alloc] initWithType: type]); - //printf ("+ struct %s\n", tag); - break; - case ty_basic: - case ty_array: - case ty_class: - case ty_alias: - break; - } - } + } } static string @@ -226,9 +120,33 @@ get_object_key (void *obj, void *unused) return [(id)obj name]; } +void +usage (string name) +{ + printf ("%s [struct|enum] [output file]\n", name); +} + int main(int argc, string *argv) { + int do_struct = 0; + int do_enum = 0; + + if (argc != 3) { + usage (argv[0]); + return 1; + } + switch (argv[1]) { + case "struct": + do_struct = 1; + break; + case "enum": + do_enum = 1; + break; + default: + usage (argv[0]); + return 1; + } encodings = PR_FindGlobal (".type_encodings"); if (!encodings) { printf ("Can't find encodings\n"); @@ -243,6 +161,8 @@ main(int argc, string *argv) for (int i = 0; i < sizeof (search_names) / sizeof (search_names[0]); i++) { id obj = (id) Hash_Find (available_types, search_names[i]); + obj = [obj resolveType]; + printf("obj: %d %s\n", obj, class_get_class_name([obj class])); if (obj && [obj class] == [Struct class]) { [obj addToQueue]; } @@ -261,13 +181,17 @@ main(int argc, string *argv) printf ("vkgen %d %s\n", i, argv[i]); } - output_file = Qopen (argv[1], "wt"); + output_file = Qopen (argv[2], "wt"); for (int i = [output_types count]; i-- > 0; ) { id obj = [output_types objectAtIndex:i]; if ([obj name] == "VkStructureType") { continue; } - if ([obj class] == [Struct class]) { + printf("obj: %d %s\n", obj, class_get_class_name([obj class])); + if (do_struct && [obj class] != [Struct class]) { + continue; + } + if (do_enum && [obj class] != [Enum class]) { continue; } [obj writeTable]; diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index fa5193b11..939f9094e 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -15,6 +15,16 @@ return str_mid(type.strct.tag, 4); } +-(void) addToQueue +{ + string name = [self name]; + if (!Hash_Find (processed_types, name)) { + printf (" +%s\n", name); + Hash_Add (processed_types, (void *) name); + [queue addObject: self]; + } +} + -(void) forEachFieldCall: (varfunc) func { qfot_struct_t *strct =&type.strct; diff --git a/libs/video/renderer/vulkan/vkgen/vktype.h b/libs/video/renderer/vulkan/vkgen/vktype.h index a4ffb83c4..834bd1896 100644 --- a/libs/video/renderer/vulkan/vkgen/vktype.h +++ b/libs/video/renderer/vulkan/vkgen/vktype.h @@ -8,11 +8,16 @@ { qfot_type_t *type; } --initWithType: (qfot_type_t *) type; ++fromType: (qfot_type_t *) type; +/** \warning returned string is ephemeral +*/ +-(string) key; /** \warning returned string is ephemeral */ -(string) name; -(void) addToQueue; +-(Type *) resolveType; ++(Type *) findType: (qfot_type_t *) type; @end #endif//__renderer_vulkan_vkgen_vktype_h diff --git a/libs/video/renderer/vulkan/vkgen/vktype.r b/libs/video/renderer/vulkan/vkgen/vktype.r index b3a7bcf2c..c5a678c48 100644 --- a/libs/video/renderer/vulkan/vkgen/vktype.r +++ b/libs/video/renderer/vulkan/vkgen/vktype.r @@ -1,19 +1,72 @@ #include +#include "vkalias.h" +#include "vkenum.h" #include "vkgen.h" +#include "vkstruct.h" #include "vktype.h" @implementation Type +static hashtab_t *registered_types; + +static string get_type_key (void *type, void *unused) +{ + return ((Type *) type).type.encoding; +} + ++(void)initialize +{ + registered_types = Hash_NewTable (127, get_type_key, nil, nil); +} + -initWithType: (qfot_type_t *) type { if (!(self = [super init])) { return nil; } self.type = type; + Hash_Add (registered_types, self); return self; } ++(Type *) findType: (qfot_type_t *) type +{ + if (type.meta == ty_alias && !type.alias.name) { + type = type.alias.full_type; + } + return (Type *) Hash_Find (registered_types, type.encoding); +} + ++fromType: (qfot_type_t *) type +{ + if (type.size == 0) { + return nil; + } + switch (type.meta) { + case ty_basic: + case ty_array: + case ty_class: + return [[Type alloc] initWithType: type]; + case ty_enum: + return [[Enum alloc] initWithType: type]; + case ty_struct: + case ty_union: + return [[Struct alloc] initWithType: type]; + case ty_alias: + if (type.alias.name) { + return [[Alias alloc] initWithType: type]; + } + break; + } + return nil; +} + +-(string) key +{ + return type.encoding; +} + -(string) name { //FIXME extract alias name and return proper type name @@ -23,11 +76,14 @@ -(void) addToQueue { string name = [self name]; - //printf (" +%s\n", name); - if (!Hash_Find (processed_types, name)) { - Hash_Add (processed_types, (void *) name); - [queue addObject: self]; + if (type.meta == ty_basic && type.type == ev_pointer) { + [[Type findType: type.fldptr.aux_type] addToQueue]; } } +-(Type *) resolveType +{ + return self; +} + @end From f544a6f0b0401b0a7cff79988c9c152cc186c205 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 4 Jul 2020 12:39:11 +0900 Subject: [PATCH 107/435] [qfcc] Treat null method return type as id This prevents a segfault when the method's return type is undefined. --- tools/qfcc/source/method.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 244ae1513..1c461af85 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -89,6 +89,10 @@ new_method (type_t *ret_type, param_t *selector, param_t *opt_params) dstring_t *name = dstring_newstr (); dstring_t *types = dstring_newstr (); + if (!ret_type) { + ret_type = &type_id; + } + selector = reverse_params (selector); selector = append_params (selector, opt_params); cmd->next = selector; From 7a478b4ce7f7fdcb94ddac77ef471055b72b09da Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 5 Jul 2020 14:38:44 +0900 Subject: [PATCH 108/435] [libr] Make PLItem more useful I can't say that I like what's there even now, but at least PLItem can be used without a lot of casting. Really, Ruamoko needs dictionary and string classes so reading a property list can build more natural object trees rather than this mess from when I knew too little. --- ruamoko/include/PropertyList.h | 44 ++++++++++++-------- ruamoko/lib/PropertyList.r | 75 ++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 18 deletions(-) diff --git a/ruamoko/include/PropertyList.h b/ruamoko/include/PropertyList.h index 3deb99a2b..c0c4bed35 100644 --- a/ruamoko/include/PropertyList.h +++ b/ruamoko/include/PropertyList.h @@ -4,7 +4,29 @@ #include #include -@interface PLItem: Object +@class PLItem; + +@protocol PLDictionary +- (int) count; +- (int) numKeys; +- (PLItem *) getObjectForKey:(string) key; +- (PLItem *) allKeys; +- addKey:(string) key value:(PLItem *) value; +@end + +@protocol PLArray +- (int) count; +- (int) numObjects; +- (PLItem *) getObjectAtIndex:(int) index; +- addObject:(PLItem *) object; +- insertObject:(PLItem *) object atIndex:(int) index; +@end + +@protocol PLString +- (string) string; +@end + +@interface PLItem: Object { plitem_t item; int own; @@ -22,34 +44,20 @@ - (pltype_t) type; @end -@interface PLDictionary: PLItem +@interface PLDictionary: PLItem + (PLDictionary *) new; - -- (int) count; -- (int) numKeys; -- (PLItem *) getObjectForKey:(string) key; -- (PLItem *) allKeys; -- addKey:(string) key value:(PLItem *) value; @end -@interface PLArray: PLItem +@interface PLArray: PLItem + (PLArray *) new; - -- (int) count; -- (int) numObjects; -- (PLItem *) getObjectAtIndex:(int) index; -- addObject:(PLItem *) object; -- insertObject:(PLItem *) object atIndex:(int) index; @end @interface PLData: PLItem + (PLData *) new:(void*) data size:(int) len; @end -@interface PLString: PLItem +@interface PLString: PLItem + (PLString *) new:(string) str; - -- (string) string; @end #endif//__ruamoko_PropertyList_h diff --git a/ruamoko/lib/PropertyList.r b/ruamoko/lib/PropertyList.r index b65edc85d..b8469e473 100644 --- a/ruamoko/lib/PropertyList.r +++ b/ruamoko/lib/PropertyList.r @@ -94,6 +94,81 @@ return PL_Type (item); } +- (int) count +{ + if ([self class] == [PLDictionary class]) { + return PL_D_NumKeys (item); + } else { + return PL_A_NumObjects (item); + } +} + +- (int) numKeys +{ + return PL_D_NumKeys (item); +} + +- (PLItem *) getObjectForKey:(string) key +{ + return [[PLItem itemClass: PL_ObjectForKey (item, key)] autorelease]; +} + +- (PLItem *) allKeys +{ + return [[PLItem itemClass: PL_D_AllKeys (item)] autorelease]; +} + +- addKey:(string) key value:(PLItem *) value +{ + if (!value.own) { + obj_error (self, 0, "add of unowned key/value to PLDictionary"); + return self; + } + PL_D_AddObject (item, key, value.item); + value.own = 0; + [value release]; + return self; +} + +- (int) numObjects +{ + return PL_A_NumObjects (item); +} + +- (PLItem *) getObjectAtIndex:(int) index +{ + return [[PLItem itemClass: PL_ObjectAtIndex (item, index)] autorelease]; +} + +- addObject:(PLItem *) object +{ + if (!object.own) { + obj_error (self, 0, "add of unowned object to PLArray"); + return self; + } + PL_A_AddObject (item, object.item); + object.own = 0; + [object release]; + return self; +} + +- insertObject:(PLItem *) object atIndex:(int) index +{ + if (!object.own) { + obj_error (self, 0, "add of unowned object to PLArray"); + return self; + } + PL_A_InsertObjectAtIndex (item, object.item, index); + object.own = 0; + [object release]; + return self; +} + +- (string) string +{ + return PL_String (item); +} + @end From 0945f30731ac47fa08088f20d5d3fcedc5420610 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 5 Jul 2020 14:59:56 +0900 Subject: [PATCH 109/435] [vulkan] Use a property list to drive code gen The property list specifies the base structures for which parser code will be generated (along with any structures and enums upon which those structures depend). It also defines option specialized parsers for better control. --- libs/video/renderer/Makemodule.am | 12 +- libs/video/renderer/vulkan/vkgen/vkalias.r | 54 ++++++++ libs/video/renderer/vulkan/vkgen/vkenum.r | 18 +++ libs/video/renderer/vulkan/vkgen/vkgen.r | 93 +++++++++---- libs/video/renderer/vulkan/vkgen/vkstruct.h | 4 +- libs/video/renderer/vulkan/vkgen/vkstruct.r | 141 ++++++++++++++++++-- libs/video/renderer/vulkan/vkgen/vktype.h | 7 + libs/video/renderer/vulkan/vkgen/vktype.r | 41 ++++++ libs/video/renderer/vulkan/vkparse.plist | 53 ++++++++ 9 files changed, 382 insertions(+), 41 deletions(-) create mode 100644 libs/video/renderer/vulkan/vkparse.plist diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index d6ae44226..c41406663 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -223,18 +223,18 @@ libs/video/renderer/vulkan/vulkan_vid_common.c: $(vkparse_src) qwaq_curses = ruamoko/qwaq/qwaq-curses$(EXEEXT) vkparse_src = \ - libs/video/renderer/vulkan/vkenum.inc \ - libs/video/renderer/vulkan/vkstruct.inc + libs/video/renderer/vulkan/vkparse.inc +vkparse_plist = \ + $(srcdir)/libs/video/renderer/vulkan/vkparse.plist V_VKGEN = $(V_VKGEN_@AM_V@) V_VKGEN_ = $(V_VKGEN_@AM_DEFAULT_V@) V_VKGEN_0 = @echo " VKGEN " $@; V_VKGEN_1 = -libs/video/renderer/vulkan/vkenum.inc: $(vkgen) $(qwaq_curses) - $(V_VKGEN)$(qwaq_curses) $(vkgen) -- enum $@ -libs/video/renderer/vulkan/vkstruct.inc: $(vkgen) $(qwaq_curses) - $(V_VKGEN)$(qwaq_curses) $(vkgen) -- struct $@ +libs/video/renderer/vulkan/vkparse.inc: $(vkgen) $(qwaq_curses) $(vkparse_plist) + $(V_VKGEN)$(qwaq_curses) $(vkgen) -- $(vkparse_plist) $@.t &&\ + $(am__mv) $@.t $@ CLEANFILES += \ libs/video/renderer/glsl/*.vc \ diff --git a/libs/video/renderer/vulkan/vkgen/vkalias.r b/libs/video/renderer/vulkan/vkgen/vkalias.r index f37396097..6228ac230 100644 --- a/libs/video/renderer/vulkan/vkgen/vkalias.r +++ b/libs/video/renderer/vulkan/vkgen/vkalias.r @@ -49,4 +49,58 @@ } } } + +-(string) parseType +{ + Type *alias = [Type findType:type.alias.full_type]; + string name = [self name]; + + if ([alias name] == "VkFlags") { + if (str_mid (name, -5) == "Flags") { + string tag = str_mid (name, 0, -1) + "Bits"; + id enumObj = [(id) Hash_Find (available_types, tag) resolveType]; + return [enumObj parseType]; + } + } + if (name == "uint32_t") { + return "QFString"; + } + return [alias parseType]; +} + +-(string) parseFunc +{ + Type *alias = [Type findType:type.alias.full_type]; + string name = [self name]; + + if ([alias name] == "VkFlags") { + if (str_mid (name, -5) == "Flags") { + string tag = str_mid (name, 0, -1) + "Bits"; + id enumObj = [(id) Hash_Find (available_types, tag) resolveType]; + return [enumObj parseFunc]; + } + } + if (name == "uint32_t") { + return "parse_uint32_t"; + } + return [alias parseFunc]; +} + +-(string) parseData +{ + Type *alias = [Type findType:type.alias.full_type]; + string name = [self name]; + + if ([alias name] == "VkFlags") { + if (str_mid (name, -5) == "Flags") { + string tag = str_mid (name, 0, -1) + "Bits"; + id enumObj = [(id) Hash_Find (available_types, tag) resolveType]; + return [enumObj parseData]; + } + } + if (name == "uint32_t") { + return "0"; + } + return [alias parseData]; +} @end diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.r b/libs/video/renderer/vulkan/vkgen/vkenum.r index 10a476432..768e4b8d4 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.r +++ b/libs/video/renderer/vulkan/vkgen/vkenum.r @@ -82,4 +82,22 @@ fprintf (output_file, "\t{ }\n"); fprintf (output_file, "};\n"); } + +-(string) parseType +{ + return "QFString"; +} + +-(string) parseFunc +{ + if (str_mid([self name], -8) == "FlagBits") { + return "parse_flags"; + } + return "parse_enum"; +} + +-(string) parseData +{ + return [self name] + "_values"; +} @end diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r index 183ba591b..7744d0cdc 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.r +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -4,11 +4,28 @@ #include #include #include +#include +#include #include "vkgen.h" #include "vkstruct.h" #include "vkenum.h" +static AutoreleasePool *autorelease_pool; +static void +arp_start (void) +{ + autorelease_pool = [[AutoreleasePool alloc] init]; +} + +static void +arp_end (void) +{ + [autorelease_pool release]; + autorelease_pool = nil; +} + + void printf (string fmt, ...) = #0; void fprintf (QFile file, string format, ...) @@ -16,11 +33,6 @@ void fprintf (QFile file, string format, ...) Qputs (file, vsprintf (format, va_copy (@args))); } -string search_names[] = { - "VkGraphicsPipelineCreateInfo", - "VkComputePipelineCreateInfo", -}; -#define numsearch (sizeof (search_names) / sizeof (search_names[0])) hashtab_t *available_types; hashtab_t *processed_types; Array *queue; @@ -123,7 +135,7 @@ get_object_key (void *obj, void *unused) void usage (string name) { - printf ("%s [struct|enum] [output file]\n", name); + printf ("%s [plist file] [output file]\n", name); } int @@ -131,36 +143,51 @@ main(int argc, string *argv) { int do_struct = 0; int do_enum = 0; + string plist_filename; + QFile plist_file; + PLItem *plist; + PLItem *search; + PLItem *parse; + + arp_start (); if (argc != 3) { usage (argv[0]); return 1; } - switch (argv[1]) { - case "struct": - do_struct = 1; - break; - case "enum": - do_enum = 1; - break; - default: - usage (argv[0]); - return 1; + plist_filename = argv[1]; + plist_file = Qopen (plist_filename, "rt"); + if (!plist_file) { + printf ("could not open property list file: %s\n", plist_filename); + return 1; } + plist = [[PLItem fromFile: plist_file] retain]; + if (!plist) { + printf ("error parsing: %s\n", plist_filename); + return 1; + } + Qclose (plist_file); + if ([plist class] != [PLDictionary class]) { + printf ("%s not a dictionary\n", plist_filename); + } + search = [[plist getObjectForKey: "search"] retain]; + parse = [[plist getObjectForKey: "parse"] retain]; + encodings = PR_FindGlobal (".type_encodings"); if (!encodings) { printf ("Can't find encodings\n"); return 1; } - queue = [[Array alloc] init]; - output_types = [[Array alloc] init]; + queue = [[Array array] retain]; + output_types = [[Array array] retain]; available_types = Hash_NewTable (127, get_object_key, nil, nil); processed_types = Hash_NewTable (127, get_string_key, nil, nil); scan_types (); - for (int i = 0; - i < sizeof (search_names) / sizeof (search_names[0]); i++) { - id obj = (id) Hash_Find (available_types, search_names[i]); + for (int i = [search numObjects]; i-- > 0; ) { + PLString *str = (PLString *) [search getObjectAtIndex:i]; + string search_name = [str string]; + id obj = (id) Hash_Find (available_types, search_name); obj = [obj resolveType]; printf("obj: %d %s\n", obj, class_get_class_name([obj class])); if (obj && [obj class] == [Struct class]) { @@ -181,20 +208,34 @@ main(int argc, string *argv) printf ("vkgen %d %s\n", i, argv[i]); } + arp_end (); + output_file = Qopen (argv[2], "wt"); for (int i = [output_types count]; i-- > 0; ) { id obj = [output_types objectAtIndex:i]; if ([obj name] == "VkStructureType") { continue; } - printf("obj: %d %s\n", obj, class_get_class_name([obj class])); - if (do_struct && [obj class] != [Struct class]) { - continue; - } - if (do_enum && [obj class] != [Enum class]) { + if ([obj class] != [Enum class]) { continue; } + + arp_start (); [obj writeTable]; + arp_end (); + } + for (int i = [output_types count]; i-- > 0; ) { + id obj = [output_types objectAtIndex:i]; + if ([obj name] == "VkStructureType") { + continue; + } + if ([obj class] != [Struct class]) { + continue; + } + + arp_start (); + [obj writeTable:parse]; + arp_end (); } Qclose (output_file); return 0; diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.h b/libs/video/renderer/vulkan/vkgen/vkstruct.h index a8a0df7e9..246d23070 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.h +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.h @@ -6,11 +6,13 @@ #include "vkgen.h" #include "vktype.h" +@class PLItem; + @interface Struct: Type { } -(void) forEachFieldCall: (varfunc) func; --(void) writeTable; +-(void) writeTable: (PLItem *) parse; @end #endif//__renderer_vulkan_vkgen_vkstruct_h diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index 939f9094e..ff364202b 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -4,6 +4,7 @@ #include #include #include +#include #include "vkgen.h" #include "vkstruct.h" @@ -34,20 +35,144 @@ } } --(void) writeTable +-(qfot_var_t *)findField:(string) fieldName { - fprintf (output_file, "structfld_t %s_fields[] = {\n", [self name]); for (int i = 0; i < type.strct.num_fields; i++) { qfot_var_t *var = &type.strct.fields[i]; - if (var.name == "sType" || var.name == "pNext") { - continue; + if (var.name == fieldName) { + return var; + } + } + return nil; +} + +-(void) writeTable: (PLItem *) parse +{ + PLItem *field_dict = [parse getObjectForKey:[self name]]; + PLItem *field_defs = [field_dict allKeys]; + Type *field_type; + + if (field_defs) { + PLItem *field_def; + qfot_var_t *field; + + for (int i = [field_defs count]; i-- > 0; ) { + string field_name = [[field_defs getObjectAtIndex:i] string]; + field_def = [field_dict getObjectForKey:field_name]; + PLItem *type_desc = [field_def getObjectForKey:"type"]; + string type_record; + string type_type; + string size_field = nil; + string value_field = nil; + + if (!type_desc) { + continue; + } + type_record = [[type_desc getObjectAtIndex:0] string]; + type_type = [[type_desc getObjectAtIndex:1] string]; + + field_type = [[Type lookup: type_type] dereference]; + fprintf (output_file, "static parse_%s_t parse_%s_%s_data = {\n", + type_record, [self name], field_name); + fprintf (output_file, "\tparse_%s,\n", type_type); + if (type_record == "single") { + value_field = [[field_def getObjectForKey:"value"] string]; + fprintf (output_file, "\tfield_offset (%s, %s),\n", + [self name], value_field); + } else { + value_field = [[field_def getObjectForKey:"values"] string]; + size_field = [[field_def getObjectForKey:"size"] string]; + fprintf (output_file, "\tfield_offset (%s, %s),\n", + [self name], value_field); + if (size_field) { + fprintf (output_file, "\tfield_offset (%s, %s),\n", + [self name], size_field); + } else { + fprintf (output_file, "\t-1,\n"); + } + } + fprintf (output_file, "};\n"); + } + } + fprintf (output_file, "static plfield_t %s_fields[] = {\n", [self name]); + if (field_defs) { + PLItem *field_def; + qfot_var_t *field; + + for (int i = [field_defs count]; i-- > 0; ) { + string field_name = [[field_defs getObjectAtIndex:i] string]; + field_def = [field_dict getObjectForKey:field_name]; + if ([field_def string] == "auto") { + field = [self findField:field_name]; + if (!field) { + continue; + } + field_type = [Type findType: field.type]; + fprintf (output_file, + "\t{\"%s\", field_offset (%s, %s), %s, %s, %s},\n", + field_name, [self name], field_name, + [field_type parseType], [field_type parseFunc], + [field_type parseData]); + } else { + PLItem *type_desc = [field_def getObjectForKey:"type"]; + string type_record; + string type_type; + string parseType; + + type_record = [[type_desc getObjectAtIndex:0] string]; + type_type = [[type_desc getObjectAtIndex:1] string]; + + field_type = [[Type lookup: type_type] dereference]; + if (type_record == "single") { + parseType = [field_type parseType]; + } else { + parseType = "QFArray"; + } + fprintf (output_file, + "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, parseType, type_record, + [self name], field_name); + } + } + } else { + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *field = &type.strct.fields[i]; + if (field.name == "sType" || field.name == "pNext") { + continue; + } + field_type = [Type findType: field.type]; + fprintf (output_file, + "\t{\"%s\", field_offset (%s, %s), %s, %s, %s},\n", + field.name, [self name], field.name, + [field_type parseType], [field_type parseFunc], + [field_type parseData]); } - string type_name = var.type.encoding; - fprintf (output_file, - "\t{\"%s\", field_offset (%s, %s), %s, %s}, // %s\n", - var.name, [self name], var.name, "0", "0", type_name); } fprintf (output_file, "\t{ }\n"); fprintf (output_file, "};\n"); + + fprintf (output_file, "static int parse_%s (const plfield_t *field," + " const plitem_t *item, void *data, plitem_t *messages)\n", + [self name]); + fprintf (output_file, "{\n"); + fprintf (output_file, + "\treturn PL_ParseDictionary (%s_fields, item, data, messages);\n", + [self name]); + fprintf (output_file, "}\n"); +} + +-(string) parseType +{ + return "QFDictionary"; +} + +-(string) parseFunc +{ + return "fix me"; +} + +-(string) parseData +{ + return "0"; } @end diff --git a/libs/video/renderer/vulkan/vkgen/vktype.h b/libs/video/renderer/vulkan/vkgen/vktype.h index 834bd1896..fc5a53c84 100644 --- a/libs/video/renderer/vulkan/vkgen/vktype.h +++ b/libs/video/renderer/vulkan/vkgen/vktype.h @@ -18,6 +18,13 @@ -(void) addToQueue; -(Type *) resolveType; +(Type *) findType: (qfot_type_t *) type; ++(Type *) lookup: (string) name; +-(string) parseType; +-(string) parseFunc; +-(string) parseData; + +-(int) isPointer; +-(Type *) dereference; @end #endif//__renderer_vulkan_vkgen_vktype_h diff --git a/libs/video/renderer/vulkan/vkgen/vktype.r b/libs/video/renderer/vulkan/vkgen/vktype.r index c5a678c48..83373d47a 100644 --- a/libs/video/renderer/vulkan/vkgen/vktype.r +++ b/libs/video/renderer/vulkan/vkgen/vktype.r @@ -38,6 +38,11 @@ static string get_type_key (void *type, void *unused) return (Type *) Hash_Find (registered_types, type.encoding); } ++(Type *) lookup: (string) name +{ + return (Type *) Hash_Find (available_types, name); +} + +fromType: (qfot_type_t *) type { if (type.size == 0) { @@ -86,4 +91,40 @@ static string get_type_key (void *type, void *unused) return self; } +-(string) parseType +{ + return "no parse"; +} + +-(string) parseFunc +{ + return "0"; +} + +-(string) parseData +{ + return "0"; +} + +-(int) isPointer +{ + if ((type.meta == ty_basic || type.meta == ty_alias) + && type.type == ev_pointer) { + return 1; + } + return 0; +} + +-(Type *) dereference +{ + qfot_type_t *t = type; + if (t.meta == ty_alias) { + t = type.alias.full_type; + } + if (t.meta == ty_basic && t.type == ev_pointer) { + t = type.fldptr.aux_type; + } + return [Type findType:t]; +} + @end diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist new file mode 100644 index 000000000..3aae7c9c2 --- /dev/null +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -0,0 +1,53 @@ +{ + search = ( + VkRenderPassCreateInfo + ); + parse = { + VkRenderPassCreateInfo = { + flags = auto; + attachments = { + type = (array, VkAttachmentDescription); + size = attachmentCount; + values = pAttachments; + }; + subpasses = { + type = (array, VkSubpassDescription); + size = subpassCount; + values = pSubpasses; + }; + dependencies = { + type = (array, VkSubpassDependency); + size = dependencyCount; + values = pDependencies; + }; + }; + VkSubpassDescription = { + flags = auto; + pipelineBindPoint = auto; + inputAttachments = { + type = (array, VkAttachmentReference); + size = inputAttachmentCount; + values = pInputAttachments; + }; + colorAttachments = { + type = (array, VkAttachmentReference); + size = colorAttachmentCount; + values = pColorAttachments; + }; + resolveAttachments = { + type = (array, VkAttachmentReference); + values = pResolveAttachments; + matchSize = colorAttachments; + }; + depthStencilAttachment = { + type = (single, VkAttachmentReference); + value = pDepthStencilAttachment; + }; + preserveAttachments = { + type = (array, uint32_t); + size = preserveAttachmentCount; + values = pPreserveAttachments; + }; + } + } +} From c6a8829a52ae878466b9ce21ed2b4ea492d203d9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 14 Jul 2020 12:05:34 +0900 Subject: [PATCH 110/435] [util] Add code to parse a plist array to an array --- include/QF/qfplist.h | 10 +++++++++ libs/util/qfplist.c | 49 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 5d719b840..089c04856 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -99,6 +99,14 @@ typedef struct plfield_s { void *data; ///< additional data for \a parser } plfield_t; +typedef struct plelement_s { + pltype_t type; ///< the required type of the array elements + size_t stride; ///< the size of each element + void *(*alloc) (size_t size); ///< allocator for array memory + plparser_t parser; ///< custom parser function + void *data; ///< additional data for \a parser +} plelement_t; + /** Create an in-memory representation of the contents of a property list. \param string the saved plist, as read from a file. @@ -316,6 +324,8 @@ void PL_Free (plitem_t *item); */ int PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, plitem_t *messages); +int PL_ParseArray (const plfield_t *fields, const plitem_t *dict, + void *data, plitem_t *messages); ///@} diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 35f136374..6949d3e53 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1130,8 +1130,7 @@ PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, void **list, **l; dictkey_t *current; int result; - int (*parser) (const plfield_t *, const plitem_t *, void *, - plitem_t *); + plparser_t parser; if (dict->type != QFDictionary) { pl_message (messages, dict, "error: not a dictionary object"); @@ -1177,3 +1176,49 @@ PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, free (list); return result; } + +VISIBLE int +PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, + plitem_t *messages) +{ + int result; + plparser_t parser; + plarray_t *plarray = (plarray_t *) array->data; + plelement_t *element = (plelement_t *) field->data; + typedef struct arr_s DARRAY_TYPE(byte) arr_t; + arr_t *arr; + plfield_t f = { 0, 0, element->type, element->parser, element->data }; + + if (array->type != QFArray) { + pl_message (messages, array, "error: not an array object"); + return 0; + } + if (field->parser) { + parser = field->parser; + } else { + parser = pl_default_parser; + } + + arr = DARRAY_ALLOCFIXED (arr_t, plarray->numvals * element->stride, + element->alloc); + + for (int i = 0; i < plarray->numvals; i++) { + plitem_t *item = plarray->values[i]; + void *eledata = &arr->a[i * element->stride]; + + if (item->type != element->type) { + pl_message (messages, item, + "error: element %d is the wrong type" + " Got %s, expected %s", i, + pl_types[element->type], + pl_types[item->type]); + result = 0; + } else { + if (!parser (&f, item, eledata, messages)) { + result = 0; + } + } + } + *(arr_t **) data = arr; + return result; +} From 79177e96e8ac9057fd3179fc569e9216ea01b942 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 16 Jul 2020 15:42:49 +0900 Subject: [PATCH 111/435] [vulkan] Start work on scripted pipeline Nothing is actually done yet other than parsing the built-in property list to property list items (the actual parser is just a skeleton), but everything compiles --- libs/video/renderer/Makemodule.am | 19 +- libs/video/renderer/vulkan/qfpipeline.plist | 71 +++++++ libs/video/renderer/vulkan/vkparse.c | 186 ++++++++++++++++++ libs/video/renderer/vulkan/vkparse.h | 10 + libs/video/renderer/vulkan/vkparse.plist | 22 +-- .../video/renderer/vulkan/vulkan_vid_common.c | 18 ++ 6 files changed, 303 insertions(+), 23 deletions(-) create mode 100644 libs/video/renderer/vulkan/qfpipeline.plist create mode 100644 libs/video/renderer/vulkan/vkparse.c create mode 100644 libs/video/renderer/vulkan/vkparse.h diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index c41406663..0b68d0b41 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -73,12 +73,13 @@ libs_video_renderer_vid_render_gl_la_SOURCES=\ shader_src= libs/video/renderer/glsl/quakeforge.glsl shader_gen= libs/video/renderer/glsl/quakeforge.slc -BUILT_SOURCES += $(shader_gen) - -SUFFICES=.frag .vert .fc .vc .slc .glsl +SUFFICES=.frag .vert .fc .vc .slc .glsl .plist .plc .glsl.slc: sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ +.plist.plc: + sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ + video_renderer_glsl_libs= \ libs/models/libmodels_glsl.la libs_video_renderer_vid_render_glsl_la_LDFLAGS= $(plugin_ldflags) @@ -196,6 +197,9 @@ libs_video_renderer_vid_render_sw32_la_SOURCES=\ libs/video/renderer/sw32/sw32_rsurf.c \ libs/video/renderer/sw32/vid_common_sw32.c +pipeline_src = libs/video/renderer/vulkan/qfpipeline.plist +pipeline_gen = libs/video/renderer/vulkan/qfpipeline.plc + vulkan_libs = libs_video_renderer_vid_render_vulkan_la_LDFLAGS= $(plugin_ldflags) libs_video_renderer_vid_render_vulkan_la_LIBADD= $(vulkan_libs) @@ -216,10 +220,14 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/swapchain.c \ libs/video/renderer/vulkan/util.c \ libs/video/renderer/vulkan/util.h \ + libs/video/renderer/vulkan/vkparse.c \ libs/video/renderer/vulkan/vulkan_draw.c \ libs/video/renderer/vulkan/vulkan_vid_common.c -libs/video/renderer/vulkan/vulkan_vid_common.c: $(vkparse_src) +libs/video/renderer/vulkan/vkparse.lo: libs/video/renderer/vulkan/vkparse.c $(vkparse_src) + +libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c $(pipeline_gen) + qwaq_curses = ruamoko/qwaq/qwaq-curses$(EXEEXT) vkparse_src = \ @@ -240,4 +248,7 @@ CLEANFILES += \ libs/video/renderer/glsl/*.vc \ libs/video/renderer/glsl/*.fc \ libs/video/renderer/glsl/*.slc \ + libs/video/renderer/vulkan/*.plc \ $(vkparse_src) + +BUILT_SOURCES += $(shader_gen) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist new file mode 100644 index 000000000..059405ceb --- /dev/null +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -0,0 +1,71 @@ +{ + renderpass = { + attachments = ( + { + flags = 0; + format = $swapchain.format; + samples = $msaaSamples; + loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + storeOp = VK_ATTACHMENT_STORE_OP_STORE; + stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + }, + { + flags = 0; + format = $swapchain.format; + samples = $msaaSamples; + loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + storeOp = VK_ATTACHMENT_STORE_OP_STORE; + stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + }, + { + flags = 0; + format = VK_FORMAT_D32_SFLOAT; + samples = VK_SAMPLE_COUNT_1_BIT; + loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + storeOp = VK_ATTACHMENT_STORE_OP_STORE; + stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + }, + ); + subpasses = ( + { + inputAttachments = ( + { + attachmeht = 0; + layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + ); + resolveAttachments = ( + { + attachmeht = 2; + layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + ); + depthStencilAttachment = { + attachmeht = 1; + layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + }; + preserveAttachments = (); + }, + ); + dependencies = ( + { + srcSubpass = VK_SUBPASS_EXTERNAL; + dstSubpass = 0; + srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + srcAccessMask = 0; + dstAccessMask = "VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT"; + dependencyFlags = 0; + } + ); + } +} diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c new file mode 100644 index 000000000..51df46a6e --- /dev/null +++ b/libs/video/renderer/vulkan/vkparse.c @@ -0,0 +1,186 @@ +/* + vkparse.c + + Parser for scripted vulkan structs + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/input.h" +#include "QF/mathlib.h" +#include "QF/qargs.h" +#include "QF/qfplist.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/renderpass.h" +#include "QF/Vulkan/swapchain.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" +#include "vkparse.h" + +typedef struct enumval_s { + const char *name; + int value; +} enumval_t; + +typedef struct parse_single_s { + plparser_t parser; + size_t value_offset; +} parse_single_t; + +typedef struct parse_array_s { + plparser_t parser; + size_t size_offset; + size_t value_offset; +} parse_array_t; + +static int parse_uint32_t (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages) +{ + return 0; +} + +static int parse_enum (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages) +{ + return 0; +} + +static int parse_flags (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages) +{ + return 0; +} + +static int parse_single (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages) +{ + return 0; +} + +static int parse_array (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages) +{ + return 0; +} + +#include "libs/video/renderer/vulkan/vkparse.inc" + +typedef struct qfv_renderpass_s { + qfv_attachmentdescription_t *attachments; + qfv_subpassparametersset_t *subpasses; + qfv_subpassdependency_t *dependencies; +} qfv_renderpass_t; + +static plelement_t parse_qfv_renderpass_attachments_data = { + QFDictionary, + sizeof (VkAttachmentDescription), + malloc, + parse_VkAttachmentDescription, + 0, +}; + +static plelement_t parse_qfv_renderpass_subpasses_data = { + QFDictionary, + sizeof (VkSubpassDescription), + malloc, + parse_VkSubpassDescription, + 0, +}; + +static plelement_t parse_qfv_renderpass_dependencies_data = { + QFDictionary, + sizeof (VkSubpassDependency), + malloc, + parse_VkSubpassDependency, + 0, +}; + +static plfield_t renderpass_fields[] = { + { "attachments", field_offset (qfv_renderpass_t, attachments), QFArray, + parse_array, &parse_qfv_renderpass_attachments_data }, + { "subpasses", field_offset (qfv_renderpass_t, subpasses), QFArray, + parse_array, &parse_qfv_renderpass_subpasses_data }, + { "dependencies", field_offset (qfv_renderpass_t, dependencies), QFArray, + parse_array, &parse_qfv_renderpass_dependencies_data }, + {} +}; + +VkRenderPass +QFV_ParseRenderPass (qfv_device_t *device, plitem_t *plist) +{ + qfv_renderpass_t renderpass_data = {}; + plitem_t *messages = PL_NewArray (); + VkRenderPass renderpass; + + if (!PL_ParseDictionary (renderpass_fields, plist, + &renderpass_data, messages)) { + for (int i = 0; i < PL_A_NumObjects (messages); i++) { + Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); + } + return 0; + } + PL_Free (messages); + renderpass = QFV_CreateRenderPass (device, + renderpass_data.attachments, + renderpass_data.subpasses, + renderpass_data.dependencies); + + free (renderpass_data.attachments); + for (size_t i = 0; i < renderpass_data.subpasses->size; i++) { + free ((void *) renderpass_data.subpasses->a[i].pInputAttachments); + free ((void *) renderpass_data.subpasses->a[i].pColorAttachments); + free ((void *) renderpass_data.subpasses->a[i].pResolveAttachments); + free ((void *) renderpass_data.subpasses->a[i].pDepthStencilAttachment); + free ((void *) renderpass_data.subpasses->a[i].pPreserveAttachments); + } + free (renderpass_data.subpasses); + free (renderpass_data.dependencies); + return renderpass; +} diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h new file mode 100644 index 000000000..0d14eecbe --- /dev/null +++ b/libs/video/renderer/vulkan/vkparse.h @@ -0,0 +1,10 @@ +#ifndef __vkparse_h +#define __vkparse_h + +#include "QF/Vulkan/renderpass.h" + +VkRenderPass +QFV_ParseRenderPass (qfv_device_t *device, plitem_t *plist); + + +#endif//__vkparse_h diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index 3aae7c9c2..017025426 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -1,26 +1,10 @@ { search = ( - VkRenderPassCreateInfo + VkAttachmentDescription, + VkSubpassDescription, + VkSubpassDependency, ); parse = { - VkRenderPassCreateInfo = { - flags = auto; - attachments = { - type = (array, VkAttachmentDescription); - size = attachmentCount; - values = pAttachments; - }; - subpasses = { - type = (array, VkSubpassDescription); - size = subpassCount; - values = pSubpasses; - }; - dependencies = { - type = (array, VkSubpassDependency); - size = dependencyCount; - values = pDependencies; - }; - }; VkSubpassDescription = { flags = auto; pipelineBindPoint = auto; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 68dd2bbe8..6f0ba9892 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -44,6 +44,7 @@ #include "QF/input.h" #include "QF/mathlib.h" #include "QF/qargs.h" +#include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/va.h" @@ -63,6 +64,10 @@ #include "util.h" +static const char quakeforge_pipeline[] = +#include "libs/video/renderer/vulkan/qfpipeline.plc" +; + cvar_t *vulkan_presentation_mode; static void @@ -232,9 +237,22 @@ static qfv_pipelinestagepair_t imageLayoutTransitionStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }, }; +static plitem_t * +qfv_load_pipeline (void) +{ + return PL_GetPropertyList (quakeforge_pipeline); +} + void Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) { + plitem_t *item = qfv_load_pipeline (); + + if (!item || !(item = PL_ObjectForKey (item, "renderpass"))) { + Sys_Printf ("error loading pipeline\n"); + } else { + Sys_Printf ("Found renderer def\n"); + } qfv_device_t *device = ctx->device; VkDevice dev = device->dev; qfv_devfuncs_t *df = device->funcs; From 8290e3800f684aac2abeb5e253978804dcadfff2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 16 Jul 2020 15:44:37 +0900 Subject: [PATCH 112/435] [qwaq] Ensure main thread return code gets returned Needed for catching vkgen errors during the build. --- ruamoko/qwaq/builtins/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ruamoko/qwaq/builtins/main.c b/ruamoko/qwaq/builtins/main.c index c4c426166..0a4faf28b 100644 --- a/ruamoko/qwaq/builtins/main.c +++ b/ruamoko/qwaq/builtins/main.c @@ -480,6 +480,7 @@ main (int argc, char **argv) } } pthread_join (thread_data.a[main_ind]->thread_id, 0); + ret = thread_data.a[main_ind]->return_code; } Sys_Shutdown (); From 72f583f16f3c2a3b997bc73c323bea672ddbf65b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 16 Jul 2020 21:12:05 +0900 Subject: [PATCH 113/435] [util] Fix some plist object parsing errors Forgot to break after finding the field when parsing a dictionary object, and use the correct parser for array objects. --- libs/util/qfplist.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 6949d3e53..26476e44d 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1165,6 +1165,7 @@ PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, result = 0; } } + break; } } if (!f->name) { @@ -1193,8 +1194,8 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, pl_message (messages, array, "error: not an array object"); return 0; } - if (field->parser) { - parser = field->parser; + if (f.parser) { + parser = f.parser; } else { parser = pl_default_parser; } From ef33adac568af526f66612b42335f62a33c8731c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 16 Jul 2020 22:02:26 +0900 Subject: [PATCH 114/435] [util] Make PL_String const correct --- include/QF/qfplist.h | 2 +- libs/util/qfplist.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 089c04856..43eef595b 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -147,7 +147,7 @@ int PL_Line (plitem_t *item) __attribute__((pure)); \note You are NOT responsible for freeing the returned object. It will be destroyed when its container is. */ -const char *PL_String (plitem_t *string) __attribute__((pure)); +const char *PL_String (const plitem_t *string) __attribute__((pure)); /** Retrieve a value from a dictionary object. diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 26476e44d..650be7741 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -232,7 +232,7 @@ PL_Free (plitem_t *item) } VISIBLE const char * -PL_String (plitem_t *string) +PL_String (const plitem_t *string) { if (string->type != QFString) return NULL; From 26cd93f78877feb222349746a95de8b22994095b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 16 Jul 2020 22:04:33 +0900 Subject: [PATCH 115/435] [util] Expose PL_Message It's far to useful elsewhere. --- include/QF/qfplist.h | 2 ++ libs/util/qfplist.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 43eef595b..011090818 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -326,6 +326,8 @@ int PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, plitem_t *messages); int PL_ParseArray (const plfield_t *fields, const plitem_t *dict, void *data, plitem_t *messages); +void __attribute__((format(printf,3,4))) +PL_Message (plitem_t *messages, const plitem_t *item, const char *fmt, ...); ///@} diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 650be7741..6d3ff018d 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1062,8 +1062,8 @@ PL_Line (plitem_t *item) return item->line; } -static void __attribute__((format(printf,3,4))) -pl_message (plitem_t *messages, const plitem_t *item, const char *fmt, ...) +VISIBLE void +PL_Message (plitem_t *messages, const plitem_t *item, const char *fmt, ...) { va_list args; dstring_t *string; @@ -1119,7 +1119,7 @@ pl_default_parser (const plfield_t *field, const plitem_t *item, void *data, *(char **)data = (char *)item->data; return 1; } - pl_message (messages, 0, "invalid item type: %d", field->type); + PL_Message (messages, 0, "invalid item type: %d", field->type); return 0; } @@ -1133,7 +1133,7 @@ PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, plparser_t parser; if (dict->type != QFDictionary) { - pl_message (messages, dict, "error: not a dictionary object"); + PL_Message (messages, dict, "error: not a dictionary object"); return 0; } @@ -1155,7 +1155,7 @@ PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, parser = pl_default_parser; } if (item->type != f->type) { - pl_message (messages, item, "error: %s is the wrong type" + PL_Message (messages, item, "error: %s is the wrong type" " Got %s, expected %s",current->key, pl_types[f->type], pl_types[item->type]); @@ -1169,7 +1169,7 @@ PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, } } if (!f->name) { - pl_message (messages, dict, "error: unknown field %s", + PL_Message (messages, dict, "error: unknown field %s", current->key); result = 0; } @@ -1191,7 +1191,7 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, plfield_t f = { 0, 0, element->type, element->parser, element->data }; if (array->type != QFArray) { - pl_message (messages, array, "error: not an array object"); + PL_Message (messages, array, "error: not an array object"); return 0; } if (f.parser) { @@ -1208,7 +1208,7 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, void *eledata = &arr->a[i * element->stride]; if (item->type != element->type) { - pl_message (messages, item, + PL_Message (messages, item, "error: element %d is the wrong type" " Got %s, expected %s", i, pl_types[element->type], From 16c6818612a9690a221f4b80e0ecf2242bb54fee Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 16 Jul 2020 22:05:15 +0900 Subject: [PATCH 116/435] [util] Set parsed array size correctly The array has to be allocated using byte elements and thus the size of the array is the number of bytes, but it needs to be the actual number of elements in the array. Problem caused by not knowing the actual type (and C not having type variables anyway). --- libs/util/qfplist.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 6d3ff018d..ab24a9499 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1202,6 +1202,10 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, arr = DARRAY_ALLOCFIXED (arr_t, plarray->numvals * element->stride, element->alloc); + memset (arr->a, 0, arr->size); + // the array is allocated using bytes, but need the actual number of + // elements in the array + arr->size = arr->maxSize = plarray->numvals; for (int i = 0; i < plarray->numvals; i++) { plitem_t *item = plarray->values[i]; From 2b23e01d9af5f2cbc7ecc841e8ebbd633e81e6ba Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 17 Jul 2020 00:22:47 +0900 Subject: [PATCH 117/435] [util] Make PL_Type and PL_Line const-correct --- include/QF/qfplist.h | 4 ++-- libs/util/qfplist.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 011090818..3fdfa7825 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -129,7 +129,7 @@ char *PL_WritePropertyList (plitem_t *pl); \param item The object \return the type of the object */ -pltype_t PL_Type (plitem_t *item) __attribute__((pure)); +pltype_t PL_Type (const plitem_t *item) __attribute__((pure)); /** Retrieve the line number of an object. @@ -137,7 +137,7 @@ pltype_t PL_Type (plitem_t *item) __attribute__((pure)); \return the line number on which the object began, or 0 if not from a string */ -int PL_Line (plitem_t *item) __attribute__((pure)); +int PL_Line (const plitem_t *item) __attribute__((pure)); /** Retrieve a string from a string object. diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index ab24a9499..2b96ecdf4 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1051,13 +1051,13 @@ PL_WritePropertyList (plitem_t *pl) } VISIBLE pltype_t -PL_Type (plitem_t *item) +PL_Type (const plitem_t *item) { return item->type; } VISIBLE int -PL_Line (plitem_t *item) +PL_Line (const plitem_t *item) { return item->line; } From 9f4f63796beba75470ac87d86f8686946c3b9890 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 17 Jul 2020 00:23:09 +0900 Subject: [PATCH 118/435] [util] Fix some unitialized vars Not sure how they got past gcc. Maybe a bug in 9.3.0? --- libs/util/qfplist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 2b96ecdf4..8eb7e867c 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1129,7 +1129,7 @@ PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, { void **list, **l; dictkey_t *current; - int result; + int result = 1; plparser_t parser; if (dict->type != QFDictionary) { @@ -1182,7 +1182,7 @@ VISIBLE int PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, plitem_t *messages) { - int result; + int result = 1; plparser_t parser; plarray_t *plarray = (plarray_t *) array->data; plelement_t *element = (plelement_t *) field->data; From 8184c546dbed052ad807ef79ba0f4b948454e09f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 17 Jul 2020 00:24:41 +0900 Subject: [PATCH 119/435] [vulkan] Fix dereference for non-pointer aliases Fixes breakage for uint32_t for array/single handling. --- libs/video/renderer/vulkan/vkgen/vktype.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/vkgen/vktype.r b/libs/video/renderer/vulkan/vkgen/vktype.r index 83373d47a..caa7ac057 100644 --- a/libs/video/renderer/vulkan/vkgen/vktype.r +++ b/libs/video/renderer/vulkan/vkgen/vktype.r @@ -118,7 +118,7 @@ static string get_type_key (void *type, void *unused) -(Type *) dereference { qfot_type_t *t = type; - if (t.meta == ty_alias) { + if (t.meta == ty_alias && t.type == ev_pointer) { t = type.alias.full_type; } if (t.meta == ty_basic && t.type == ev_pointer) { From f4c8d341e13162aa5b65c1fd5609332948bfe122 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 17 Jul 2020 00:29:53 +0900 Subject: [PATCH 120/435] [vulkan] Implement most of the parser This gets renderpass parsing almost working (not hooked up, though). The missing bits are support for expressions for flags (namely support for the | operator) and references (eg $swapchain.format). However, this shows that the basic concept for the parser is working. --- libs/video/renderer/vulkan/vkgen/vkstruct.r | 2 + libs/video/renderer/vulkan/vkparse.c | 133 ++++++++++++++++++-- 2 files changed, 126 insertions(+), 9 deletions(-) diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index ff364202b..dc6aa39d6 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -74,6 +74,8 @@ field_type = [[Type lookup: type_type] dereference]; fprintf (output_file, "static parse_%s_t parse_%s_%s_data = {\n", type_record, [self name], field_name); + fprintf (output_file, "\t%s,\n", [field_type parseType]); + fprintf (output_file, "\tsizeof (%s),\n", type_type); fprintf (output_file, "\tparse_%s,\n", type_type); if (type_record == "single") { value_field = [[field_def getObjectForKey:"value"] string]; diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 51df46a6e..7fb137b29 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -70,44 +70,159 @@ typedef struct enumval_s { } enumval_t; typedef struct parse_single_s { + pltype_t type; + size_t stride; plparser_t parser; size_t value_offset; } parse_single_t; typedef struct parse_array_s { + pltype_t type; + size_t stride; plparser_t parser; - size_t size_offset; size_t value_offset; + size_t size_offset; } parse_array_t; +static int find_enum (const char *valstr, enumval_t *enumval, int *val) +{ + while (enumval->name && strcmp (enumval->name, valstr) != 0) { + enumval++; + } + if (enumval->name) { + *val = enumval->value; + return 1; + } + return 0; +} + static int parse_uint32_t (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages) { - return 0; + int ret = 1; + const char *valstr = PL_String (item); + //Sys_Printf ("parse_uint32_t: %s %zd %d %p %p: %s\n", + // field->name, field->offset, field->type, field->parser, + // field->data, valstr); + if (strcmp (valstr, "VK_SUBPASS_EXTERNAL") == 0) { + *(uint32_t *) data = VK_SUBPASS_EXTERNAL; + } else { + char *end; + unsigned long val = strtoul (valstr, &end, 0); + if (*valstr && !*end && val <= 0xffffffff) { + *(uint32_t *) data = val; + } else if (val > 0xffffffff) { + PL_Message (messages, item, "%lu bigger than 32 bits", val); + ret = 0; + } else { + PL_Message (messages, item, "invalid char at %d in '%s'\n", + (int) (end - valstr), valstr); + ret = 0; + } + } + + return ret; } static int parse_enum (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages) { - return 0; + int ret = 1; + int val; + const char *valstr = PL_String (item); + __auto_type enumval = (enumval_t *) field->data; + //Sys_Printf ("parse_enum: %s %zd %d %p %p %s\n", + // field->name, field->offset, field->type, field->parser, + // field->data, valstr); + if (find_enum (valstr, enumval, &val)) { + *(int *) data = val; + } else { + PL_Message (messages, item, "invalid enum: %s", valstr); + ret = 0; + } + return ret; } static int parse_flags (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages) { - return 0; + int ret = 1; + int val; + const char *valstr = PL_String (item); + __auto_type enumval = (enumval_t *) field->data; + //Sys_Printf ("parse_flags: %s %zd %d %p %p %s\n", + // field->name, field->offset, field->type, field->parser, + // field->data, valstr); + if (find_enum (valstr, enumval, &val)) { + *(int *) data = val; + } else if (strcmp (valstr, "0") == 0) { + *(int *) data = 0; + } else { + PL_Message (messages, item, "invalid enum: %s", valstr); + ret = 0; + } + return ret; } static int parse_single (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages) { - return 0; + __auto_type single = (parse_single_t *) field->data; + void *flddata = (byte *)data + single->value_offset; + + //Sys_Printf ("parse_single: %s %zd %d %p %p\n", field->name, field->offset, + // field->type, field->parser, field->data); + + if (PL_Type (item) != single->type) { + PL_Message (messages, item, "error: wrong type"); + return 0; + } + + plfield_t f = { 0, 0, single->type, single->parser, 0 }; + void *value = calloc (1, single->stride); + if (!single->parser (&f, item, value, messages)) { + free (value); + return 0; + } + + *(void **) flddata = value; + return 1; } static int parse_array (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages) { - return 0; + __auto_type array = (parse_array_t *) field->data; + __auto_type value = (void **) ((byte *)data + array->value_offset); + __auto_type size = (uint32_t *) ((byte *)data + array->size_offset); + + plelement_t element = { + array->type, + array->stride, + malloc, + array->parser, + 0, + }; + plfield_t f = { 0, 0, 0, 0, &element }; + + typedef struct arr_s DARRAY_TYPE(byte) arr_t; + arr_t *arr; + + //Sys_Printf ("parse_array: %s %zd %d %p %p %p\n", + // field->name, field->offset, field->type, field->parser, + // field->data, data); + //Sys_Printf (" %d %zd %p %zd %zd\n", array->type, array->stride, + // array->parser, array->value_offset, array->size_offset); + if (!PL_ParseArray (&f, item, &arr, messages)) { + return 0; + } + *value = malloc (array->stride * arr->size); + memcpy (*value, arr->a, array->stride * arr->size); + if ((void *) size > data) { + *size = arr->size; + } + free (arr); + return 1; } #include "libs/video/renderer/vulkan/vkparse.inc" @@ -144,11 +259,11 @@ static plelement_t parse_qfv_renderpass_dependencies_data = { static plfield_t renderpass_fields[] = { { "attachments", field_offset (qfv_renderpass_t, attachments), QFArray, - parse_array, &parse_qfv_renderpass_attachments_data }, + PL_ParseArray, &parse_qfv_renderpass_attachments_data }, { "subpasses", field_offset (qfv_renderpass_t, subpasses), QFArray, - parse_array, &parse_qfv_renderpass_subpasses_data }, + PL_ParseArray, &parse_qfv_renderpass_subpasses_data }, { "dependencies", field_offset (qfv_renderpass_t, dependencies), QFArray, - parse_array, &parse_qfv_renderpass_dependencies_data }, + PL_ParseArray, &parse_qfv_renderpass_dependencies_data }, {} }; From 91ff15ca7c306eb4f0659f2befd2570fa7630c9d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 17 Jul 2020 00:33:00 +0900 Subject: [PATCH 121/435] [vulkan] Correct some plist errors in the renderpass Typos and incorrect attachment array reference. --- libs/video/renderer/vulkan/qfpipeline.plist | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 059405ceb..1c594aee0 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -37,20 +37,20 @@ ); subpasses = ( { - inputAttachments = ( + colorAttachments = ( { - attachmeht = 0; + attachment = 0; layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } ); resolveAttachments = ( { - attachmeht = 2; + attachment = 2; layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } ); depthStencilAttachment = { - attachmeht = 1; + attachment = 1; layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; }; preserveAttachments = (); From 900728169e647b01877184eb512c8fe0416b371c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 17 Jul 2020 01:20:02 +0900 Subject: [PATCH 122/435] [build] Support silent rules for sed --- libs/video/renderer/Makemodule.am | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 0b68d0b41..1077ef6ca 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -73,12 +73,19 @@ libs_video_renderer_vid_render_gl_la_SOURCES=\ shader_src= libs/video/renderer/glsl/quakeforge.glsl shader_gen= libs/video/renderer/glsl/quakeforge.slc +V_SED = $(V_SED_@AM_V@) +V_SED_ = $(V_SED_@AM_DEFAULT_V@) +V_SED_0 = @echo " SED " $@; +V_SED_1 = + SUFFICES=.frag .vert .fc .vc .slc .glsl .plist .plc .glsl.slc: - sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ + $(V_SED)sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@.t &&\ + $(am__mv) $@.t $@ .plist.plc: - sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ + $(V_SED)sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' $< > $@.t &&\ + $(am__mv) $@.t $@ video_renderer_glsl_libs= \ libs/models/libmodels_glsl.la @@ -249,6 +256,7 @@ CLEANFILES += \ libs/video/renderer/glsl/*.fc \ libs/video/renderer/glsl/*.slc \ libs/video/renderer/vulkan/*.plc \ + libs/video/renderer/vulkan/vkgen.sym \ $(vkparse_src) BUILT_SOURCES += $(shader_gen) From 3413947e0cc6d50fb103feda206cec15159f569d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 17 Jul 2020 20:11:44 +0900 Subject: [PATCH 123/435] [qfmap] Update script.py from io_object_mu While not necessary for qf (at this stage), this brings in support for optionally not parsing strings and better utf-8 and wide char handling. --- tools/io_qfmap/script.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/io_qfmap/script.py b/tools/io_qfmap/script.py index 9e34934f9..fc030e3e5 100644 --- a/tools/io_qfmap/script.py +++ b/tools/io_qfmap/script.py @@ -25,10 +25,15 @@ class ScriptError(Exception): self.line = line class Script: - def __init__(self, filename, text, single="{}()':"): + def __init__(self, filename, text, single="{}()':", quotes=True): self.filename = filename + if text[0:3] == "\xef\xbb\xbf": + text = text[3:] + elif text[0] == u"\ufeff": + text = text[1:] self.text = text self.single = single + self.quotes = quotes self.pos = 0 self.line = 1 self.unget = False @@ -87,7 +92,7 @@ class Script: if not crossline: self.error("line is incomplete") return None - if self.text[self.pos] == "\"": + if self.quotes and self.text[self.pos] == "\"": self.pos += 1 start = self.pos if self.text[self.pos] == len(self.text): From 62c20aa4abe6a68e1082471908241a3ad7db5ae6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Aug 2020 11:30:53 +0900 Subject: [PATCH 124/435] [ruamoko] Fix incorrect clearing of dtables The problem was caused by passing the index into the dtables array to dtable_get which expects a handle. A handle is the ones-compliment negative of the index which means that handle 0 is invalid (but 0 was being passed... oops). Fixes the segfault when qw-client-x11 connects to a server. --- libs/ruamoko/rua_obj.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index 7ecc8ef28..baa8fe73b 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -2192,7 +2192,10 @@ rua_obj_cleanup (progs_t *pr, void *data) } for (i = 0; i < probj->dtables._size; i++) { - dtable_t *dtable = dtable_get (probj, i); + /* dtable_get expects a handle, but a handle is the ones-compliment + * negative of the index. + */ + dtable_t *dtable = dtable_get (probj, ~i); if (!dtable->imp) { break; } From 550b9c3bb2bdedc7ffcafd7f0f8cbad290122df3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Aug 2020 14:35:20 +0900 Subject: [PATCH 125/435] [qfcc] Fix silent make rules flex and bison --- tools/qfcc/source/Makemodule.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/source/Makemodule.am b/tools/qfcc/source/Makemodule.am index d8db07b5c..dacfd3448 100644 --- a/tools/qfcc/source/Makemodule.am +++ b/tools/qfcc/source/Makemodule.am @@ -80,13 +80,13 @@ BUILT_SOURCES += \ tools/qfcc/source/qp-lex.c tools/qfcc/source/qc-parse.c: tools/qfcc/source/qc-parse.y - $(YACC) $(YFLAGS) -Dapi.prefix={qc_yy} $< -o $@ + $(AM_V_YACC)$(YACCCOMPILE) -Dapi.prefix={qc_yy} $< -o $@ tools/qfcc/source/qc-lex.c: tools/qfcc/source/qc-lex.l tools/qfcc/source/qc-parse.h - $(LEX) $(LFLAGS) $(AM_LFLAGS) -Pqc_yy -o$@ $< + $(AM_V_LEX)$(LEXCOMPILE) -Pqc_yy -o$@ $< tools/qfcc/source/qp-parse.c: tools/qfcc/source/qp-parse.y - $(YACC) $(YFLAGS) -Dapi.prefix={qp_yy} $< -o $@ + $(AM_V_YACC)$(YACCCOMPILE) -Dapi.prefix={qp_yy} $< -o $@ tools/qfcc/source/qp-lex.c: tools/qfcc/source/qp-lex.l tools/qfcc/source/qp-parse.h - $(LEX) $(LFLAGS) $(AM_LFLAGS) -Pqp_yy -o$@ $< + $(AM_V_LEX)$(LEXCOMPILE) -Pqp_yy -o$@ $< EXTRA_DIST += \ tools/qfcc/source/qfpreqcc From 4a8818f0b6d3d8bc1b5303a0e3f954fa9a6f3ee7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Aug 2020 14:36:08 +0900 Subject: [PATCH 126/435] [qfcc] Clean up some excess includes --- tools/qfcc/source/defspace.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tools/qfcc/source/defspace.c b/tools/qfcc/source/defspace.c index 72537f2d0..1cfe572c3 100644 --- a/tools/qfcc/source/defspace.c +++ b/tools/qfcc/source/defspace.c @@ -44,15 +44,9 @@ #include "QF/sys.h" #include "QF/va.h" -#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/def.h" #include "tools/qfcc/include/defspace.h" #include "tools/qfcc/include/diagnostic.h" -#include "tools/qfcc/include/expr.h" -#include "tools/qfcc/include/options.h" -#include "tools/qfcc/include/reloc.h" -#include "tools/qfcc/include/strpool.h" -#include "tools/qfcc/include/struct.h" -#include "tools/qfcc/include/type.h" typedef struct locref_s { struct locref_s *next; From e991c44232cf1a1ca19946374536bb88ed687fbc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 14 Dec 2020 13:36:28 +0900 Subject: [PATCH 127/435] [util] Make a minor improvement to QuatMultVec Switch from using addition to multiplication for doubling the value. Also, fix lib/util/test Makemodule to actually work (too much c&p coding). --- libs/util/mathlib.c | 2 +- libs/util/test/Makemodule.am | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libs/util/mathlib.c b/libs/util/mathlib.c index 842f96df1..1267df2ad 100644 --- a/libs/util/mathlib.c +++ b/libs/util/mathlib.c @@ -268,7 +268,7 @@ QuatMultVec (const quat_t q, const vec3_t v, vec3_t out) dqq = DotProduct (q, q); VectorScale (tv, s, tv); VectorMultAdd (tv, dqv, q, tv); - VectorAdd (tv, tv, tv); + VectorScale (tv, 2, tv); VectorMultAdd (tv, s * s - dqq, v, out); } diff --git a/libs/util/test/Makemodule.am b/libs/util/test/Makemodule.am index cf35f885c..8bbb671ad 100644 --- a/libs/util/test/Makemodule.am +++ b/libs/util/test/Makemodule.am @@ -14,9 +14,10 @@ libs_util_tests = \ libs/util/test/test-set \ libs/util/test/test-txtbuffer \ libs/util/test/test-vrect -check_PROGRAMS += $(libs_util_tests) -TESTS += $(libs_model_tests) +TESTS += $(libs_util_tests) + +check_PROGRAMS += $(libs_util_tests) libs_util_test_test_bary_SOURCES=libs/util/test/test-bary.c libs_util_test_test_bary_LDADD=libs/util/libQFutil.la From 62f3e1f428406d3d5a0a7e3c87821111c7e922d0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 19 Dec 2020 17:29:08 +0900 Subject: [PATCH 128/435] [util] Calculate quaternion to rotate between two vectors The calculation fails (produces NaN) if the vectors are anti-parallel, but works for all other combinations. I came up with this implementation when I discovered Unity's Quaternion.FromToRotation could did not work with very small angles. This implementation will produce a usable quaternion below 0.00255 degrees (though it will be slightly larger than unit). Unity's failed such that I could see KSP's skybox snap while it rotated around my test vessel. --- include/QF/math/quaternion.h | 1 + libs/util/mathlib.c | 18 +++++++ libs/util/test/test-quat.c | 102 +++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) diff --git a/include/QF/math/quaternion.h b/include/QF/math/quaternion.h index d6e34814a..da39b7734 100644 --- a/include/QF/math/quaternion.h +++ b/include/QF/math/quaternion.h @@ -164,6 +164,7 @@ extern const vec_t *const quat_origin; void QuatMult (const quat_t q1, const quat_t q2, quat_t out); void QuatMultVec (const quat_t q, const vec3_t v, vec3_t out); +void QuatRotation (const vec3_t a, const vec3_t b, quat_t out); void QuatInverse (const quat_t in, quat_t out); void QuatExp (const quat_t a, quat_t b); void QuatToMatrix (const quat_t q, vec_t *m, int homogenous, int vertical); diff --git a/libs/util/mathlib.c b/libs/util/mathlib.c index 1267df2ad..2d547f756 100644 --- a/libs/util/mathlib.c +++ b/libs/util/mathlib.c @@ -272,6 +272,24 @@ QuatMultVec (const quat_t q, const vec3_t v, vec3_t out) VectorMultAdd (tv, s * s - dqq, v, out); } +VISIBLE void +QuatRotation(const vec3_t a, const vec3_t b, quat_t out) +{ + vec_t ma, mb; + vec_t den, mba_mab; + vec3_t t; + + ma = VectorLength(a); + mb = VectorLength(b); + den = 2 * ma * mb; + VectorScale (a, mb, t); + VectorMultAdd(t, ma, b, t); + mba_mab = VectorLength(t); + CrossProduct (a, b, t); + VectorScale(t, 1 / mba_mab, out); + out[3] = mba_mab / den; +} + VISIBLE void QuatInverse (const quat_t in, quat_t out) { diff --git a/libs/util/test/test-quat.c b/libs/util/test/test-quat.c index 44c8923b3..11cc5b617 100644 --- a/libs/util/test/test-quat.c +++ b/libs/util/test/test-quat.c @@ -29,6 +29,45 @@ static vec3_t test_angles[] = { }; #define num_angle_tests (sizeof (test_angles) / sizeof (test_angles[0])) +static struct { + vec3_t a; + vec3_t b; + quat_t expect; +} quat_vector_rotation_tests[] = { + {{1, 0, 0}, {1, 0, 0}, {0, 0, 0, 1}}, + {{0, 1, 0}, {0, 1, 0}, {0, 0, 0, 1}}, + {{0, 0, 1}, {0, 0, 1}, {0, 0, 0, 1}}, + {{1, 0, 0}, {8, 0, 0}, {0, 0, 0, 1}}, + {{0, 8, 0}, {0, 1, 0}, {0, 0, 0, 1}}, + {{0, 0, 8}, {0, 0, 8}, {0, 0, 0, 1}}, + {{1, 0, 0}, {-1, 0, 0}, {0, 0, 0, 0}}, // x, y, z = NaN + {{0, -1, 0}, {0, 1, 0}, {0, 0, 0, 0}}, // x, y, z = NaN + {{0, 0, 1}, {0, 0, -1}, {0, 0, 0, 0}}, // x, y, z = NaN + {{-1, 0, 0}, {8, 0, 0}, {0, 0, 0, 0}}, // x, y, z = NaN + {{0, 8, 0}, {0, -1, 0}, {0, 0, 0, 0}}, // x, y, z = NaN + {{0, 0, -8}, {0, 0, 8}, {0, 0, 0, 0}}, // x, y, z = NaN + // excessive for float, but if vec_t becomes double... + // 1/50 second orbiting JNSQ Kerbin at 120km altitude. While this has + // nothing to do with quakeforge (yet?), it came up when testing camera + // rotation in KSP and Unity failed miserably. I don't remember the exact + // details, but I could see significant snapping in the rotation (I thought + // it was a few times per second, but these numbers indicate it must have + // been every few seconds). + // The quaternion is unit to 9 sigfigs (a little larger) + {{1720000, 0, 0}, {1719999.9983028059, 76.409082595828366, 0}, {0, 0, 2.22119434e-5, 1}}, + // 1/20 second, same situation + {{1720000, 0, 0}, {1719999.9893925365, 191.02270615971355, 0}, {0, 0, 5.55298575e-5, 1}}, + // 1/5 second, same situation + {{1720000, 0, 0}, {1719999.8302805868, 764.09080107761736, 0}, {0, 0, 2.2211943e-4, 1}}, + // 1/4 second, same situation + {{1720000, 0, 0}, {1719999.7348134194, 955.11348367609469, 0}, {0, 0, 2.77649262e-4, 1}}, + // 1/3 second, same situation. This is (float) 1 ulp in w: about 0.0424 + // degrees. + // The quaternion is unit to 9 sigfigs (a little larger) + {{1720000, 0, 0}, {1719999.5285571995, 1273.4845939975546, 0}, {0, 0, 3.70199094e-4, 0.99999994}}, +}; +#define num_quat_vector_rotation_tests (sizeof (quat_vector_rotation_tests) / sizeof (quat_vector_rotation_tests[0])) + // return true if a and b are close enough (yay, floats) static int compare (vec_t a, vec_t b) @@ -200,6 +239,60 @@ fail: return 0; } +static int +test_rotation4 (const vec3_t a, const vec3_t b, const quat_t expect) +{ + int i; + quat_t quat; + vec3_t t; + vec_t d = 0; + + VectorZero (t); + + // find the rotation vector between a and b + QuatRotation (a, b, quat); + + if (quat[3] == 0) { + if (expect[3] != 0) { + goto fail; + } + // expect NaN for the vector components because the vectors are + // anti-parallel and thus the rotation axis is undefined + if (!(isnan(quat[0]) && isnan(quat[1]) && isnan(quat[2]))) { + goto fail; + } + } else { + // the vectors are not anti-parallel and thus the rotation axis is + // defined, so NaN is invalid + if (isnan(quat[0]) || isnan(quat[1]) || isnan(quat[2])) { + goto fail; + } + for (i = 0; i < 4; i++) { + // yes, float precision will make it difficult to set up expect + // but it is at least consistent (ie, the "errors" are not at all + // random and thus will be the same from run to run) + if (quat[i] != expect[i]) { + goto fail; + } + } + QuatMultVec(quat, a, t); + + d = DotProduct (t, b) / (VectorLength (t) * VectorLength (b)) - 1; + if (d * d > 1e-8) { + goto fail; + } + } + return 1; +fail: + printf ("\ntest_rotation4\n"); + printf ("%11.9g %11.9g %11.9g\n", VectorExpand(a)); + printf ("%11.9g %11.9g %11.9g\n", VectorExpand(b)); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand(quat)); + printf ("%11.9g %11.9g %11.9g\n", VectorExpand(t)); + printf ("%11.9g\n", d); + return 0; +} + #define s05 0.70710678118654757 static struct { @@ -285,6 +378,15 @@ main (int argc, const char **argv) res = 1; } + for (i = 0; i < num_quat_vector_rotation_tests; i++) { + vec_t *a = quat_vector_rotation_tests[i].a; + vec_t *b = quat_vector_rotation_tests[i].b; + vec_t *expect = quat_vector_rotation_tests[i].expect; + if (!test_rotation4 (a, b, expect)) { + res = 1; + } + } + for (i = 0; i < num_quat_mat_tests; i ++) { vec_t *q = quat_mat_tests[i].q; vec_t *expect = quat_mat_tests[i].expect; From af814ff9a80fb57ba52866a0dc5c2e89a4169320 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 19 Dec 2020 17:37:22 +0900 Subject: [PATCH 129/435] [util] Add a cache-line aligned memory allocator This was inspired by Hoard: A Scalable Memory Allocator for Multithreaded Applications Emery D. Berger, Kathryn S. McKinley, Robert D. Blumofe, Paul R. Wilson, It's not anywhere near the same implementation, but it did take a few basic concepts. The idea is twofold: 1) A pool of memory from which blocks can be allocated and then freed en-mass and is fairly efficient for small (4-16 byte) blocks 2) Tread safety for use with the Vulkan renderer (and any other multi-threaded tasks). However, based on the Hoard paper, small allocations are cache-line aligned. On top of that, larger allocations are page aligned. I suspect it would help qfvis somewhat if I ever get around to tweaking qfvis to use cmem. --- include/QF/cmem.h | 96 ++++++++++ libs/util/Makemodule.am | 1 + libs/util/cmem.c | 327 +++++++++++++++++++++++++++++++++ libs/util/test/Makemodule.am | 5 + libs/util/test/test-cmem.c | 346 +++++++++++++++++++++++++++++++++++ 5 files changed, 775 insertions(+) create mode 100644 include/QF/cmem.h create mode 100644 libs/util/cmem.c create mode 100644 libs/util/test/test-cmem.c diff --git a/include/QF/cmem.h b/include/QF/cmem.h new file mode 100644 index 000000000..966696d6c --- /dev/null +++ b/include/QF/cmem.h @@ -0,0 +1,96 @@ +/* + cmem.h + + Cache-line aligned memory allocator + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __cmem_h +#define __cmem_h + +#include "QF/qtypes.h" + +#define MEM_LINE_SIZE 64 + +typedef struct memline_s { + struct memline_s *next; + size_t size; + size_t pad[6]; +} memline_t; + +typedef struct memsline_s { + struct memsline_s *next; + size_t size:2; + size_t list:4; + size_t prev:58; // memsline_t ** +} memsline_t; + +typedef struct memblock_s { + struct memblock_s *next; + struct memblock_s **prev; + /* The pointer to pass to free() + */ + void *mem; + memline_t *free_lines; + /* Size of memory region before block "header". + * + * Since large blocks are allocated with page-size alignment, odds are + * high that the there will be many cache lines "wasted" in the space + * between the address returned from aligned_alloc (to cache-line + * alignment) and the block itself. Setting them up as a pool makes the + * lines available for smaller allocations, thus reducing waste. + */ + size_t pre_size; + /* Size of memory region after block "header". + * + * Will be 0 for blocks that were allocated exclusively for small + * allocations, otherwise indicates the size of the allocated block. + */ + size_t post_size; + /* True if the post-header block is free to be reused. + */ + int post_free; + int pad; + size_t pre_allocated; +} memblock_t; + +typedef struct memsuper_s { + size_t page_size; + size_t page_mask; + memblock_t *memblocks; + /* Allocated cache lines from which smaller blocks can be allocated. + * + * The index is the base-2 log minus 2 of the size of the elements in the + * cache line from which an element was last freed. Only 4-32 bytes are of + * interest because nothing smaller than 4 bytes (int/float) will be + * allocated, and 64 bytes and up consume entire cache lines. + */ + memsline_t *last_freed[4]; + size_t pad; +} memsuper_t; + +memsuper_t *new_memsuper (void); +void delete_memsuper (memsuper_t *super); +void *cmemalloc (memsuper_t *super, size_t size); +void cmemfree (memsuper_t *super, void *mem); + +#endif//__cmem_h diff --git a/libs/util/Makemodule.am b/libs/util/Makemodule.am index 272459d4d..af99b15d3 100644 --- a/libs/util/Makemodule.am +++ b/libs/util/Makemodule.am @@ -45,6 +45,7 @@ libs_util_libQFutil_la_SOURCES= \ libs/util/cbuf.c \ libs/util/checksum.c \ libs/util/cmd.c \ + libs/util/cmem.c \ libs/util/crc.c \ libs/util/cvar.c \ libs/util/dstring.c \ diff --git a/libs/util/cmem.c b/libs/util/cmem.c new file mode 100644 index 000000000..b446e58f0 --- /dev/null +++ b/libs/util/cmem.c @@ -0,0 +1,327 @@ +/* + cmem.c + + Cache-line aligned memory allocator + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#include + +#include "QF/alloc.h" +#include "QF/cmem.h" + + +memsuper_t * +new_memsuper (void) +{ + memsuper_t *super = aligned_alloc (MEM_LINE_SIZE, sizeof (*super)); + memset (super, 0, sizeof (*super)); + super->page_size = sysconf (_SC_PAGESIZE); + super->page_mask = (super->page_size - 1); + return super; +} + +void +delete_memsuper (memsuper_t *super) +{ + while (super->memblocks) { + memblock_t *t = super->memblocks; + super->memblocks = super->memblocks->next; + free (t->mem); + } + free (super); +} + +static memblock_t * +init_block (memsuper_t *super, void *mem, size_t alloc_size) +{ + size_t size = super->page_size; + size_t mask = super->page_mask; + size_t ptr = (size_t) mem; + memblock_t *block; + + block = (memblock_t *) (((ptr + size) & ~mask) - sizeof (memblock_t)); + memset (block, 0, sizeof (memblock_t)); + + if (super->memblocks) { + super->memblocks->prev = &block->next; + } + block->next = super->memblocks; + block->prev = &super->memblocks; + super->memblocks = block; + + block->mem = mem; + block->pre_size = (size_t) block - (size_t) mem; + block->post_size = alloc_size - block->pre_size - sizeof (memblock_t); + if (!((size_t) mem & mask) && block->pre_size) { + // can't use the first cache line of the page as it would be + // indistinguishable from a large block + block->pre_size -= MEM_LINE_SIZE; + } + if (block->pre_size) { + block->free_lines = (memline_t *) ((size_t) block - block->pre_size); + block->free_lines->next = 0; + block->free_lines->size = block->pre_size; + } + return block; +} + +static memblock_t * +block_alloc (memsuper_t *super, size_t size) +{ + memblock_t *block; + memblock_t *best = 0; + size_t best_size = ~0u; + + for (block = super->memblocks; block; block = block->next) { + if (block->post_free && block->post_size >= size + && block->post_size < best_size) { + best = block; + best_size = block->post_size; + } + } + if (best) { + best->post_free = 0; + return best; + } + + size_t page_size = super->page_size; + size_t alloc_size = sizeof (memblock_t) + page_size + size; + void *mem = aligned_alloc (MEM_LINE_SIZE, alloc_size); + block = init_block (super, mem, alloc_size); + return block; +} + +static void * +line_alloc (memblock_t *block, size_t size) +{ + memline_t **line = &block->free_lines; + memline_t **best = 0; + memline_t *mem; + size_t best_size = ~0u; + + while (*line) { + if ((*line)->size >= size && (*line)->size < best_size) { + best_size = (*line)->size; + best = line; + } + line = &(*line)->next; + } + if (!best) { + return 0; + } + mem = *best; + if (size < best_size) { + *best = (memline_t *)((size_t) mem + size); + (*best)->next = mem->next; + (*best)->size = mem->size - size; + } else { + *best = (*best)->next; + } + block->pre_allocated += size; + return mem; +} + +static void +line_free (memblock_t *block, void *mem) +{ + //FIXME right now, can free only single lines (need allocated lines to + // have a control block) + size_t size = MEM_LINE_SIZE; + memline_t **l; + memline_t *line = 0; + + block->pre_allocated -= size; + + for (l = &block->free_lines; *l; l = &(*l)->next) { + line = *l; + + if ((size_t) mem + size < (size_t) line) { + // line to be freed is below the free line + break; + } + if ((size_t) mem + size == (size_t) line) { + // line to be freed is immediately below the free line + // merge with the free line + size += line->size; + line = line->next; + break; + } + if ((size_t) line + line->size == (size_t) mem) { + // line to be freed is immediately above the free line + // merge with the free line + line->size += size; + if (line->next && (size_t) line->next == (size_t) mem + size) { + line->size += line->next->size; + line->next = line->next->next; + } + return; + } + } + ((memline_t *) mem)->next = line; + ((memline_t *) mem)->size = size; + *l = mem; +} + +static memsline_t * +sline_new (memsuper_t *super, size_t size_ind) +{ + size_t size = 4 << size_ind; + size_t free_loc = (sizeof (memsline_t) + size - 1) & ~(size - 1); + memsline_t *sline = cmemalloc (super, MEM_LINE_SIZE); + sline->size = size_ind; + sline->list = free_loc >> 2; + while (free_loc + size < MEM_LINE_SIZE) { + *(uint16_t *)((size_t) sline + free_loc) = free_loc + size; + free_loc += size; + } + *(uint16_t *)((size_t) sline + free_loc) = 0; + if (super->last_freed[size_ind]) { + super->last_freed[size_ind]->prev = (size_t) &sline->next >> 6; + } + sline->next = super->last_freed[size_ind]; + sline->prev = (size_t) &super->last_freed[size_ind] >> 6; + super->last_freed[size_ind] = sline; + return sline; +} + +void * +cmemalloc (memsuper_t *super, size_t size) +{ + size_t ind = 0; + // allocation sizes start at 4 (sizeof(float)) and go up in powers of two + while ((4u << ind) < size) { + ind++; + } + // round size up + if (size > MEM_LINE_SIZE * 8 || size > super->page_size / 8) { + // the object is large enough it could cause excessive fragmentation, + memblock_t *block = block_alloc (super, 4 << ind); + if (!block) { + return 0; + } + return block + 1; + } else { + size = 4 << ind; + if (size >= MEM_LINE_SIZE) { + // whole cache lines are required for this object + // FIXME slow + memblock_t *block = super->memblocks; + void *mem; + + while (block) { + if ((mem = line_alloc (block, size))) { + return mem; + } + block = block->next; + } + /* The cache-line pool is page aligned for two reasons: + * 1) so it fits exactly within a page + * 2) the control block can be found easily + * And the reason the pool is exactly one page large is so no + * allocated line is ever page-aligned as that would make the line + * indistinguishable from a large block. + */ + mem = aligned_alloc (super->page_size, super->page_size); + block = init_block (super, mem, super->page_size); + return line_alloc (block, size); + } else { + void *mem = 0; + memsline_t **sline = &super->last_freed[ind]; + if (!*sline) { + *sline = sline_new (super, ind); + } + if (*sline) { + size_t list = (*sline)->list << 2; + mem = (void *) ((size_t) *sline + list); + (*sline)->list = *(uint16_t *) mem >> 2; + if (!(*sline)->list) { + // the sub-line is full, so remove it from the free + // list. Freeing a block from the line will add it back + // to the list + memsline_t *s = *sline; + if ((*sline)->next) { + (*sline)->next->prev = (*sline)->prev; + } + *sline = (*sline)->next; + s->next = 0; + s->prev = 0; + } + } + return mem; + } + } + return 0; +} + +static void +unlink_block (memblock_t *block) +{ + if (block->next) { + block->next->prev = block->prev; + } + *block->prev = block->next; +} + +void +cmemfree (memsuper_t *super, void *mem) +{ + memsline_t **super_sline; + memsline_t *sline; + memblock_t *block; + + if ((size_t) mem & (MEM_LINE_SIZE - 1)) { + // sub line block + sline = (memsline_t *) ((size_t) mem & ~(MEM_LINE_SIZE - 1)); + *(uint16_t *) mem = sline->list << 2; + sline->list = (size_t) mem & (MEM_LINE_SIZE - 1); + super_sline = &super->last_freed[sline->size]; + if (*super_sline != sline) { + if (sline->next) { + sline->next->prev = sline->prev; + } + if (sline->prev) { + *(memsline_t **) (size_t)(sline->prev << 6) = sline->next; + } + + (*super_sline)->prev = (size_t) &sline->next >> 6; + sline->next = *super_sline; + sline->prev = (size_t) super_sline >> 6; + (*super_sline) = sline; + } + return; + } else if ((size_t) mem & super->page_mask) { + // cache line + size_t page_size = super->page_size; + size_t page_mask = super->page_mask; + block = (memblock_t *) (((size_t) mem + page_size) & ~page_mask) - 1; + line_free (block, mem); + } else { + // large block + block = (memblock_t *) mem - 1; + block->post_free = 1; + } + if (!block->pre_allocated && (!block->post_size || block->post_free)) { + unlink_block (block); + free (block->mem); + } +} diff --git a/libs/util/test/Makemodule.am b/libs/util/test/Makemodule.am index 8bbb671ad..39140bee7 100644 --- a/libs/util/test/Makemodule.am +++ b/libs/util/test/Makemodule.am @@ -1,5 +1,6 @@ libs_util_tests = \ libs/util/test/test-bary \ + libs/util/test/test-cmem \ libs/util/test/test-cs \ libs/util/test/test-darray \ libs/util/test/test-dq \ @@ -23,6 +24,10 @@ libs_util_test_test_bary_SOURCES=libs/util/test/test-bary.c libs_util_test_test_bary_LDADD=libs/util/libQFutil.la libs_util_test_test_bary_DEPENDENCIES=libs/util/libQFutil.la +libs_util_test_test_cmem_SOURCES=libs/util/test/test-cmem.c +libs_util_test_test_cmem_LDADD=libs/util/libQFutil.la +libs_util_test_test_cmem_DEPENDENCIES=libs/util/libQFutil.la + libs_util_test_test_cs_SOURCES=libs/util/test/test-cs.c libs_util_test_test_cs_LDADD=libs/util/libQFutil.la libs_util_test_test_cs_DEPENDENCIES=libs/util/libQFutil.la diff --git a/libs/util/test/test-cmem.c b/libs/util/test/test-cmem.c new file mode 100644 index 000000000..c8c2ee7e3 --- /dev/null +++ b/libs/util/test/test-cmem.c @@ -0,0 +1,346 @@ +#include +#include +#include +#include + +#include "QF/cmem.h" + +static int +test_block (memsuper_t *super) +{ + size_t size = super->page_size; + void *mem = cmemalloc (super, size); + memblock_t *block; + + if (!mem) { + fprintf (stderr, "could not allocate %zd byte block\n", + super->page_size); + return 0; + } + if ((size_t) mem & super->page_mask) { + fprintf (stderr, "mem not page aligned: %p %zd\n", + mem, super->page_size); + return 0; + } + block = super->memblocks; + if (mem != block + 1) { + fprintf (stderr, "super does not point to mem\n"); + return 0; + } + if (block->post_size < size) { + fprintf (stderr, "block post_size too small: %zd < %zd\n", + block->post_size, size); + return 0; + } + if (block->post_size - size >= super->page_size) { + fprintf (stderr, "block post_size too big: %zd < %zd\n", + block->post_size - size, super->page_size); + return 0; + } + memset (mem, 0, size); // valgrind check + cmemfree (super, mem); + if (super->memblocks) { + fprintf (stderr, "super still points to mem\n"); + return 0; + } + return 1; +} + +static int +test_line (memsuper_t *super) +{ + memline_t *line1 = cmemalloc (super, MEM_LINE_SIZE); + memline_t *line2 = cmemalloc (super, MEM_LINE_SIZE); + memline_t *line3 = cmemalloc (super, MEM_LINE_SIZE); + memblock_t *block = super->memblocks; + + if (block->next) { + fprintf (stderr, "too many memblocks\n"); + return 0; + } + if (line1 < (memline_t *) block->mem || line1 >= (memline_t *) block) { + fprintf (stderr, "line1 outside block line pool\n"); + return 0; + } + if (line2 < (memline_t *) block->mem || line2 >= (memline_t *) block) { + fprintf (stderr, "line2 outside block line pool\n"); + return 0; + } + if (line3 < (memline_t *) block->mem || line3 >= (memline_t *) block) { + fprintf (stderr, "line3 outside block line pool\n"); + return 0; + } + if (!((size_t) line1 & super->page_mask)) { + fprintf (stderr, "line1 is page aligned\n"); + return 0; + } + if (!((size_t) line2 & super->page_mask)) { + fprintf (stderr, "line2 is page aligned\n"); + return 0; + } + if (!((size_t) line3 & super->page_mask)) { + fprintf (stderr, "line3 is page aligned\n"); + return 0; + } + if (line1 + 1 != line2 || line2 + 1 != line3) { + fprintf (stderr, "lines not contiguous\n"); + return 0; + } + if (line3 + 1 != block->free_lines) { + fprintf (stderr, "line3 not contiguous with free lines\n"); + return 0; + } + if (block->free_lines->next) { + fprintf (stderr, "multiple free line blocks\n"); + return 0; + } + if (block->pre_allocated != 3 * MEM_LINE_SIZE) { + fprintf (stderr, "pre_allocated wrong size: %zd != %d\n", + block->pre_allocated, 3 * MEM_LINE_SIZE); + return 0; + } + if (block->free_lines->size != block->pre_size - block->pre_allocated) { + fprintf (stderr, "free lines wrong size: %zd != %zd\n", + block->free_lines->size, + block->pre_size - block->pre_allocated); + return 0; + } + size_t old_size = block->free_lines->size; + memline_t *old_line = block->free_lines; + cmemfree (super, line2); + if (block->pre_allocated != 2 * MEM_LINE_SIZE) { + fprintf (stderr, "pre_allocated wrong size: %zd != %d\n", + block->pre_allocated, 2 * MEM_LINE_SIZE); + return 0; + } + if (block->free_lines != line2) { + fprintf (stderr, "free lines not pointing to line2\n"); + return 0; + } + if (!block->free_lines->next || block->free_lines->next->next) { + fprintf (stderr, "incorrect number of free blocks\n"); + return 0; + } + if (line2->next != old_line || old_line->size != old_size) { + fprintf (stderr, "free line blocks corrupted\n"); + return 0; + } + if (block->free_lines->size != MEM_LINE_SIZE) { + fprintf (stderr, "free line block wrong size: %zd != %d\n", + block->free_lines->size, MEM_LINE_SIZE); + return 0; + } + cmemfree (super, line3); + if (block->free_lines != line2) { + fprintf (stderr, "free lines not pointing to line2 2\n"); + return 0; + } + if (block->pre_allocated != MEM_LINE_SIZE) { + fprintf (stderr, "pre_allocated wrong size: %zd != %d\n", + block->pre_allocated, MEM_LINE_SIZE); + return 0; + } + if (block->free_lines->size != block->pre_size - block->pre_allocated) { + fprintf (stderr, "free lines wrong size: %zd != %zd\n", + block->free_lines->size, + block->pre_size - block->pre_allocated); + return 0; + } + cmemfree (super, line1); + if (super->memblocks) { + fprintf (stderr, "line pool not freed\n"); + return 0; + } + return 1; +} + +static int +test_sline (memsuper_t *super) +{ + void *mem[] = { + //cmemalloc (super, 2), // smaller than min size + cmemalloc (super, 4), + cmemalloc (super, 4), + cmemalloc (super, 8), + cmemalloc (super, 8), + cmemalloc (super, 16), + cmemalloc (super, 16), + cmemalloc (super, 32), + cmemalloc (super, 32), + }; +#define mem_size (sizeof (mem) / sizeof (mem[0])) + int fail = 0; + for (size_t i = 0; i < mem_size; i++) { + printf("%p\n", mem[i]); + if (!mem[i]) { + fprintf (stderr, "mem[%zd] is null\n", i); + fail = 1; + } + for (size_t j = i + 1; j < mem_size; j++) { + if (mem[i] == mem[j]) { + fprintf (stderr, "mem[%zd] is dupped with %zd\n", i, j); + fail = 1; + } + } + } + if (fail) { + return 0; + } +#undef mem_size + return 1; +} + +static int +test_block_line (memsuper_t *super) +{ + void *mem = cmemalloc (super, 2 * super->page_size); + void *line; + memblock_t *block = super->memblocks; + + if (block + 1 != (memblock_t *) mem) { + fprintf (stderr, "super memblocks do not point to mem\n"); + return 0; + } + if (block->pre_size < MEM_LINE_SIZE) { + // need to figure out a way to guarantee a shared block + fprintf (stderr, "can't allocate line from block\n"); + return 0; + } + if (block->next) { + fprintf (stderr, "excess blocks in super\n"); + return 0; + } + line = cmemalloc (super, MEM_LINE_SIZE); + if (!((size_t) line & super->page_mask)) { + fprintf (stderr, "line is page aligned\n"); + return 0; + } + if (super->memblocks->next) { + // need to figure out a way to guarantee a shared block + fprintf (stderr, "mem and line not in same block\n"); + return 0; + } + cmemfree (super, mem); + if (!super->memblocks) { + fprintf (stderr, "shared block freed\n"); + return 0; + } + if (cmemalloc (super, super->page_size) != mem) { + fprintf (stderr, "block not reused for mem\n"); + return 0; + } + if (super->memblocks != block || super->memblocks->next) { + // need to figure out a way to guarantee a shared block + fprintf (stderr, "blocks corrupt\n"); + return 0; + } + cmemfree (super, line); + if (!super->memblocks) { + fprintf (stderr, "shared block freed 2\n"); + return 0; + } + cmemfree (super, mem); + if (super->memblocks) { + fprintf (stderr, "shared block not freed\n"); + return 0; + } + return 1; +} + +int +main (void) +{ + memsuper_t *super = new_memsuper (); + + if (sizeof (memsuper_t) != MEM_LINE_SIZE) { + fprintf (stderr, "memsuper_t not cache size: %zd\n", + sizeof (memline_t)); + return 1; + } + if (sizeof (memline_t) != MEM_LINE_SIZE) { + fprintf (stderr, "memline_t not cache size: %zd\n", + sizeof (memline_t)); + return 1; + } + if (sizeof (memsline_t) != 2 * sizeof (void *)) { + fprintf (stderr, "memsline_t not two pointers: %zd\n", + sizeof (memsline_t)); + return 1; + } + if (sizeof (memblock_t) != MEM_LINE_SIZE) { + fprintf (stderr, "memblock_t not cache size: %zd\n", + sizeof (memblock_t)); + return 1; + } + if ((size_t) super & (MEM_LINE_SIZE - 1)) { + fprintf (stderr, "super block not cache aligned: %p\n", super); + return 1; + } + if (super->page_size != (size_t) sysconf (_SC_PAGESIZE)) { + fprintf (stderr, "page size not equal to system page size: %zd, %zd\n", + super->page_size, sysconf (_SC_PAGESIZE)); + return 1; + } + if (!super->page_size || (super->page_size & (super->page_size - 1))) { + fprintf (stderr, "page size not power of two: %zd\n", + super->page_size); + return 1; + } + if (super->page_mask + 1 != super->page_size) { + fprintf (stderr, "page mask not page size - 1: %zx %zx\n", + super->page_mask, super->page_size); + return 1; + } + if (!super->page_mask || (super->page_mask & (super->page_mask + 1))) { + fprintf (stderr, "page mask not all 1s: %zx\n", + super->page_mask); + return 1; + } + if (super->memblocks) { + fprintf (stderr, "super block list not null\n"); + return 1; + } + if (!test_block (super)) { + fprintf (stderr, "block tests failed\n"); + } + if (super->memblocks) { + fprintf (stderr, "super block list not null 2\n"); + return 1; + } + if (!test_line (super)) { + fprintf (stderr, "line tests failed\n"); + return 1; + } + if (super->memblocks) { + fprintf (stderr, "super block list not null 2\n"); + return 1; + } + if (!test_block_line (super)) { + fprintf (stderr, "block-line tests failed\n"); + return 1; + } + for (size_t i = 0; i < 2 * super->page_size / MEM_LINE_SIZE; i++) { + void *line = cmemalloc (super, MEM_LINE_SIZE); + if (!line) { + fprintf (stderr, "could not allocate %d byte line\n", + MEM_LINE_SIZE); + return 1; + } + if ((size_t) line % MEM_LINE_SIZE) { + fprintf (stderr, "line not cache-line aligned: %p %d\n", + line, MEM_LINE_SIZE); + return 1; + } + if (!((size_t) line & super->page_mask)) { + fprintf (stderr, "line is page aligned: %p %zd\n", + line, super->page_size); + return 1; + } + } + if (!test_sline (super)) { + fprintf (stderr, "sub-line tests failed\n"); + return 1; + } + delete_memsuper (super); + return 0; +} From ab04a1915ed45646a7111b43371b451626ea6d2c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 21 Dec 2020 02:12:51 +0900 Subject: [PATCH 130/435] [build] Fix a pile of gcc 10 issues gcc got stricter about array accesses, complicating progs macros, and much better at detecting buffer overflows. --- include/QF/math/vector.h | 7 +- include/QF/pr_comp.h | 4 +- include/QF/progs.h | 14 ++-- libs/console/bi_inputline.c | 2 +- libs/gamecode/pr_debug.c | 8 +- libs/gamecode/pr_exec.c | 89 +++++++++++---------- libs/gamecode/pr_parse.c | 6 +- libs/models/alias/model_alias.c | 2 +- libs/ruamoko/rua_hash.c | 2 +- libs/ruamoko/rua_msgbuf.c | 5 +- libs/ruamoko/rua_obj.c | 2 +- libs/ruamoko/rua_plist.c | 2 +- libs/ruamoko/rua_qfile.c | 2 +- libs/ruamoko/rua_script.c | 2 +- libs/ruamoko/rua_set.c | 4 +- libs/util/zone.c | 3 +- libs/video/renderer/r_progs.c | 2 +- libs/video/renderer/vulkan/vkgen/vkstruct.r | 39 +++++---- nq/include/sv_progs.h | 2 +- qw/include/sv_progs.h | 2 +- qw/source/pmove.c | 2 +- qw/source/sv_progs.c | 4 +- ruamoko/qwaq/builtins/curses.c | 4 +- ruamoko/qwaq/builtins/debug.c | 2 +- ruamoko/qwaq/builtins/editbuffer.c | 2 +- ruamoko/qwaq/builtins/main.c | 1 + tools/qfbsp/source/outside.c | 2 + tools/qfcc/include/qfcc.h | 4 +- tools/qflight/include/noise.h | 2 +- tools/qfmodelgen/source/modelgen.c | 10 ++- 30 files changed, 125 insertions(+), 107 deletions(-) diff --git a/include/QF/math/vector.h b/include/QF/math/vector.h index 6a8b80809..993cbaf08 100644 --- a/include/QF/math/vector.h +++ b/include/QF/math/vector.h @@ -142,7 +142,12 @@ extern const vec_t *const vec3_origin; } while (0) #define VectorIsZero(a) (!(a)[0] && !(a)[1] && !(a)[2]) -#define VectorZero(a) ((a)[2] = (a)[1] = (a)[0] = 0); +#define VectorZero(a) \ + do { \ + (a)[0] = 0; \ + (a)[1] = 0; \ + (a)[2] = 0; \ + } while (0) #define VectorSet(a,b,c,d) \ do { \ (d)[0] = a; \ diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index a84e56953..0cd65d7e5 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -474,8 +474,8 @@ typedef union pr_type_u { string_t string_var; func_t func_var; pr_int_t entity_var; - float vector_var[0]; // really 3, but this structure must be 32 bits - float quat_var[0]; // really 4, but this structure must be 32 bits + float vector_var; // really [3], but this structure must be 32 bits + float quat_var; // really [4], but this structure must be 32 bits pr_int_t integer_var; pointer_t pointer_var; pr_uint_t uinteger_var; diff --git a/include/QF/progs.h b/include/QF/progs.h index 8a78926bf..64a9d20bb 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -445,7 +445,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define G_VECTOR(p,o) G_var (p, o, vector) +#define G_VECTOR(p,o) (&G_var (p, o, vector)) /** Access a quaternion global. Can be assigned to. @@ -457,7 +457,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define G_QUAT(p,o) G_var (p, o, quat) +#define G_QUAT(p,o) (&G_var (p, o, quat)) /** Access a string index global. Can be assigned to. @@ -661,7 +661,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define P_VECTOR(p,n) P_var (p, n, vector) +#define P_VECTOR(p,n) (&P_var (p, n, vector)) /** Access a quaterion parameter. Can be used any way a quat_t variable can. @@ -673,7 +673,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define P_QUAT(p,n) P_var (p, n, quat) +#define P_QUAT(p,n) (&P_var (p, n, quat)) /** Access a string index parameter. Can be assigned to. @@ -873,7 +873,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define R_VECTOR(p) R_var (p, vector) +#define R_VECTOR(p) (&R_var (p, vector)) /** Access the VM function return value as a \c ::quat_t quaternion. @@ -884,7 +884,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define R_QUAT(p) R_var (p, quat) +#define R_QUAT(p) (&R_var (p, quat)) /** Access the VM function return value as a ::string_t (a VM string reference). @@ -1054,7 +1054,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define E_VECTOR(e,o) E_var (e, o, vector) +#define E_VECTOR(e,o) (&E_var (e, o, vector)) /** Access a quaternion entity field. Can be used any way a quat_t variable can. diff --git a/libs/console/bi_inputline.c b/libs/console/bi_inputline.c index f48a4551e..7e4e743a2 100644 --- a/libs/console/bi_inputline.c +++ b/libs/console/bi_inputline.c @@ -83,7 +83,7 @@ il_data_get (il_resources_t *res, unsigned index) PR_RESGET (res->line_map, index); } -static inline int +static inline int __attribute__((pure)) il_data_index (il_resources_t *res, il_data_t *line) { PR_RESINDEX (res->line_map, line); diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 3d99da30a..d8105c5f6 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -1133,9 +1133,7 @@ pr_debug_vector_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "'%.9g %.9g %.9g'", - value->vector_var[0], value->vector_var[1], - value->vector_var[2]); + dasprintf (dstr, "'%.9g %.9g %.9g'", VectorExpand (&value->vector_var)); } static void @@ -1213,9 +1211,7 @@ pr_debug_quat_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "'%.9g %.9g %.9g %.9g'", - value->vector_var[0], value->vector_var[1], - value->vector_var[2], value->vector_var[3]); + dasprintf (dstr, "'%.9g %.9g %.9g %.9g'", QuatExpand (&value->quat_var)); } static void diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index 4a79f8173..9a9d03893 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -512,10 +512,10 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) OPC.float_var = OPA.float_var + OPB.float_var; break; case OP_ADD_V: - VectorAdd (OPA.vector_var, OPB.vector_var, OPC.vector_var); + VectorAdd (&OPA.vector_var, &OPB.vector_var, &OPC.vector_var); break; case OP_ADD_Q: - QuatAdd (OPA.quat_var, OPB.quat_var, OPC.quat_var); + QuatAdd (&OPA.quat_var, &OPB.quat_var, &OPC.quat_var); break; case OP_ADD_S: OPC.string_var = PR_CatStrings (pr, @@ -531,10 +531,11 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) OPC.float_var = OPA.float_var - OPB.float_var; break; case OP_SUB_V: - VectorSubtract (OPA.vector_var, OPB.vector_var, OPC.vector_var); + VectorSubtract (&OPA.vector_var, &OPB.vector_var, + &OPC.vector_var); break; case OP_SUB_Q: - QuatSubtract (OPA.quat_var, OPB.quat_var, OPC.quat_var); + QuatSubtract (&OPA.quat_var, &OPB.quat_var, &OPC.quat_var); break; case OP_MUL_D: OPC_double_var = OPA_double_var * OPB_double_var; @@ -543,14 +544,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) OPC.float_var = OPA.float_var * OPB.float_var; break; case OP_MUL_V: - OPC.float_var = DotProduct (OPA.vector_var, OPB.vector_var); + OPC.float_var = DotProduct (&OPA.vector_var, &OPB.vector_var); break; case OP_MUL_DV: { // avoid issues with the likes of x = x.x * x; // makes for faster code, too double scale = OPA_double_var; - VectorScale (OPB.vector_var, scale, OPC.vector_var); + VectorScale (&OPB.vector_var, scale, &OPC.vector_var); } break; case OP_MUL_VD: @@ -558,7 +559,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) // avoid issues with the likes of x = x * x.x; // makes for faster code, too double scale = OPB_double_var; - VectorScale (OPA.vector_var, scale, OPC.vector_var); + VectorScale (&OPA.vector_var, scale, &OPC.vector_var); } break; case OP_MUL_FV: @@ -566,7 +567,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) // avoid issues with the likes of x = x.x * x; // makes for faster code, too float scale = OPA.float_var; - VectorScale (OPB.vector_var, scale, OPC.vector_var); + VectorScale (&OPB.vector_var, scale, &OPC.vector_var); } break; case OP_MUL_VF: @@ -574,21 +575,21 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) // avoid issues with the likes of x = x * x.x; // makes for faster code, too float scale = OPB.float_var; - VectorScale (OPA.vector_var, scale, OPC.vector_var); + VectorScale (&OPA.vector_var, scale, &OPC.vector_var); } break; case OP_MUL_Q: - QuatMult (OPA.quat_var, OPB.quat_var, OPC.quat_var); + QuatMult (&OPA.quat_var, &OPB.quat_var, &OPC.quat_var); break; case OP_MUL_QV: - QuatMultVec (OPA.quat_var, OPB.vector_var, OPC.vector_var); + QuatMultVec (&OPA.quat_var, &OPB.vector_var, &OPC.vector_var); break; case OP_MUL_DQ: { // avoid issues with the likes of x = x.s * x; // makes for faster code, too double scale = OPA_double_var; - QuatScale (OPB.quat_var, scale, OPC.quat_var); + QuatScale (&OPB.quat_var, scale, &OPC.quat_var); } break; case OP_MUL_QD: @@ -596,7 +597,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) // avoid issues with the likes of x = x * x.s; // makes for faster code, too double scale = OPB_double_var; - QuatScale (OPA.quat_var, scale, OPC.quat_var); + QuatScale (&OPA.quat_var, scale, &OPC.quat_var); } break; case OP_MUL_FQ: @@ -604,7 +605,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) // avoid issues with the likes of x = x.s * x; // makes for faster code, too float scale = OPA.float_var; - QuatScale (OPB.quat_var, scale, OPC.quat_var); + QuatScale (&OPB.quat_var, scale, &OPC.quat_var); } break; case OP_MUL_QF: @@ -612,11 +613,11 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) // avoid issues with the likes of x = x * x.s; // makes for faster code, too float scale = OPB.float_var; - QuatScale (OPA.quat_var, scale, OPC.quat_var); + QuatScale (&OPA.quat_var, scale, &OPC.quat_var); } break; case OP_CONJ_Q: - QuatConj (OPA.quat_var, OPC.quat_var); + QuatConj (&OPA.quat_var, &OPC.quat_var); break; case OP_DIV_D: OPC_double_var = OPA_double_var / OPB_double_var; @@ -673,10 +674,10 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) OPC.integer_var = !FNZ (OPA); break; case OP_NOT_V: - OPC.integer_var = VectorIsZero (OPA.vector_var); + OPC.integer_var = VectorIsZero (&OPA.vector_var); break; case OP_NOT_Q: - OPC.integer_var = QuatIsZero (OPA.quat_var); + OPC.integer_var = QuatIsZero (&OPA.quat_var); break; case OP_NOT_S: OPC.integer_var = !OPA.string_var || @@ -692,11 +693,11 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) OPC.integer_var = OPA.float_var == OPB.float_var; break; case OP_EQ_V: - OPC.integer_var = VectorCompare (OPA.vector_var, - OPB.vector_var); + OPC.integer_var = VectorCompare (&OPA.vector_var, + &OPB.vector_var); break; case OP_EQ_Q: - OPC.integer_var = QuatCompare (OPA.quat_var, OPB.quat_var); + OPC.integer_var = QuatCompare (&OPA.quat_var, &OPB.quat_var); break; case OP_EQ_E: OPC.integer_var = OPA.integer_var == OPB.integer_var; @@ -708,11 +709,11 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) OPC.integer_var = OPA.float_var != OPB.float_var; break; case OP_NE_V: - OPC.integer_var = !VectorCompare (OPA.vector_var, - OPB.vector_var); + OPC.integer_var = !VectorCompare (&OPA.vector_var, + &OPB.vector_var); break; case OP_NE_Q: - OPC.integer_var = !QuatCompare (OPA.quat_var, OPB.quat_var); + OPC.integer_var = !QuatCompare (&OPA.quat_var, &OPB.quat_var); break; case OP_LE_S: case OP_GE_S: @@ -753,10 +754,10 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) OPB.integer_var = OPA.integer_var; break; case OP_STORE_V: - VectorCopy (OPA.vector_var, OPB.vector_var); + VectorCopy (&OPA.vector_var, &OPB.vector_var); break; case OP_STORE_Q: - QuatCopy (OPA.quat_var, OPB.quat_var); + QuatCopy (&OPA.quat_var, &OPB.quat_var); break; case OP_STORE_D: OPB_double_var = OPA_double_var; @@ -782,7 +783,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (OPA.vector_var, ptr->vector_var); + VectorCopy (&OPA.vector_var, &ptr->vector_var); break; case OP_STOREP_Q: pointer = OPB.integer_var; @@ -790,7 +791,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; - QuatCopy (OPA.quat_var, ptr->quat_var); + QuatCopy (&OPA.quat_var, &ptr->quat_var); break; case OP_STOREP_D: pointer = OPB.integer_var; @@ -909,7 +910,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (ptr->vector_var, OPC.vector_var); + VectorCopy (&ptr->vector_var, &OPC.vector_var); break; case OP_LOADB_Q: pointer = OPA.integer_var + OPB.integer_var; @@ -917,7 +918,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; - QuatCopy (ptr->quat_var, OPC.quat_var); + QuatCopy (&ptr->quat_var, &OPC.quat_var); break; case OP_LOADB_D: pointer = OPA.integer_var + OPB.integer_var; @@ -948,7 +949,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (ptr->vector_var, OPC.vector_var); + VectorCopy (&ptr->vector_var, &OPC.vector_var); break; case OP_LOADBI_Q: pointer = OPA.integer_var + (short) st->b; @@ -956,7 +957,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; - QuatCopy (ptr->quat_var, OPC.quat_var); + QuatCopy (&ptr->quat_var, &OPC.quat_var); break; case OP_LOADBI_D: pointer = OPA.integer_var + (short) st->b; @@ -997,7 +998,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (OPA.vector_var, ptr->vector_var); + VectorCopy (&OPA.vector_var, &ptr->vector_var); break; case OP_STOREB_Q: pointer = OPB.integer_var + OPC.integer_var; @@ -1005,7 +1006,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; - QuatCopy (OPA.quat_var, ptr->quat_var); + QuatCopy (&OPA.quat_var, &ptr->quat_var); break; case OP_STOREB_D: pointer = OPB.integer_var + OPC.integer_var; @@ -1036,7 +1037,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_vector); } ptr = pr->pr_globals + pointer; - VectorCopy (OPA.vector_var, ptr->vector_var); + VectorCopy (&OPA.vector_var, &ptr->vector_var); break; case OP_STOREBI_Q: pointer = OPB.integer_var + (short) st->c; @@ -1044,7 +1045,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } ptr = pr->pr_globals + pointer; - QuatCopy (OPA.quat_var, ptr->quat_var); + QuatCopy (&OPA.quat_var, &ptr->quat_var); break; case OP_STOREBI_D: pointer = OPB.integer_var + (short) st->c; @@ -1131,7 +1132,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_integer); } - VectorCopy (ptr->vector_var, stk->vector_var); + VectorCopy (&ptr->vector_var, &stk->vector_var); *pr->globals.stack = stack; } break; @@ -1148,7 +1149,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } - QuatCopy (ptr->quat_var, stk->quat_var); + QuatCopy (&ptr->quat_var, &stk->quat_var); *pr->globals.stack = stack; } break; @@ -1189,7 +1190,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_integer); } - VectorCopy (ptr->vector_var, stk->vector_var); + VectorCopy (&ptr->vector_var, &stk->vector_var); *pr->globals.stack = stack; } break; @@ -1206,7 +1207,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } - QuatCopy (ptr->quat_var, stk->quat_var); + QuatCopy (&ptr->quat_var, &stk->quat_var); *pr->globals.stack = stack; } break; @@ -1287,7 +1288,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_integer); } - VectorCopy (ptr->vector_var, stk->vector_var); + VectorCopy (&ptr->vector_var, &stk->vector_var); *pr->globals.stack = stack + 3; } break; @@ -1304,7 +1305,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } - QuatCopy (ptr->quat_var, stk->quat_var); + QuatCopy (&ptr->quat_var, &stk->quat_var); *pr->globals.stack = stack + 4; } break; @@ -1345,7 +1346,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_integer); } - VectorCopy (ptr->vector_var, stk->vector_var); + VectorCopy (&ptr->vector_var, &stk->vector_var); *pr->globals.stack = stack + 3; } break; @@ -1362,7 +1363,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) PR_BoundsCheck (pr, pointer, ev_quat); } - QuatCopy (ptr->quat_var, stk->quat_var); + QuatCopy (&ptr->quat_var, &stk->quat_var); *pr->globals.stack = stack + 4; } break; diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index 2652694e8..6471a44bb 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -92,10 +92,10 @@ PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val, dstring_t *line) dsprintf (line, "%d", val->integer_var); break; case ev_vector: - dsprintf (line, "%.9g %.9g %.9g", VectorExpand (val->vector_var)); + dsprintf (line, "%.9g %.9g %.9g", VectorExpand (&val->vector_var)); break; case ev_quat: - dsprintf (line, "%.9g %.9g %.9g %.9g", QuatExpand (val->quat_var)); + dsprintf (line, "%.9g %.9g %.9g %.9g", QuatExpand (&val->quat_var)); break; default: dsprintf (line, "bad type %i", type); @@ -241,7 +241,7 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s) while (*v && *v != ' ') v++; *v = 0; - d->vector_var[i] = atof (w); + (&d->vector_var)[i] = atof (w); w = v = v + 1; } free (string); diff --git a/libs/models/alias/model_alias.c b/libs/models/alias/model_alias.c index af2731d71..8a4784b2d 100644 --- a/libs/models/alias/model_alias.c +++ b/libs/models/alias/model_alias.c @@ -138,7 +138,7 @@ Mod_LoadAliasFrame (void *pin, int *posenum, maliasframedesc_t *frame, pdaliasframe = (daliasframe_t *) pin; - strncpy (frame->name, pdaliasframe->name, sizeof (frame->name)); + memcpy (frame->name, pdaliasframe->name, sizeof (frame->name)); frame->name[sizeof (frame->name) - 1] = 0; frame->firstpose = (*posenum); frame->numposes = 1; diff --git a/libs/ruamoko/rua_hash.c b/libs/ruamoko/rua_hash.c index cff92eb4e..98d9722ba 100644 --- a/libs/ruamoko/rua_hash.c +++ b/libs/ruamoko/rua_hash.c @@ -85,7 +85,7 @@ table_get (hash_resources_t *res, int index) PR_RESGET(res->table_map, index); } -static inline int +static inline int __attribute__((pure)) table_index (hash_resources_t *res, bi_hashtab_t *table) { PR_RESINDEX(res->table_map, table); diff --git a/libs/ruamoko/rua_msgbuf.c b/libs/ruamoko/rua_msgbuf.c index 9b026c90f..51c7bcf16 100644 --- a/libs/ruamoko/rua_msgbuf.c +++ b/libs/ruamoko/rua_msgbuf.c @@ -80,7 +80,7 @@ msgbuf_get (msgbuf_resources_t *res, int index) PR_RESGET(res->msgbuf_map, index); } -static inline int +static inline int __attribute__((pure)) msgbuf_index (msgbuf_resources_t *res, msgbuf_t *msgbuf) { PR_RESINDEX(res->msgbuf_map, msgbuf); @@ -358,8 +358,7 @@ static void bi_MsgBuf_ReadCoordAngleV (progs_t *pr) { msgbuf_t *mb = get_msgbuf (pr, __FUNCTION__, P_INT (pr, 0)); - MSG_ReadCoordAngleV (&mb->msg, P_GPOINTER (pr, 1)->vector_var, - P_GPOINTER (pr, 2)->vector_var); + MSG_ReadCoordAngleV (&mb->msg, P_VECTOR (pr, 1), P_VECTOR (pr, 2)); } static void diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index baa8fe73b..155124b9f 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -108,7 +108,7 @@ dtable_get (probj_t *probj, int index) PR_RESGET (probj->dtables, index); } -static inline int +static inline int __attribute__((pure)) dtable_index (probj_t *probj, dtable_t *dtable) { PR_RESINDEX (probj->dtables, dtable); diff --git a/libs/ruamoko/rua_plist.c b/libs/ruamoko/rua_plist.c index 9732b75c3..b71af2ead 100644 --- a/libs/ruamoko/rua_plist.c +++ b/libs/ruamoko/rua_plist.c @@ -84,7 +84,7 @@ plist_get (plist_resources_t *res, unsigned index) PR_RESGET(res->plist_map, index); } -static inline int +static inline int __attribute__((pure)) plist_index (plist_resources_t *res, bi_plist_t *plist) { PR_RESINDEX(res->plist_map, plist); diff --git a/libs/ruamoko/rua_qfile.c b/libs/ruamoko/rua_qfile.c index d96c433a2..2f625a949 100644 --- a/libs/ruamoko/rua_qfile.c +++ b/libs/ruamoko/rua_qfile.c @@ -77,7 +77,7 @@ handle_get (qfile_resources_t *res, int index) PR_RESGET(res->handle_map, index); } -static inline int +static inline int __attribute__((pure)) handle_index (qfile_resources_t *res, qfile_t *handle) { PR_RESINDEX(res->handle_map, handle); diff --git a/libs/ruamoko/rua_script.c b/libs/ruamoko/rua_script.c index ff5b2ab0a..7c2cd6666 100644 --- a/libs/ruamoko/rua_script.c +++ b/libs/ruamoko/rua_script.c @@ -78,7 +78,7 @@ script_get (script_resources_t *res, int index) PR_RESGET(res->scripts, index); } -static inline int +static inline int __attribute__((pure)) script_index (script_resources_t *res, rua_script_t *script) { PR_RESINDEX(res->scripts, script); diff --git a/libs/ruamoko/rua_set.c b/libs/ruamoko/rua_set.c index 0fdd964e7..4e3ea732d 100644 --- a/libs/ruamoko/rua_set.c +++ b/libs/ruamoko/rua_set.c @@ -98,7 +98,7 @@ res_set_get (set_resources_t *res, int index) PR_RESGET(res->set_map, index); } -static inline int +static inline int __attribute__((pure)) res_set_index (set_resources_t *res, bi_set_t *set) { PR_RESINDEX(res->set_map, set); @@ -128,7 +128,7 @@ res_set_iter_get (set_resources_t *res, int index) PR_RESGET(res->set_iter_map, index); } -static inline int +static inline int __attribute__((pure)) res_set_iter_index (set_resources_t *res, bi_set_iter_t *set_iter) { PR_RESINDEX(res->set_iter_map, set_iter); diff --git a/libs/util/zone.c b/libs/util/zone.c index 40af412ba..f52226d55 100644 --- a/libs/util/zone.c +++ b/libs/util/zone.c @@ -577,7 +577,8 @@ Hunk_AllocName (int size, const char *name) h->size = size; h->sentinal = HUNK_SENTINAL; - strncpy (h->name, name, 8); + memcpy (h->name, name, 8); + h->name[7] = 0; return (void *) (h + 1); } diff --git a/libs/video/renderer/r_progs.c b/libs/video/renderer/r_progs.c index aba1de6ea..3f2925fba 100644 --- a/libs/video/renderer/r_progs.c +++ b/libs/video/renderer/r_progs.c @@ -101,7 +101,7 @@ qpic_get (draw_resources_t *res, int index) PR_RESGET (res->qpic_map, index); } -static inline int +static inline int __attribute__((pure)) qpic_index (draw_resources_t *res, qpic_res_t *qp) { PR_RESINDEX (res->qpic_map, qp); diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index dc6aa39d6..b1bf22960 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -48,9 +48,15 @@ -(void) writeTable: (PLItem *) parse { - PLItem *field_dict = [parse getObjectForKey:[self name]]; + string name = [self name]; + PLItem *field_dict = [parse getObjectForKey:name]; PLItem *field_defs = [field_dict allKeys]; Type *field_type; + PLItem *new_name = [field_dict getObjectForKey:".name"]; + + if (new_name) { + name = [new_name string]; + } if (field_defs) { PLItem *field_def; @@ -65,7 +71,7 @@ string size_field = nil; string value_field = nil; - if (!type_desc) { + if (!type_desc || str_mid(field_name, 0, 1) == ".") { continue; } type_record = [[type_desc getObjectAtIndex:0] string]; @@ -73,22 +79,22 @@ field_type = [[Type lookup: type_type] dereference]; fprintf (output_file, "static parse_%s_t parse_%s_%s_data = {\n", - type_record, [self name], field_name); + type_record, name, field_name); fprintf (output_file, "\t%s,\n", [field_type parseType]); fprintf (output_file, "\tsizeof (%s),\n", type_type); fprintf (output_file, "\tparse_%s,\n", type_type); if (type_record == "single") { value_field = [[field_def getObjectForKey:"value"] string]; fprintf (output_file, "\tfield_offset (%s, %s),\n", - [self name], value_field); + name, value_field); } else { value_field = [[field_def getObjectForKey:"values"] string]; size_field = [[field_def getObjectForKey:"size"] string]; fprintf (output_file, "\tfield_offset (%s, %s),\n", - [self name], value_field); + name, value_field); if (size_field) { fprintf (output_file, "\tfield_offset (%s, %s),\n", - [self name], size_field); + name, size_field); } else { fprintf (output_file, "\t-1,\n"); } @@ -96,13 +102,16 @@ fprintf (output_file, "};\n"); } } - fprintf (output_file, "static plfield_t %s_fields[] = {\n", [self name]); + fprintf (output_file, "static plfield_t %s_fields[] = {\n", name); if (field_defs) { PLItem *field_def; qfot_var_t *field; for (int i = [field_defs count]; i-- > 0; ) { string field_name = [[field_defs getObjectAtIndex:i] string]; + if (str_mid(field_name, 0, 1) == ".") { + continue; + } field_def = [field_dict getObjectForKey:field_name]; if ([field_def string] == "auto") { field = [self findField:field_name]; @@ -112,7 +121,7 @@ field_type = [Type findType: field.type]; fprintf (output_file, "\t{\"%s\", field_offset (%s, %s), %s, %s, %s},\n", - field_name, [self name], field_name, + field_name, name, field_name, [field_type parseType], [field_type parseFunc], [field_type parseData]); } else { @@ -133,7 +142,7 @@ fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", field_name, parseType, type_record, - [self name], field_name); + name, field_name); } } } else { @@ -145,7 +154,7 @@ field_type = [Type findType: field.type]; fprintf (output_file, "\t{\"%s\", field_offset (%s, %s), %s, %s, %s},\n", - field.name, [self name], field.name, + field.name, name, field.name, [field_type parseType], [field_type parseFunc], [field_type parseData]); } @@ -154,12 +163,14 @@ fprintf (output_file, "};\n"); fprintf (output_file, "static int parse_%s (const plfield_t *field," - " const plitem_t *item, void *data, plitem_t *messages)\n", - [self name]); + " const plitem_t *item, void *data, plitem_t *messages," + " void *context)\n", + name); fprintf (output_file, "{\n"); fprintf (output_file, - "\treturn PL_ParseDictionary (%s_fields, item, data, messages);\n", - [self name]); + "\treturn PL_ParseDictionary (%s_fields, item, data, messages," + " context);\n", + name); fprintf (output_file, "}\n"); } diff --git a/nq/include/sv_progs.h b/nq/include/sv_progs.h index 07a8c8f7c..3d798ac16 100644 --- a/nq/include/sv_progs.h +++ b/nq/include/sv_progs.h @@ -208,7 +208,7 @@ extern progs_t sv_pr_state; #define SVstring(e,f) SVFIELD (e, f, string) #define SVfunc(e,f) SVFIELD (e, f, func) #define SVentity(e,f) SVFIELD (e, f, entity) -#define SVvector(e,f) SVFIELD (e, f, vector) +#define SVvector(e,f) (&SVFIELD (e, f, vector)) #define SVinteger(e,f) SVFIELD (e, f, integer) #if TYPECHECK_PROGS #define SVdouble(e,f) E_DOUBLE (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__)) diff --git a/qw/include/sv_progs.h b/qw/include/sv_progs.h index 18bdde503..88fe18c24 100644 --- a/qw/include/sv_progs.h +++ b/qw/include/sv_progs.h @@ -193,7 +193,7 @@ extern progs_t sv_pr_state; #define SVstring(e,f) SVFIELD (e, f, string) #define SVfunc(e,f) SVFIELD (e, f, func) #define SVentity(e,f) SVFIELD (e, f, entity) -#define SVvector(e,f) SVFIELD (e, f, vector) +#define SVvector(e,f) (&SVFIELD (e, f, vector)) #define SVinteger(e,f) SVFIELD (e, f, integer) #if TYPECHECK_PROGS #define SVdouble(e,f) E_DOUBLE (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__)) diff --git a/qw/source/pmove.c b/qw/source/pmove.c index 637528afa..358409bc5 100644 --- a/qw/source/pmove.c +++ b/qw/source/pmove.c @@ -738,7 +738,7 @@ SpectatorMove (void) // friction speed = DotProduct (pmove.velocity, pmove.velocity); if (speed < 1) { - VectorZero (pmove.velocity) + VectorZero (pmove.velocity); } else { speed = sqrt (speed); drop = 0; diff --git a/qw/source/sv_progs.c b/qw/source/sv_progs.c index 276ee2875..7ef651a15 100644 --- a/qw/source/sv_progs.c +++ b/qw/source/sv_progs.c @@ -101,8 +101,8 @@ free_edict (progs_t *pr, edict_t *ent) ent->v[sv_fields.frame].float_var = 0; ent->v[sv_fields.nextthink].float_var = -1; ent->v[sv_fields.solid].float_var = 0; - memset (ent->v[sv_fields.origin].vector_var, 0, 3*sizeof (float)); - memset (ent->v[sv_fields.angles].vector_var, 0, 3*sizeof (float)); + memset (&ent->v[sv_fields.origin].vector_var, 0, 3*sizeof (float)); + memset (&ent->v[sv_fields.angles].vector_var, 0, 3*sizeof (float)); } else { ED_ClearEdict (pr, ent, 0); } diff --git a/ruamoko/qwaq/builtins/curses.c b/ruamoko/qwaq/builtins/curses.c index 8f543f493..4f2044cf7 100644 --- a/ruamoko/qwaq/builtins/curses.c +++ b/ruamoko/qwaq/builtins/curses.c @@ -148,7 +148,7 @@ window_get (qwaq_resources_t *res, unsigned index) PR_RESGET(res->window_map, index); } -static inline int +static inline int __attribute__((pure)) window_index (qwaq_resources_t *res, window_t *win) { PR_RESINDEX (res->window_map, win); @@ -194,7 +194,7 @@ panel_get (qwaq_resources_t *res, unsigned index) PR_RESGET(res->panel_map, index); } -static inline int +static inline int __attribute__((pure)) panel_index (qwaq_resources_t *res, panel_t *win) { PR_RESINDEX (res->panel_map, win); diff --git a/ruamoko/qwaq/builtins/debug.c b/ruamoko/qwaq/builtins/debug.c index d16ac6f97..19b215e38 100644 --- a/ruamoko/qwaq/builtins/debug.c +++ b/ruamoko/qwaq/builtins/debug.c @@ -94,7 +94,7 @@ target_get (qwaq_debug_t *debug, unsigned index) PR_RESGET (debug->targets, index); } -static inline int +static inline int __attribute__((pure)) target_index (qwaq_debug_t *debug, qwaq_target_t *target) { PR_RESINDEX (debug->targets, target); diff --git a/ruamoko/qwaq/builtins/editbuffer.c b/ruamoko/qwaq/builtins/editbuffer.c index 12cde52ab..d687103d3 100644 --- a/ruamoko/qwaq/builtins/editbuffer.c +++ b/ruamoko/qwaq/builtins/editbuffer.c @@ -52,7 +52,7 @@ editbuffer_get (qwaq_ebresources_t *res, unsigned index) PR_RESGET (res->buffers, index); } -static inline int +static inline int __attribute__((pure)) editbuffer_index (qwaq_ebresources_t *res, editbuffer_t *buffer) { PR_RESINDEX (res->buffers, buffer); diff --git a/ruamoko/qwaq/builtins/main.c b/ruamoko/qwaq/builtins/main.c index 0a4faf28b..f493e8528 100644 --- a/ruamoko/qwaq/builtins/main.c +++ b/ruamoko/qwaq/builtins/main.c @@ -86,6 +86,7 @@ open_file (const char *path, int *len) if (!file) { strerror_r(errno, errbuff, sizeof (errbuff)); Sys_Printf ("%s\n", errbuff); + *len = 0; return 0; } *len = Qfilesize (file); diff --git a/tools/qfbsp/source/outside.c b/tools/qfbsp/source/outside.c index 15da18dba..d7ba0d142 100644 --- a/tools/qfbsp/source/outside.c +++ b/tools/qfbsp/source/outside.c @@ -180,6 +180,8 @@ MarkLeakTrail2 (void) vec3_t wc, pwc; const vec_t *v; + VectorZero (wc); + leakfile = fopen (options.pointfile, "w"); if (!leakfile) Sys_Error ("Couldn't open %s\n", options.pointfile); diff --git a/tools/qfcc/include/qfcc.h b/tools/qfcc/include/qfcc.h index 6fac011ce..9d552ab3e 100644 --- a/tools/qfcc/include/qfcc.h +++ b/tools/qfcc/include/qfcc.h @@ -101,8 +101,8 @@ extern pr_info_t pr; #define D_DOUBLE(d) (*(double *) ((d)->space->data + (d)->offset)) #define D_FLOAT(d) D_var (float, d) #define D_INT(d) D_var (integer, d) -#define D_VECTOR(d) D_var (vector, d) -#define D_QUAT(d) D_var (quat, d) +#define D_VECTOR(d) (&D_var (vector, d)) +#define D_QUAT(d) (&D_var (quat, d)) #define D_STRING(d) D_var (string, d) #define D_GETSTR(d) GETSTR (D_STRING (d)) #define D_FUNCTION(d) D_var (func, d) diff --git a/tools/qflight/include/noise.h b/tools/qflight/include/noise.h index be63d9de1..0b118d17a 100644 --- a/tools/qflight/include/noise.h +++ b/tools/qflight/include/noise.h @@ -34,7 +34,7 @@ ///@{ float noise3d (vec3_t v, int num) __attribute__((pure)); -float noiseXYZ (float x, float y, float z, int num) __attribute__((pure)); +float noiseXYZ (float x, float y, float z, int num) __attribute__((const)); float noise_scaled (vec3_t v, float s, int num) __attribute__((pure)); float noise_perlin (vec3_t v, float p, int num) __attribute__((pure)); void snap_vector (vec3_t v_old, vec3_t v_new, float scale); diff --git a/tools/qfmodelgen/source/modelgen.c b/tools/qfmodelgen/source/modelgen.c index 5d3eee4d0..a4b18b1ac 100644 --- a/tools/qfmodelgen/source/modelgen.c +++ b/tools/qfmodelgen/source/modelgen.c @@ -178,15 +178,17 @@ SetQdirFromPath (char *path) static const char * ExpandPath (const char *path) { - static char full[1024]; + static dstring_t *full; - //FIXME buffer overflow central + if (!full) { + full = dstring_new(); + } //if (!qdir) // Sys_Error ("ExpandPath called without qdir set"); if (path[0] == '/' || path[0] == '\\' || path[1] == ':') return path; - sprintf (full, "%s%s", qdir, path); - return full; + dsprintf (full, "%s%s", qdir, path); + return full->str; } static void From ebcef5c8a46b7d199df88ac9d4f3f1ae5b5b6cbd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 21 Dec 2020 02:32:29 +0900 Subject: [PATCH 131/435] [util] Deal with gcc optimizing out isnan checks This occurs because of -ffast-math, but I need to investigate how much of an impact disabling it has on QF's performance. --- libs/util/test/test-quat.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/libs/util/test/test-quat.c b/libs/util/test/test-quat.c index 11cc5b617..8e4738449 100644 --- a/libs/util/test/test-quat.c +++ b/libs/util/test/test-quat.c @@ -239,11 +239,16 @@ fail: return 0; } +// XXX FIXME see usage in test_rotation4. need to investigate whether +// -ffast-math is any real benefit +#define ISNAN(x) (((x) & 0x7f800000) == 0x7f800000 && ((x) & 0x7fffff)) + static int test_rotation4 (const vec3_t a, const vec3_t b, const quat_t expect) { int i; - quat_t quat; + union { int x[4]; vec_t q[4]; } q; + vec_t *quat = q.q; vec3_t t; vec_t d = 0; @@ -258,13 +263,19 @@ test_rotation4 (const vec3_t a, const vec3_t b, const quat_t expect) } // expect NaN for the vector components because the vectors are // anti-parallel and thus the rotation axis is undefined - if (!(isnan(quat[0]) && isnan(quat[1]) && isnan(quat[2]))) { + //XXX FIXME(?) still using -ffast-math which implies + // -ffinite-math-only which in turn disables nan/inf checks, so have + // to do it by hand + // if (!(isnan(quat[0]) && isnan(quat[1]) && isnan(quat[2]))) { + if (!(ISNAN(q.x[0]) && ISNAN(q.x[1]) && ISNAN(q.x[2]))) { goto fail; } } else { // the vectors are not anti-parallel and thus the rotation axis is // defined, so NaN is invalid - if (isnan(quat[0]) || isnan(quat[1]) || isnan(quat[2])) { + // XXX FIXME see above + //if (isnan(quat[0]) || isnan(quat[1]) || isnan(quat[2])) { + if (ISNAN(q.x[0]) || ISNAN(q.x[1]) || ISNAN(q.x[2])) { goto fail; } for (i = 0; i < 4; i++) { @@ -288,6 +299,7 @@ fail: printf ("%11.9g %11.9g %11.9g\n", VectorExpand(a)); printf ("%11.9g %11.9g %11.9g\n", VectorExpand(b)); printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand(quat)); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand(expect)); printf ("%11.9g %11.9g %11.9g\n", VectorExpand(t)); printf ("%11.9g\n", d); return 0; From 591667c36dbcd71f31269ed78285ced5a191c549 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 21 Dec 2020 13:55:54 +0900 Subject: [PATCH 132/435] [util] Add a context parameter to the plist parsers Not used by the dict/array parsers themselves, but is passed on to any value parser callbacks for their own use. --- include/QF/qfplist.h | 9 ++++++--- libs/util/qfplist.c | 10 +++++----- libs/video/renderer/vulkan/vkparse.c | 16 ++++++++-------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 3fdfa7825..70a1b8302 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -80,12 +80,14 @@ struct plfield_s; error messages. Messages should be strings, but no checking is done: it is up to the top-level caller to parse out the messages. + \param context Additional context data passed to the parser. \return 0 for error, 1 for success. See \a PL_ParseDictionary. */ typedef int (*plparser_t) (const struct plfield_s *field, const struct plitem_s *item, void *data, - struct plitem_s *messages); + struct plitem_s *messages, + void *context); /** A field to be parsed from a dictionary item. @@ -320,12 +322,13 @@ void PL_Free (plitem_t *item); message format is "[line number]: [message]". If the line number is 0, then the actual line is unknown (due to the source item not being parsed from a file or string). + \param context Additional context data passed to the parser. \return 0 if there are any errors, 1 if there are no errors. */ int PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, - void *data, plitem_t *messages); + void *data, plitem_t *messages, void *context); int PL_ParseArray (const plfield_t *fields, const plitem_t *dict, - void *data, plitem_t *messages); + void *data, plitem_t *messages, void *context); void __attribute__((format(printf,3,4))) PL_Message (plitem_t *messages, const plitem_t *item, const char *fmt, ...); diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 8eb7e867c..2f71d42bc 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1086,7 +1086,7 @@ PL_Message (plitem_t *messages, const plitem_t *item, const char *fmt, ...) static int pl_default_parser (const plfield_t *field, const plitem_t *item, void *data, - plitem_t *messages) + plitem_t *messages, void *context) { switch (field->type) { case QFDictionary: @@ -1125,7 +1125,7 @@ pl_default_parser (const plfield_t *field, const plitem_t *item, void *data, VISIBLE int PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, - plitem_t *messages) + plitem_t *messages, void *context) { void **list, **l; dictkey_t *current; @@ -1161,7 +1161,7 @@ PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, pl_types[item->type]); result = 0; } else { - if (!parser (f, item, flddata, messages)) { + if (!parser (f, item, flddata, messages, context)) { result = 0; } } @@ -1180,7 +1180,7 @@ PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, VISIBLE int PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, - plitem_t *messages) + plitem_t *messages, void *context) { int result = 1; plparser_t parser; @@ -1219,7 +1219,7 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, pl_types[item->type]); result = 0; } else { - if (!parser (&f, item, eledata, messages)) { + if (!parser (&f, item, eledata, messages, context)) { result = 0; } } diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 7fb137b29..a4b037202 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -97,7 +97,7 @@ static int find_enum (const char *valstr, enumval_t *enumval, int *val) } static int parse_uint32_t (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages) + void *data, plitem_t *messages, void *ctx) { int ret = 1; const char *valstr = PL_String (item); @@ -125,7 +125,7 @@ static int parse_uint32_t (const plfield_t *field, const plitem_t *item, } static int parse_enum (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages) + void *data, plitem_t *messages, void *ctx) { int ret = 1; int val; @@ -144,7 +144,7 @@ static int parse_enum (const plfield_t *field, const plitem_t *item, } static int parse_flags (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages) + void *data, plitem_t *messages, void *ctx) { int ret = 1; int val; @@ -165,7 +165,7 @@ static int parse_flags (const plfield_t *field, const plitem_t *item, } static int parse_single (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages) + void *data, plitem_t *messages, void *ctx) { __auto_type single = (parse_single_t *) field->data; void *flddata = (byte *)data + single->value_offset; @@ -180,7 +180,7 @@ static int parse_single (const plfield_t *field, const plitem_t *item, plfield_t f = { 0, 0, single->type, single->parser, 0 }; void *value = calloc (1, single->stride); - if (!single->parser (&f, item, value, messages)) { + if (!single->parser (&f, item, value, messages, ctx)) { free (value); return 0; } @@ -190,7 +190,7 @@ static int parse_single (const plfield_t *field, const plitem_t *item, } static int parse_array (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages) + void *data, plitem_t *messages, void *ctx) { __auto_type array = (parse_array_t *) field->data; __auto_type value = (void **) ((byte *)data + array->value_offset); @@ -213,7 +213,7 @@ static int parse_array (const plfield_t *field, const plitem_t *item, // field->data, data); //Sys_Printf (" %d %zd %p %zd %zd\n", array->type, array->stride, // array->parser, array->value_offset, array->size_offset); - if (!PL_ParseArray (&f, item, &arr, messages)) { + if (!PL_ParseArray (&f, item, &arr, messages, ctx)) { return 0; } *value = malloc (array->stride * arr->size); @@ -275,7 +275,7 @@ QFV_ParseRenderPass (qfv_device_t *device, plitem_t *plist) VkRenderPass renderpass; if (!PL_ParseDictionary (renderpass_fields, plist, - &renderpass_data, messages)) { + &renderpass_data, messages, 0)) { for (int i = 0; i < PL_A_NumObjects (messages); i++) { Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); } From f3682638d4757b7b34a5c005a16110a2c9aabfb5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 21 Dec 2020 14:06:21 +0900 Subject: [PATCH 133/435] [util] Add a mini expression parser It is capable of parsing single expressions with fairly simple operations. It current supports ints, enums, cvars and (external) data structs. It is also thread-safe (in theory, needs proper testing) and the memory it uses can be mass-freed. --- include/QF/cexpr.h | 118 +++++++++++++ libs/util/Makemodule.am | 13 ++ libs/util/cexpr-lex.l | 281 +++++++++++++++++++++++++++++++ libs/util/cexpr-parse.y | 219 ++++++++++++++++++++++++ libs/util/cexpr-type.c | 314 +++++++++++++++++++++++++++++++++++ libs/util/cexpr-vars.c | 154 +++++++++++++++++ libs/util/test/Makemodule.am | 5 + libs/util/test/test-cexpr.c | 81 +++++++++ 8 files changed, 1185 insertions(+) create mode 100644 include/QF/cexpr.h create mode 100644 libs/util/cexpr-lex.l create mode 100644 libs/util/cexpr-parse.y create mode 100644 libs/util/cexpr-type.c create mode 100644 libs/util/cexpr-vars.c create mode 100644 libs/util/test/test-cexpr.c diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h new file mode 100644 index 000000000..fcdeaad57 --- /dev/null +++ b/include/QF/cexpr.h @@ -0,0 +1,118 @@ +/* + cexpr.h + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __expr_h +#define __expr_h + +#include + +struct exprval_s; +struct exprctx_s; + +typedef struct binop_s { + int op; + struct exprtype_s *other; + struct exprtype_s *result; + void (*func) (const struct exprval_s *val1, + const struct exprval_s *val2, + struct exprval_s *result, + struct exprctx_s *context); +} binop_t; + +typedef struct unop_s { + int op; + struct exprtype_s *result; + void (*func) (const struct exprval_s *val, struct exprval_s *result, + struct exprctx_s *context); +} unop_t; + +typedef struct exprtype_s { + const char *name; + size_t size; + binop_t *binops; + unop_t *unops; + void *data; +} exprtype_t; + +typedef struct exprval_s { + exprtype_t *type; + void *value; +} exprval_t; + +typedef struct exprsym_s { + const char *name; + exprtype_t *type; + void *value; + struct exprsym_s *next; +} exprsym_t; + +typedef struct exprtab_s { + exprsym_t *symbols; + struct hashtab_s *tab; +} exprtab_t; + +typedef struct exprctx_s { + exprval_t *result; + exprtab_t *symtab; // directly accessible symbols + exprtab_t *external_variables; // accessible via $id + struct memsuper_s *memsuper; + const struct plitem_s *item; + struct plitem_s *messages; + struct hashlink_s *hashlinks; +} exprctx_t; + +typedef struct exprenum_s { + exprtype_t *type; + exprtab_t *symtab; +} exprenum_t; + +int cexpr_parse_enum (exprenum_t *enm, const char *str, + const exprctx_t *context, void *data); +binop_t *cexpr_find_cast (exprtype_t *dst_type, exprtype_t *src_type) __attribute__((pure)); +exprval_t *cexpr_value (exprtype_t *type, exprctx_t *ctx); +exprval_t *cexpr_value_reference (exprtype_t *type, void *data, exprctx_t *ctx); +int cexpr_eval_string (const char *str, exprctx_t *context); +void cexpr_error(exprctx_t *ctx, const char *fmt, ...) __attribute__((format(printf,2,3))); + +void cexpr_struct_getfield (const exprval_t *a, const exprval_t *b, + exprval_t *c, exprctx_t *ctx); +exprval_t *cexpr_cvar (const char *name, exprctx_t *ctx); +exprval_t *cexpr_cvar_struct (exprctx_t *ctx); + +void cexpr_init_symtab (exprtab_t *symtab, exprctx_t *ctx); + +char *cexpr_yyget_text (void *scanner); + +extern exprtype_t cexpr_int; +extern exprtype_t cexpr_uint; +extern exprtype_t cexpr_float; +extern exprtype_t cexpr_double; +extern exprtype_t cexpr_exprval; +extern exprtype_t cexpr_field; + +extern binop_t cexpr_struct_binops[]; + +#endif diff --git a/libs/util/Makemodule.am b/libs/util/Makemodule.am index af99b15d3..f554289be 100644 --- a/libs/util/Makemodule.am +++ b/libs/util/Makemodule.am @@ -43,6 +43,10 @@ libs_util_libQFutil_la_SOURCES= \ libs/util/bspfile.c \ libs/util/buildnum.c \ libs/util/cbuf.c \ + libs/util/cexpr-lex.l \ + libs/util/cexpr-parse.y \ + libs/util/cexpr-type.c \ + libs/util/cexpr-vars.c \ libs/util/checksum.c \ libs/util/cmd.c \ libs/util/cmem.c \ @@ -82,4 +86,13 @@ libs_util_libQFutil_la_SOURCES= \ libs/util/zone.c \ $(dirent) $(fnmatch) $(getopt) +BUILT_SOURCES += \ + libs/util/cexpr-lex.c \ + libs/util/cexpr-parse.c + +libs/util/cexpr-parse.c: libs/util/cexpr-parse.y + $(AM_V_YACC)$(YACCCOMPILE) $< -o $@ +libs/util/cexpr-lex.c: libs/util/cexpr-lex.l libs/util/cexpr-parse.h + $(AM_V_LEX)$(LEXCOMPILE) -o$@ $< + EXTRA_DIST += $(fnmatch_src) $(getopt_src) diff --git a/libs/util/cexpr-lex.l b/libs/util/cexpr-lex.l new file mode 100644 index 000000000..cfb1b99c6 --- /dev/null +++ b/libs/util/cexpr-lex.l @@ -0,0 +1,281 @@ +/* + cexpr-lex.l + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +%option bison-bridge +%option reentrant +%option prefix="cexpr_yy" +%option noyywrap + +%{ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include +#include + +#include "QF/cmem.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/qfplist.h" +#include "QF/sys.h" + +#include "QF/cexpr.h" +#include "libs/util/cexpr-parse.h" + +#define YY_NO_INPUT +#define YY_NO_UNPUT + +#define YYSTYPE CEXPR_YYSTYPE +#define YY_EXTRA_TYPE exprctx_t * + +exprctx_t *cexpr_yyget_extra (yyscan_t yyscanner) __attribute__((pure)); +int cexpr_yyget_lineno (yyscan_t yyscanner) __attribute__((pure)); +int cexpr_yyget_column (yyscan_t yyscanner) __attribute__((pure)); +YYSTYPE *cexpr_yyget_lval (yyscan_t yyscanner) __attribute__((pure)); +int cexpr_yyget_debug (yyscan_t yyscanner) __attribute__((pure)); +char *cexpr_yyget_text (yyscan_t yyscanner) __attribute__((pure)); +int cexpr_yyget_leng (yyscan_t yyscanner) __attribute__((pure)); +FILE *cexpr_yyget_out (yyscan_t yyscanner) __attribute__((pure)); +FILE *cexpr_yyget_in (yyscan_t yyscanner) __attribute__((pure)); + +static exprval_t *parse_int (const char *str, exprctx_t *context); +static exprval_t *parse_uint (const char *str, exprctx_t *context); +static exprval_t *parse_float (const char *str, exprctx_t *context); +static exprval_t *parse_double (const char *str, exprctx_t *context); +static exprsym_t *parse_name (const char *str, exprctx_t *context); +static exprval_t *parse_variable (const char *str, exprctx_t *context); + +VISIBLE void +cexpr_error(exprctx_t *ctx, const char *fmt, ...) +{ + va_list args; + dstring_t *string; + + string = dstring_new (); + + va_start (args, fmt); + dvsprintf (string, fmt, args); + va_end (args); + + if (ctx->messages) { + PL_Message (ctx->messages, ctx->item, "%s", string->str); + } else { + Sys_Printf ("%s\n", string->str); + } + dstring_delete (string); +} + +%} + +s [ \t] +m [\-+] +D [0-9] +B [01] +X [0-9a-fA-F] +ID [a-zA-Z_][a-zA-Z_0-9]* +FLOAT ({D}+|{D}*\.{D}+|{D}+\.{D}*)([eE]{m}?{D}+)? +FLOATf {FLOAT}[fF] +FLOATd {FLOAT}[dD] +INT ({D}+|0[xX]{X}+|0[bB]{B}) +STRING \"(\\.|[^"\\])*\" + +%% +%{ + __auto_type context = yyget_extra (yyscanner); +%} + +{INT}+ { + yylval->value = parse_int (yytext, context); + return VALUE; + } + +{INT}+[uU] { + yylval->value = parse_uint (yytext, context); + return VALUE; + } + +{FLOAT} { + yylval->value = parse_double (yytext, context); + return VALUE; + } +{FLOATf} { + yylval->value = parse_float (yytext, context); + return VALUE; + } +{FLOATd} { + yylval->value = parse_double (yytext, context); + return VALUE; + } + +{ID} { + yylval->symbol = parse_name (yytext, context); + return NAME; + } + +\${ID} { + yylval->value = parse_variable (yytext + 1, context); + return VALUE; + } + +{STRING} { + } +@ return '@'; + +'(\\[^xX0-7\r\n]|[^'\r\n]|\\[xX][0-9A-Fa-f]+|\\[0-7]+)*' { + } + +[+\-*/&|^%]= { + } + +"%%=" { + } + +"<<=" { + } + +">>=" { + } + +[!(){}.*/&|^~+\-=\[\];,#%?:] { + return yytext[0]; + } + +"%%" { + } + +"<<" return SHL; +">>" return SHR; + +"&&" return AND; +"||" return OR; +"==" return EQ; +"!=" return NE; +"<=" return LE; +">=" return GE; +"<" return LT; +">" return GT; + +"++" { + } + +"--" { + } + +<*>\r*\n { + } + +<*>{s}* /* skip */ + +<*>. cexpr_error (context, "all your typo are belong to us"); + +%% + +VISIBLE int +cexpr_eval_string (const char *str, exprctx_t *context) +{ + int status; + yyscan_t scanner; + cexpr_yypstate *ps = cexpr_yypstate_new (); + + yylex_init_extra (context, &scanner); + yy_scan_string (str, scanner); + + do { + CEXPR_YYSTYPE lval; + int token = yylex (&lval, scanner); + status = cexpr_yypush_parse (ps, token, &lval, scanner, context); + } while (status == YYPUSH_MORE); + + yylex_destroy (scanner); + cexpr_yypstate_delete (ps); + return status; +} + +static exprval_t *parse_int (const char *str, exprctx_t *context) +{ + exprval_t *val = cexpr_value (&cexpr_int, context); + *(int *) val->value = strtoimax (str, 0, 0); + return val; +} + +static exprval_t *parse_uint (const char *str, exprctx_t *context) +{ + exprval_t *val = cexpr_value (&cexpr_uint, context); + *(unsigned *) val->value = strtoumax (str, 0, 0); + return val; +} + +static exprval_t *parse_float (const char *str, exprctx_t *context) +{ + exprval_t *val = cexpr_value (&cexpr_int, context); + *(float *) val->value = strtof (str, 0); + return val; +} + +static exprval_t *parse_double (const char *str, exprctx_t *context) +{ + exprval_t *val = cexpr_value (&cexpr_int, context); + *(double *) val->value = strtod (str, 0); + return val; +} + +static exprsym_t * +parse_name (const char *name, exprctx_t *context) +{ + exprtab_t *symtab = context->symtab; + + __auto_type sym = (exprsym_t *) Hash_Find (symtab->tab, name); + return sym; +} + +static exprval_t * +parse_variable (const char *name, exprctx_t *context) +{ + exprval_t *val = 0; + if (strcmp (name, "cvars") == 0) { + val = cexpr_cvar_struct (context); + } else { + exprtab_t *symtab = context->external_variables; + __auto_type sym = (exprsym_t *) Hash_Find (symtab->tab, name); + if (sym) { + val = cexpr_value_reference (sym->type, sym->value, context); + } else { + val = cexpr_cvar (name, context); + } + } + if (!val) { + cexpr_error (context, "undefined variable %s", name); + } + return val; +} diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y new file mode 100644 index 000000000..ac41c549c --- /dev/null +++ b/libs/util/cexpr-parse.y @@ -0,0 +1,219 @@ +/* + cexpr-parse.y + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +%define api.prefix {cexpr_yy} +%define api.pure full +%define api.push-pull push +%parse-param {void *scanner} {exprctx_t *context} + +%{ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/cmem.h" +#include "QF/hash.h" +#include "QF/qfplist.h" +#include "QF/sys.h" + +#include "QF/cexpr.h" + +static void assign_expr (exprval_t *dst, const exprval_t *src, + exprctx_t *context); +static exprval_t *binary_expr (int op, const exprval_t *a, const exprval_t *b, + exprctx_t *context); +static exprval_t *field_expr (const exprval_t *a, const exprval_t *b, + exprctx_t *context); + +static void +yyerror (void *scanner, exprctx_t *context, const char *s) +{ + cexpr_error (context, "%s before %s\n", s, cexpr_yyget_text (scanner)); +} + +%} + +%left COMMA +%right '=' ASX +%right '?' ':' +%left OR +%left AND +%left '|' +%left '^' +%left '&' +%left EQ NE +%left LE GE LT GT + +%left SHL SHR +%left '+' '-' +%left '*' '/' '%' MOD +%right SIZEOF UNARY INCOP +%left HYPERUNARY +%left '.' '(' '[' + +%token NAME +%token VALUE + +%type expr field + +%union { + int op; + exprsym_t *symbol; + exprval_t *value; + const char *string; +} + +%% + +start + : expr { assign_expr (context->result, $1, context); } + ; + +expr + : expr SHL expr { $$ = binary_expr (SHL, $1, $3, context); } + | expr SHR expr { $$ = binary_expr (SHR, $1, $3, context); } + | expr '+' expr { $$ = binary_expr ('+', $1, $3, context); } + | expr '-' expr { $$ = binary_expr ('-', $1, $3, context); } + | expr '*' expr { $$ = binary_expr ('*', $1, $3, context); } + | expr '/' expr { $$ = binary_expr ('/', $1, $3, context); } + | expr '&' expr { $$ = binary_expr ('&', $1, $3, context); } + | expr '|' expr { $$ = binary_expr ('|', $1, $3, context); } + | expr '^' expr { $$ = binary_expr ('^', $1, $3, context); } + | expr '%' expr { $$ = binary_expr ('%', $1, $3, context); } + | expr '.' field { $$ = field_expr ($1, $3, context); } + | expr MOD expr { $$ = binary_expr (MOD, $1, $3, context); } + | NAME + { + if ($1) { + $$ = (exprval_t *) cmemalloc (context->memsuper, sizeof (*$$)); + $$->type = $1->type; + $$->value = $1->value; + } else { + cexpr_error (context, "undefined identifier %s", + cexpr_yyget_text (scanner)); + } + } + | VALUE + ; + +field + : NAME + { + exprctx_t *ctx = context; + const char *name = cexpr_yyget_text (scanner); + size_t size = strlen (name) + 1; + //FIXME reuse strings + $$ = (exprval_t *) cmemalloc (ctx->memsuper, sizeof (exprval_t)); + $$->type = &cexpr_field; + $$->value = cmemalloc (ctx->memsuper, size); + memcpy ($$->value, name, size); + } + ; + +%% + +static void +assign_expr (exprval_t *dst, const exprval_t *src, exprctx_t *context) +{ + binop_t *binop; + if (!src) { + return; + } + for (binop = dst->type->binops; binop && binop->op; binop++) { + if (binop->op == '=' && binop->other == src->type) { + break; + } + } + if (binop && binop->op) { + binop->func (dst, src, dst, context); + } else { + if (dst->type != src->type) { + cexpr_error (context, + "type mismatch in expression result: %s = %s\n", + dst->type->name, src->type->name); + return; + } + memcpy (dst->value, src->value, dst->type->size); + } +} + +static exprval_t * +binary_expr (int op, const exprval_t *a, const exprval_t *b, + exprctx_t *context) +{ + binop_t *binop; + + for (binop = a->type->binops; binop->op; binop++) { + exprtype_t *otype = binop->other; + if (!otype) { + otype = a->type; + } + if (binop->op == op && binop->other == b->type) { + break; + } + } + exprtype_t *rtype = binop->result; + if (!rtype) { + rtype = a->type; + } + exprval_t *result = cexpr_value (rtype, context); + if (!binop->op) { + cexpr_error (context, "invalid binary expression: %s %c %s\n", + a->type->name, op, b->type->name); + } else { + binop->func (a, b, result, context); + } + return result; +} + +static exprval_t * +field_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context) +{ + binop_t *binop; + exprval_t *result = 0; + + for (binop = a->type->binops; binop->op; binop++) { + if (binop->op == '.' && binop->other == b->type) { + break; + } + } + if (!binop->op) { + cexpr_error (context, "invalid binary expression: %s.%s\n", + a->type->name, b->type->name); + } else { + exprval_t c = { 0, &result }; + binop->func (a, b, &c, context); + } + return result; +} diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c new file mode 100644 index 000000000..35c62ee85 --- /dev/null +++ b/libs/util/cexpr-type.c @@ -0,0 +1,314 @@ +/* + cexpr-type.c + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include "QF/cexpr.h" + +#include "libs/util/cexpr-parse.h" + +#define BINOP(pre, opname, type, op) \ +static void \ +pre##_##opname (const exprval_t *a, const exprval_t *b, exprval_t *c, \ + exprctx_t *ctx) \ +{ \ + (*(type *) c->value) = (*(type *) a->value) op (*(type *) b->value); \ +} + +#define UNOP(pre, opname, type, op) \ +static void \ +pre##_##opname (const exprval_t *a, exprval_t *b, exprctx_t *ctx) \ +{ \ + (*(type *) b->value) = op (*(type *) a->value); \ +} + +BINOP(int, shl, int, <<) +BINOP(int, shr, int, >>) +BINOP(int, add, int, +) +BINOP(int, sub, int, -) +BINOP(int, mul, int, *) +BINOP(int, div, int, /) +BINOP(int, band, int, &) +BINOP(int, bor, int, |) +BINOP(int, xor, int, ^) +BINOP(int, rem, int, %) + +UNOP(int, pos, int, +) +UNOP(int, neg, int, -) +UNOP(int, tnot, int, !) +UNOP(int, bnot, int, ~) + +static void +int_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + // implement true modulo for integers: + // 5 mod 3 = 2 + // -5 mod 3 = 1 + // 5 mod -3 = -1 + // -5 mod -3 = -2 + int a = *(int *) val1->value; + int b = *(int *) val2->value; + int c = a % b; + // % is really remainder and so has the same sign rules + // as division: -5 % 3 = -2, so need to add b (3 here) + // if c's sign is incorrect, but only if c is non-zero + int mask = (a ^ b) >> 31; + mask &= ~(!!c + 0) + 1; // +0 to convert bool to int (gcc) + *(int *) result->value = c + (mask & b); +} + +binop_t int_binops[] = { + { SHL, &cexpr_int, &cexpr_int, int_shl }, + { SHR, &cexpr_int, &cexpr_int, int_shr }, + { '+', &cexpr_int, &cexpr_int, int_add }, + { '-', &cexpr_int, &cexpr_int, int_sub }, + { '*', &cexpr_int, &cexpr_int, int_mul }, + { '/', &cexpr_int, &cexpr_int, int_div }, + { '&', &cexpr_int, &cexpr_int, int_band }, + { '|', &cexpr_int, &cexpr_int, int_bor }, + { '^', &cexpr_int, &cexpr_int, int_xor }, + { '%', &cexpr_int, &cexpr_int, int_rem }, + { MOD, &cexpr_int, &cexpr_int, int_mod }, + {} +}; + +unop_t int_unops[] = { + { '+', &cexpr_int, int_pos }, + { '-', &cexpr_int, int_neg }, + { '!', &cexpr_int, int_tnot }, + { '~', &cexpr_int, int_bnot }, + {} +}; + +exprtype_t cexpr_int = { + "int", + sizeof (int), + int_binops, + int_unops, +}; + +BINOP(uint, shl, unsigned, <<) +BINOP(uint, shr, unsigned, >>) +BINOP(uint, add, unsigned, +) +BINOP(uint, sub, unsigned, -) +BINOP(uint, mul, unsigned, *) +BINOP(uint, div, unsigned, /) +BINOP(uint, band, unsigned, &) +BINOP(uint, bor, unsigned, |) +BINOP(uint, xor, unsigned, ^) +BINOP(uint, rem, unsigned, %) + +UNOP(uint, pos, unsigned, +) +UNOP(uint, neg, unsigned, -) +UNOP(uint, tnot, unsigned, !) +UNOP(uint, bnot, unsigned, ~) + +binop_t uint_binops[] = { + { SHL, &cexpr_uint, &cexpr_uint, uint_shl }, + { SHR, &cexpr_uint, &cexpr_uint, uint_shr }, + { '+', &cexpr_uint, &cexpr_uint, uint_add }, + { '-', &cexpr_uint, &cexpr_uint, uint_sub }, + { '*', &cexpr_uint, &cexpr_uint, uint_mul }, + { '/', &cexpr_uint, &cexpr_uint, uint_div }, + { '&', &cexpr_uint, &cexpr_uint, uint_band }, + { '|', &cexpr_uint, &cexpr_uint, uint_bor }, + { '^', &cexpr_uint, &cexpr_uint, uint_xor }, + { '%', &cexpr_uint, &cexpr_uint, uint_rem }, + { MOD, &cexpr_uint, &cexpr_uint, uint_rem }, + {} +}; + +unop_t uint_unops[] = { + { '+', &cexpr_uint, uint_pos }, + { '-', &cexpr_uint, uint_neg }, + { '!', &cexpr_uint, uint_tnot }, + { '~', &cexpr_uint, uint_bnot }, + {} +}; + +exprtype_t cexpr_uint = { + "uint", + sizeof (unsigned), + uint_binops, + uint_unops, +}; + +BINOP(float, add, float, +) +BINOP(float, sub, float, -) +BINOP(float, mul, float, *) +BINOP(float, div, float, /) + +static void +float_rem (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + float a = *(float *) val1->value; + float b = *(float *) val2->value; + *(float *) result->value = a - b * truncf (a / b); +} + +static void +float_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + // implement true modulo for integers: + // 5 mod 3 = 2 + // -5 mod 3 = 1 + // 5 mod -3 = -1 + // -5 mod -3 = -2 + float a = *(float *) val1->value; + float b = *(float *) val2->value; + *(float *) result->value = a - b * floorf (a / b); +} + +UNOP(float, pos, float, +) +UNOP(float, neg, float, -) +UNOP(float, tnot, float, !) + +binop_t float_binops[] = { + { '+', &cexpr_float, &cexpr_float, float_add }, + { '-', &cexpr_float, &cexpr_float, float_sub }, + { '*', &cexpr_float, &cexpr_float, float_mul }, + { '/', &cexpr_float, &cexpr_float, float_div }, + { '%', &cexpr_float, &cexpr_float, float_rem }, + { MOD, &cexpr_float, &cexpr_float, float_mod }, + {} +}; + +unop_t float_unops[] = { + { '+', &cexpr_float, float_pos }, + { '-', &cexpr_float, float_neg }, + { '!', &cexpr_float, float_tnot }, + {} +}; + +exprtype_t cexpr_float = { + "float", + sizeof (float), + float_binops, + float_unops, +}; + +BINOP(double, add, double, +) +BINOP(double, sub, double, -) +BINOP(double, mul, double, *) +BINOP(double, div, double, /) + +static void +double_rem (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + double a = *(double *) val1->value; + double b = *(double *) val2->value; + *(double *) result->value = a - b * truncf (a / b); +} + +static void +double_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + // implement true modulo for integers: + // 5 mod 3 = 2 + // -5 mod 3 = 1 + // 5 mod -3 = -1 + // -5 mod -3 = -2 + double a = *(double *) val1->value; + double b = *(double *) val2->value; + *(double *) result->value = a - b * floorf (a / b); +} + +UNOP(double, pos, double, +) +UNOP(double, neg, double, -) +UNOP(double, tnot, double, !) + +binop_t double_binops[] = { + { '+', &cexpr_double, &cexpr_double, double_add }, + { '-', &cexpr_double, &cexpr_double, double_sub }, + { '*', &cexpr_double, &cexpr_double, double_mul }, + { '/', &cexpr_double, &cexpr_double, double_div }, + { '%', &cexpr_double, &cexpr_double, double_rem }, + { MOD, &cexpr_double, &cexpr_double, double_mod }, + {} +}; + +unop_t double_unops[] = { + { '+', &cexpr_double, double_pos }, + { '-', &cexpr_double, double_neg }, + { '!', &cexpr_double, double_tnot }, + {} +}; + +exprtype_t cexpr_double = { + "double", + sizeof (double), + double_binops, + double_unops, +}; + +exprtype_t cexpr_exprval = { + "exprval", + sizeof (exprval_t *), + 0, // can't actually do anything with an exprval + 0, +}; + +exprtype_t cexpr_field = { + "field", + 0, // has no size of its own, rather, it's the length of the name + 0, // can't actually do anything with a field + 0, +}; + +VISIBLE binop_t * +cexpr_find_cast (exprtype_t *dst_type, exprtype_t *src_type) +{ + binop_t *binop = 0; + + for (binop = dst_type->binops; binop && binop->op; binop++) { + if (binop->op == '=' && binop->other == src_type) { + break; + } + } + if (binop && binop->op) { + return binop; + } + return 0; +} + +VISIBLE int +cexpr_parse_enum (exprenum_t *enm, const char *str, const exprctx_t *ctx, + void *data) +{ + exprval_t result = { enm->type, data }; + exprctx_t context = *ctx; + context.symtab = enm->symtab; + context.result = &result; + return cexpr_eval_string (str, &context); +} diff --git a/libs/util/cexpr-vars.c b/libs/util/cexpr-vars.c new file mode 100644 index 000000000..9f01e3134 --- /dev/null +++ b/libs/util/cexpr-vars.c @@ -0,0 +1,154 @@ +/* + cexpr-vars.c + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include + +#include "QF/cexpr.h" +#include "QF/cmem.h" +#include "QF/cvar.h" +#include "QF/hash.h" +#include "QF/qfplist.h" + +#include "libs/util/cexpr-parse.h" + +VISIBLE void +cexpr_struct_getfield (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + __auto_type symtab = (exprtab_t *) a->type->data; + __auto_type name = (const char *) b->value; + __auto_type field = (exprsym_t *) Hash_Find (symtab->tab, name); + exprval_t *val = 0; + if (field) { + val = cmemalloc (ctx->memsuper, sizeof (exprval_t)); + val->type = field->type; + val->value = a->value + (ptrdiff_t) field->value; + } + *(exprval_t **) c->value = val; +} + +VISIBLE binop_t cexpr_struct_binops[] = { + { '.', &cexpr_field, &cexpr_exprval, cexpr_struct_getfield }, + {} +}; + +static void +cvar_get (const exprval_t *a, const exprval_t *b, exprval_t *c, exprctx_t *ctx) +{ + __auto_type name = (const char *) b->value; + exprval_t *var = cexpr_cvar (name, ctx); + if (!var) { + PL_Message (ctx->messages, ctx->item, "unknown cvar %s", name); + } + *(exprval_t **) c->value = var; +} + +static binop_t cvar_binops[] = { + { '.', &cexpr_field, &cexpr_exprval, cvar_get }, + {} +}; + +static exprtype_t cvar_type = { + "cvar", + sizeof (void *), // ref to struct (will always be 0) + cvar_binops, + 0, +}; + +VISIBLE exprval_t * +cexpr_cvar (const char *name, exprctx_t *ctx) +{ + cvar_t *var = Cvar_FindVar (name); + if (!var) { + var = Cvar_FindAlias (name); + } + if (!var) { + return 0; + } + + exprtype_t *type = ctx->result->type; + binop_t *cast = cexpr_find_cast (type, &cexpr_int); + + exprval_t *val = 0; + if (cast || val->type == &cexpr_int || val->type == &cexpr_uint) { + val = cexpr_value (type, ctx); + *(int *) val->value = var->int_val; + } else if (val->type == &cexpr_float) { + val = cexpr_value (type, ctx); + *(float *) val->value = var->value; + } else if (val->type == &cexpr_double) { + val = cexpr_value (type, ctx); + //FIXME cvars need to support double values + *(double *) val->value = var->value; + } + return val; +} + +VISIBLE exprval_t * +cexpr_cvar_struct (exprctx_t *ctx) +{ + exprval_t *cvars = cexpr_value (&cvar_type, ctx); + *(void **) cvars->value = 0; + return cvars; +} + +static const char *expr_getkey (const void *s, void *unused) +{ + __auto_type sym = (exprsym_t *) s; + return sym->name; +} + +void cexpr_init_symtab (exprtab_t *symtab, exprctx_t *ctx) +{ + exprsym_t *sym; + + symtab->tab = Hash_NewTable (61, expr_getkey, 0, 0, &ctx->hashlinks); + for (sym = symtab->symbols; sym->name; sym++) { + Hash_Add (symtab->tab, sym); + } +} + +VISIBLE exprval_t * +cexpr_value_reference (exprtype_t *type, void *data, exprctx_t *ctx) +{ + __auto_type ref = (exprval_t *) cmemalloc (ctx->memsuper, + sizeof (exprval_t)); + ref->type = type; + ref->value = data; + return ref; +} + +VISIBLE exprval_t * +cexpr_value (exprtype_t *type, exprctx_t *ctx) +{ + exprval_t *val = cexpr_value_reference (type, 0, ctx); + val->value = cmemalloc (ctx->memsuper, type->size); + return val; +} diff --git a/libs/util/test/Makemodule.am b/libs/util/test/Makemodule.am index 39140bee7..9447a7807 100644 --- a/libs/util/test/Makemodule.am +++ b/libs/util/test/Makemodule.am @@ -1,5 +1,6 @@ libs_util_tests = \ libs/util/test/test-bary \ + libs/util/test/test-cexpr \ libs/util/test/test-cmem \ libs/util/test/test-cs \ libs/util/test/test-darray \ @@ -24,6 +25,10 @@ libs_util_test_test_bary_SOURCES=libs/util/test/test-bary.c libs_util_test_test_bary_LDADD=libs/util/libQFutil.la libs_util_test_test_bary_DEPENDENCIES=libs/util/libQFutil.la +libs_util_test_test_cexpr_SOURCES=libs/util/test/test-cexpr.c +libs_util_test_test_cexpr_LDADD=libs/util/libQFutil.la +libs_util_test_test_cexpr_DEPENDENCIES=libs/util/libQFutil.la + libs_util_test_test_cmem_SOURCES=libs/util/test/test-cmem.c libs_util_test_test_cmem_LDADD=libs/util/libQFutil.la libs_util_test_test_cmem_DEPENDENCIES=libs/util/libQFutil.la diff --git a/libs/util/test/test-cexpr.c b/libs/util/test/test-cexpr.c new file mode 100644 index 000000000..095316222 --- /dev/null +++ b/libs/util/test/test-cexpr.c @@ -0,0 +1,81 @@ +/* + test-cexpr.c + + Config expression parser. Or concurrent. + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#include "QF/cexpr.h" +#include "QF/cmem.h" +#include "QF/hash.h" + +int a = 5; +int b = 6; +int c; + +exprsym_t symbols[] = { + { "a", &cexpr_int, &a }, + { "b", &cexpr_int, &b }, + {} +}; +exprval_t result = { &cexpr_int, &c }; + +exprtab_t symtab = { + symbols, + 0 +}; + +exprctx_t context = { &result, &symtab }; + +#define TEST_BINOP(op) \ + do { \ + c = -4096; \ + cexpr_eval_string ("a " #op " b", &context); \ + printf ("c = a %s b -> %d = %d %s %d\n", #op, c, a, #op, b); \ + if (c != (a op b)) { \ + ret |= 1; \ + } \ + } while (0) + +int +main(int argc, const char **argv) +{ + int ret = 0; + + cexpr_init_symtab (&symtab, &context); + context.memsuper = new_memsuper(); + + TEST_BINOP (<<); + TEST_BINOP (>>); + TEST_BINOP (+); + TEST_BINOP (-); + TEST_BINOP (*); + TEST_BINOP (/); + TEST_BINOP (&); + TEST_BINOP (|); + TEST_BINOP (^); + TEST_BINOP (%); + + Hash_DelTable (symtab.tab); + delete_memsuper (context.memsuper); + return ret; +} From 4649294a275b9777e81b0852a26e9fa004a5fbf6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 21 Dec 2020 14:47:15 +0900 Subject: [PATCH 134/435] [util] Fix inferred binary operator type checking The problem is that I needed to support dynamic types on operators (for bit-field enums), had things working, but a bad edit messed things up and I had to rebuild that bit of code. Missed one bit :P --- libs/util/cexpr-parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y index ac41c549c..e789a40e9 100644 --- a/libs/util/cexpr-parse.y +++ b/libs/util/cexpr-parse.y @@ -179,7 +179,7 @@ binary_expr (int op, const exprval_t *a, const exprval_t *b, if (!otype) { otype = a->type; } - if (binop->op == op && binop->other == b->type) { + if (binop->op == op && otype == b->type) { break; } } From 96df447c45481a9698402f136061b41deb331ed3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 21 Dec 2020 18:38:31 +0900 Subject: [PATCH 135/435] [vulkan] Hook up the expression parser The pipeline parser still isn't hooked up yet as something isn't quite right, but it seems all the parsing works. --- include/vid_vulkan.h | 1 + libs/video/renderer/Makemodule.am | 17 ++- libs/video/renderer/vulkan/qfpipeline.plist | 13 +- libs/video/renderer/vulkan/vkgen/vkalias.r | 18 +++ libs/video/renderer/vulkan/vkgen/vkenum.h | 3 + libs/video/renderer/vulkan/vkgen/vkenum.r | 74 ++++++++-- libs/video/renderer/vulkan/vkgen/vkgen.h | 1 + libs/video/renderer/vulkan/vkgen/vkgen.r | 21 ++- libs/video/renderer/vulkan/vkgen/vkstruct.h | 1 + libs/video/renderer/vulkan/vkgen/vkstruct.r | 95 +++++++++++- libs/video/renderer/vulkan/vkgen/vktype.h | 1 + libs/video/renderer/vulkan/vkgen/vktype.r | 5 + libs/video/renderer/vulkan/vkgen/vulkan.r | 1 + libs/video/renderer/vulkan/vkparse.c | 137 ++++++++++-------- libs/video/renderer/vulkan/vkparse.h | 6 +- libs/video/renderer/vulkan/vkparse.plist | 5 + .../video/renderer/vulkan/vulkan_vid_common.c | 22 ++- 17 files changed, 332 insertions(+), 89 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 2675d3036..411fcf4db 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -41,6 +41,7 @@ typedef struct vulkan_ctx_s { struct qfv_instance_s *instance; struct qfv_device_s *device; struct qfv_swapchain_s *swapchain; + struct hashlink_s *hashlinks; //FIXME want per thread VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain VkCommandPool cmdpool; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 1077ef6ca..e2b71bf07 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -233,12 +233,15 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/vkparse.lo: libs/video/renderer/vulkan/vkparse.c $(vkparse_src) -libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c $(pipeline_gen) +libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c ${vkparse_src} $(pipeline_gen) qwaq_curses = ruamoko/qwaq/qwaq-curses$(EXEEXT) +vkparse_cinc = libs/video/renderer/vulkan/vkparse.cinc +vkparse_hinc = libs/video/renderer/vulkan/vkparse.hinc vkparse_src = \ - libs/video/renderer/vulkan/vkparse.inc + ${vkparse_cinc} \ + ${vkparse_hinc} vkparse_plist = \ $(srcdir)/libs/video/renderer/vulkan/vkparse.plist @@ -247,9 +250,13 @@ V_VKGEN_ = $(V_VKGEN_@AM_DEFAULT_V@) V_VKGEN_0 = @echo " VKGEN " $@; V_VKGEN_1 = -libs/video/renderer/vulkan/vkparse.inc: $(vkgen) $(qwaq_curses) $(vkparse_plist) - $(V_VKGEN)$(qwaq_curses) $(vkgen) -- $(vkparse_plist) $@.t &&\ - $(am__mv) $@.t $@ +${vkparse_cinc}: $(vkgen) $(qwaq_curses) $(vkparse_plist) + $(V_VKGEN)$(qwaq_curses) $(vkgen) -- $(vkparse_plist) ${vkparse_cinc}.t ${vkparse_hinc}.t &&\ + $(am__mv) ${vkparse_cinc}.t ${vkparse_cinc} &&\ + $(am__mv) ${vkparse_hinc}.t ${vkparse_hinc} + +${vkparse_hinc}: ${vkparse_cinc} +# do nothing: hinc generated at the same time as cinc CLEANFILES += \ libs/video/renderer/glsl/*.vc \ diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 1c594aee0..a8e1c36c9 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -14,18 +14,18 @@ }, { flags = 0; - format = $swapchain.format; - samples = $msaaSamples; + format = VK_FORMAT_D32_SFLOAT; + samples = $cvars.msaaSamples; loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - storeOp = VK_ATTACHMENT_STORE_OP_STORE; + storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; }, { flags = 0; - format = VK_FORMAT_D32_SFLOAT; + format = $swapchain.format; samples = VK_SAMPLE_COUNT_1_BIT; loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -37,6 +37,7 @@ ); subpasses = ( { + pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; colorAttachments = ( { attachment = 0; @@ -51,7 +52,7 @@ ); depthStencilAttachment = { attachment = 1; - layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; }; preserveAttachments = (); }, diff --git a/libs/video/renderer/vulkan/vkgen/vkalias.r b/libs/video/renderer/vulkan/vkgen/vkalias.r index 6228ac230..132e6291a 100644 --- a/libs/video/renderer/vulkan/vkgen/vkalias.r +++ b/libs/video/renderer/vulkan/vkgen/vkalias.r @@ -50,6 +50,24 @@ } } +-(string) cexprType +{ + Type *alias = [Type findType:type.alias.full_type]; + string name = [self name]; + + if ([alias name] == "VkFlags") { + if (str_mid (name, -5) == "Flags") { + string tag = str_mid (name, 0, -1) + "Bits"; + id enumObj = [(id) Hash_Find (available_types, tag) resolveType]; + return [enumObj cexprType]; + } + } + if (name == "uint32_t") { + return "cexpr_uint"; + } + return [alias cexprType]; +} + -(string) parseType { Type *alias = [Type findType:type.alias.full_type]; diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.h b/libs/video/renderer/vulkan/vkgen/vkenum.h index 5deb7ff6f..6694c24cb 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.h +++ b/libs/video/renderer/vulkan/vkgen/vkenum.h @@ -3,11 +3,14 @@ #include "vktype.h" +@class PLItem; + @interface Enum: Type { int prefix_length; } -(void) writeTable; +-(void) writeSymtabInit:(PLItem *) parse; @end #endif//__renderer_vulkan_vkgen_vkenum_h diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.r b/libs/video/renderer/vulkan/vkgen/vkenum.r index 768e4b8d4..e3894902a 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.r +++ b/libs/video/renderer/vulkan/vkgen/vkenum.r @@ -50,6 +50,15 @@ } } +static int +skip_value(string name) +{ + return (str_str (name, "_MAX_ENUM") >= 0 + || str_str (name, "_BEGIN_RANGE") >= 0 + || str_str (name, "_END_RANGE") >= 0 + || str_str (name, "_RANGE_SIZE") >= 0); +} + -(void) writeTable { int strip_bit = 0; @@ -57,16 +66,37 @@ strip_bit = 1; } - fprintf (output_file, "enumval_t %s_values[] = {\n", [self name]); - for (int i = 0; i < type.strct.num_fields; i++) { + fprintf (output_file, "static exprtype_t %s_type = {\n", [self name]); + fprintf (output_file, "\t\"%s\",\n", [self name]); + fprintf (output_file, "\tsizeof (int),\n"); + if (strip_bit) { + fprintf (output_file, "\tflag_binops,\n"); + fprintf (output_file, "\tflag_unops,\n"); + } else { + fprintf (output_file, "\t0,\n"); + fprintf (output_file, "\t0,\n"); + } + fprintf (output_file, "};\n"); + + fprintf (output_file, "static %s %s_values[] = {\n", [self name], [self name]); + for (int i = 0, index = 0; i < type.strct.num_fields; i++) { qfot_var_t *var = &type.strct.fields[i]; - if (str_str (var.name, "_MAX_ENUM") >= 0 - || str_str (var.name, "_BEGIN_RANGE") >= 0 - || str_str (var.name, "_END_RANGE") >= 0 - || str_str (var.name, "_RANGE_SIZE") >= 0) { + if (skip_value (var.name)) { continue; } - fprintf (output_file, "\t{\"%s\", %d},\n", var.name, var.offset); + fprintf (output_file, "\t%s, // %d 0x%x\n", + var.name, var.offset, var.offset); + index++; + } + fprintf (output_file, "};\n"); + fprintf (output_file, "static exprsym_t %s_symbols[] = {\n", [self name]); + for (int i = 0, index = 0; i < type.strct.num_fields; i++) { + qfot_var_t *var = &type.strct.fields[i]; + if (skip_value (var.name)) { + continue; + } + fprintf (output_file, "\t{\"%s\", &%s_type, %s_values + %d},\n", + var.name, [self name], [self name], index); if (prefix_length) { string shortname = str_mid (var.name, prefix_length); if (strip_bit) { @@ -75,12 +105,33 @@ shortname = str_mid (shortname, 0, bit_pos); } } - fprintf (output_file, "\t{\"%s\", %d},\n", str_lower(shortname), - var.offset); + fprintf (output_file, "\t{\"%s\", &%s_type, %s_values + %d},\n", + str_lower(shortname), [self name], [self name], index); } + index++; } fprintf (output_file, "\t{ }\n"); fprintf (output_file, "};\n"); + fprintf (output_file, "static exprtab_t %s_symtab = {\n", [self name]); + fprintf (output_file, "\t%s_symbols,\n", [self name]); + fprintf (output_file, "};\n"); + fprintf (output_file, "exprenum_t %s_enum = {\n", [self name]); + fprintf (output_file, "\t&%s_type,\n", [self name]); + fprintf (output_file, "\t&%s_symtab,\n", [self name]); + fprintf (output_file, "};\n"); + + fprintf (header_file, "extern exprenum_t %s_enum;\n", [self name]); +} + +-(void) writeSymtabInit:(PLItem *) parse +{ + fprintf (output_file, "\tcexpr_init_symtab (&%s_symtab, context);\n", + [self name]); +} + +-(string) cexprType +{ + return [self name] + "_type"; } -(string) parseType @@ -90,14 +141,11 @@ -(string) parseFunc { - if (str_mid([self name], -8) == "FlagBits") { - return "parse_flags"; - } return "parse_enum"; } -(string) parseData { - return [self name] + "_values"; + return "&" + [self name] + "_enum"; } @end diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.h b/libs/video/renderer/vulkan/vkgen/vkgen.h index 0d488abe8..e60499f25 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.h +++ b/libs/video/renderer/vulkan/vkgen/vkgen.h @@ -13,6 +13,7 @@ void fprintf (QFile file, string format, ...); extern Array *queue; extern Array *output_types; extern QFile output_file; +extern QFile header_file; extern hashtab_t *processed_types; extern hashtab_t *available_types; diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r index 7744d0cdc..025e3d2cc 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.r +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -25,7 +25,6 @@ arp_end (void) autorelease_pool = nil; } - void printf (string fmt, ...) = #0; void fprintf (QFile file, string format, ...) @@ -39,6 +38,7 @@ Array *queue; Array *output_types; QFile output_file; +QFile header_file; qfot_type_encodings_t *encodings; @@ -135,7 +135,7 @@ get_object_key (void *obj, void *unused) void usage (string name) { - printf ("%s [plist file] [output file]\n", name); + printf ("%s [plist file] [output file] [header file]\n", name); } int @@ -151,7 +151,7 @@ main(int argc, string *argv) arp_start (); - if (argc != 3) { + if (argc != 4) { usage (argv[0]); return 1; } @@ -211,6 +211,7 @@ main(int argc, string *argv) arp_end (); output_file = Qopen (argv[2], "wt"); + header_file = Qopen (argv[3], "wt"); for (int i = [output_types count]; i-- > 0; ) { id obj = [output_types objectAtIndex:i]; if ([obj name] == "VkStructureType") { @@ -237,6 +238,20 @@ main(int argc, string *argv) [obj writeTable:parse]; arp_end (); } + fprintf (output_file, "static void\n"); + fprintf (output_file, "vkgen_init_symtabs (exprctx_t *context)\n"); + fprintf (output_file, "{\n"); + for (int i = [output_types count]; i-- > 0; ) { + id obj = [output_types objectAtIndex:i]; + if ([obj name] == "VkStructureType") { + continue; + } + arp_start (); + [obj writeSymtabInit:parse]; + arp_end (); + } + fprintf (output_file, "}\n"); Qclose (output_file); + Qclose (header_file); return 0; } diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.h b/libs/video/renderer/vulkan/vkgen/vkstruct.h index 246d23070..c251cb4c0 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.h +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.h @@ -13,6 +13,7 @@ } -(void) forEachFieldCall: (varfunc) func; -(void) writeTable: (PLItem *) parse; +-(void) writeSymtabInit:(PLItem *) parse; @end #endif//__renderer_vulkan_vkgen_vkstruct_h diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index b1bf22960..4c9040cb6 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -162,7 +162,11 @@ fprintf (output_file, "\t{ }\n"); fprintf (output_file, "};\n"); - fprintf (output_file, "static int parse_%s (const plfield_t *field," + fprintf (header_file, "int parse_%s (const plfield_t *field," + " const plitem_t *item, void *data, plitem_t *messages," + " void *context);\n", + name); + fprintf (output_file, "int parse_%s (const plfield_t *field," " const plitem_t *item, void *data, plitem_t *messages," " void *context)\n", name); @@ -172,6 +176,95 @@ " context);\n", name); fprintf (output_file, "}\n"); + + fprintf (output_file, "static exprsym_t %s_symbols[] = {\n", name); + if (field_defs) { + PLItem *field_def; + qfot_var_t *field; + + for (int i = [field_defs count]; i-- > 0; ) { + string field_name = [[field_defs getObjectAtIndex:i] string]; + field_def = [field_dict getObjectForKey:field_name]; + PLItem *type_desc = [field_def getObjectForKey:"type"]; + string type_record; + string type_type; + string size_field = nil; + string value_field = nil; + + if (str_mid(field_name, 0, 1) == ".") { + continue; + } + field_def = [field_dict getObjectForKey:field_name]; + if ([field_def string] == "auto") { + field = [self findField:field_name]; + if (!field) { + continue; + } + field_type = [Type findType: field.type]; + fprintf (output_file, + "\t{\"%s\", &%s, (void *) field_offset (%s, %s)},\n", + field_name, [field_type cexprType], name, field_name); + } else { + type_record = [[type_desc getObjectAtIndex:0] string]; + if (type_record == "single") { + value_field = [[field_def getObjectForKey:"value"] string]; + } else { + value_field = [[field_def getObjectForKey:"values"] string]; + } + if (!value_field) { + value_field = field_name; + } + fprintf (output_file, + "\t{\"%s\", 0/*FIXME*/," + " (void *) field_offset (%s, %s)},\n", + field_name, name, value_field); + } + } + } else { + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *field = &type.strct.fields[i]; + if (field.name == "sType" || field.name == "pNext") { + continue; + } + field_type = [Type findType: field.type]; + fprintf (output_file, + "\t{\"%s\", &%s, (void *) field_offset (%s, %s)},\n", + field.name, [field_type cexprType], name, field.name); + } + } + fprintf (output_file, "\t{ }\n"); + fprintf (output_file, "};\n"); + + fprintf (output_file, "static exprtab_t %s_symtab = {\n", name); + fprintf (output_file, "\t%s_symbols,\n", name); + fprintf (output_file, "};\n"); + + fprintf (output_file, "exprtype_t %s_type = {\n", name); + fprintf (output_file, "\t\"%s\",\n", name); + fprintf (output_file, "\tsizeof (%s),\n", name); + fprintf (output_file, "\tcexpr_struct_binops,\n"); + fprintf (output_file, "\t0,\n"); + fprintf (output_file, "\t&%s_symtab,\n", name); + fprintf (output_file, "};\n"); + fprintf (header_file, "extern exprtype_t %s_type;\n", name); +} + +-(void) writeSymtabInit:(PLItem *) parse +{ + string name = [self name]; + PLItem *field_dict = [parse getObjectForKey:name]; + PLItem *new_name = [field_dict getObjectForKey:".name"]; + + if (new_name) { + name = [new_name string]; + } + + fprintf (output_file, "\tcexpr_init_symtab (&%s_symtab, context);\n", name); +} + +-(string) cexprType +{ + return [self name] + "_type"; } -(string) parseType diff --git a/libs/video/renderer/vulkan/vkgen/vktype.h b/libs/video/renderer/vulkan/vkgen/vktype.h index fc5a53c84..0008c83ab 100644 --- a/libs/video/renderer/vulkan/vkgen/vktype.h +++ b/libs/video/renderer/vulkan/vkgen/vktype.h @@ -19,6 +19,7 @@ -(Type *) resolveType; +(Type *) findType: (qfot_type_t *) type; +(Type *) lookup: (string) name; +-(string) cexprType; -(string) parseType; -(string) parseFunc; -(string) parseData; diff --git a/libs/video/renderer/vulkan/vkgen/vktype.r b/libs/video/renderer/vulkan/vkgen/vktype.r index caa7ac057..5d6c1b7ae 100644 --- a/libs/video/renderer/vulkan/vkgen/vktype.r +++ b/libs/video/renderer/vulkan/vkgen/vktype.r @@ -91,6 +91,11 @@ static string get_type_key (void *type, void *unused) return self; } +-(string) cexprType +{ + return "cexpr_" + [self name]; +} + -(string) parseType { return "no parse"; diff --git a/libs/video/renderer/vulkan/vkgen/vulkan.r b/libs/video/renderer/vulkan/vkgen/vulkan.r index 46b720d0c..a2a53be7c 100644 --- a/libs/video/renderer/vulkan/vkgen/vulkan.r +++ b/libs/video/renderer/vulkan/vkgen/vulkan.r @@ -1,2 +1,3 @@ #define __x86_64__ #include +#include "QF/Vulkan/swapchain.h" diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index a4b037202..55798c185 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -38,6 +38,8 @@ # include #endif +#include "QF/cexpr.h" +#include "QF/cmem.h" #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/input.h" @@ -64,10 +66,41 @@ #include "util.h" #include "vkparse.h" -typedef struct enumval_s { - const char *name; - int value; -} enumval_t; +static void flag_or (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + *(int *) (result->value) = *(int *) (val1->value) | *(int *) (val2->value); +} + +static void flag_and (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + *(int *) (result->value) = *(int *) (val1->value) & *(int *) (val2->value); +} + +static void flag_cast_int (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + // FIXME should check value is valid + *(int *) (result->value) = *(int *) (val2->value); +} + +static void flag_not (const exprval_t *val, exprval_t *result, exprctx_t *ctx) +{ + *(int *) (result->value) = ~(*(int *) (val->value)); +} + +binop_t flag_binops[] = { + { '|', 0, 0, flag_or }, + { '&', 0, 0, flag_and }, + { '=', &cexpr_int, 0, flag_cast_int }, + {} +}; + +unop_t flag_unops[] = { + { '~', 0, flag_not }, + {} +}; typedef struct parse_single_s { pltype_t type; @@ -84,20 +117,8 @@ typedef struct parse_array_s { size_t size_offset; } parse_array_t; -static int find_enum (const char *valstr, enumval_t *enumval, int *val) -{ - while (enumval->name && strcmp (enumval->name, valstr) != 0) { - enumval++; - } - if (enumval->name) { - *val = enumval->value; - return 1; - } - return 0; -} - static int parse_uint32_t (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *ctx) + void *data, plitem_t *messages, void *context) { int ret = 1; const char *valstr = PL_String (item); @@ -125,47 +146,25 @@ static int parse_uint32_t (const plfield_t *field, const plitem_t *item, } static int parse_enum (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *ctx) + void *data, plitem_t *messages, void *context) { int ret = 1; - int val; + __auto_type enm = (exprenum_t *) field->data; + exprctx_t ectx = *(exprctx_t *)context; + exprval_t result = { enm->type, data }; + ectx.symtab = enm->symtab; + ectx.result = &result; const char *valstr = PL_String (item); - __auto_type enumval = (enumval_t *) field->data; - //Sys_Printf ("parse_enum: %s %zd %d %p %p %s\n", - // field->name, field->offset, field->type, field->parser, - // field->data, valstr); - if (find_enum (valstr, enumval, &val)) { - *(int *) data = val; - } else { - PL_Message (messages, item, "invalid enum: %s", valstr); - ret = 0; - } - return ret; -} - -static int parse_flags (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *ctx) -{ - int ret = 1; - int val; - const char *valstr = PL_String (item); - __auto_type enumval = (enumval_t *) field->data; - //Sys_Printf ("parse_flags: %s %zd %d %p %p %s\n", - // field->name, field->offset, field->type, field->parser, - // field->data, valstr); - if (find_enum (valstr, enumval, &val)) { - *(int *) data = val; - } else if (strcmp (valstr, "0") == 0) { - *(int *) data = 0; - } else { - PL_Message (messages, item, "invalid enum: %s", valstr); - ret = 0; - } + Sys_Printf ("parse_enum: %s %zd %d %p %p %s\n", + field->name, field->offset, field->type, field->parser, + field->data, valstr); + ret = !cexpr_parse_enum (enm, valstr, &ectx, data); + Sys_Printf (" %d\n", *(int *)data); return ret; } static int parse_single (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *ctx) + void *data, plitem_t *messages, void *context) { __auto_type single = (parse_single_t *) field->data; void *flddata = (byte *)data + single->value_offset; @@ -180,7 +179,7 @@ static int parse_single (const plfield_t *field, const plitem_t *item, plfield_t f = { 0, 0, single->type, single->parser, 0 }; void *value = calloc (1, single->stride); - if (!single->parser (&f, item, value, messages, ctx)) { + if (!single->parser (&f, item, value, messages, context)) { free (value); return 0; } @@ -190,7 +189,7 @@ static int parse_single (const plfield_t *field, const plitem_t *item, } static int parse_array (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *ctx) + void *data, plitem_t *messages, void *context) { __auto_type array = (parse_array_t *) field->data; __auto_type value = (void **) ((byte *)data + array->value_offset); @@ -213,7 +212,7 @@ static int parse_array (const plfield_t *field, const plitem_t *item, // field->data, data); //Sys_Printf (" %d %zd %p %zd %zd\n", array->type, array->stride, // array->parser, array->value_offset, array->size_offset); - if (!PL_ParseArray (&f, item, &arr, messages, ctx)) { + if (!PL_ParseArray (&f, item, &arr, messages, context)) { return 0; } *value = malloc (array->stride * arr->size); @@ -225,7 +224,7 @@ static int parse_array (const plfield_t *field, const plitem_t *item, return 1; } -#include "libs/video/renderer/vulkan/vkparse.inc" +#include "libs/video/renderer/vulkan/vkparse.cinc" typedef struct qfv_renderpass_s { qfv_attachmentdescription_t *attachments; @@ -268,20 +267,37 @@ static plfield_t renderpass_fields[] = { }; VkRenderPass -QFV_ParseRenderPass (qfv_device_t *device, plitem_t *plist) +QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) { + qfv_device_t *device = ctx->device; qfv_renderpass_t renderpass_data = {}; plitem_t *messages = PL_NewArray (); VkRenderPass renderpass; + exprsym_t var_syms[] = { + {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, + {} + }; + exprtab_t vars_tab = { var_syms, 0 }; + exprctx_t exprctx = {}; + + exprctx.external_variables = &vars_tab; + exprctx.memsuper = new_memsuper (); + exprctx.messages = messages; + exprctx.hashlinks = ctx->hashlinks; + + cexpr_init_symtab (&vars_tab, &exprctx); if (!PL_ParseDictionary (renderpass_fields, plist, - &renderpass_data, messages, 0)) { + &renderpass_data, messages, &exprctx)) { for (int i = 0; i < PL_A_NumObjects (messages); i++) { Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); } return 0; } PL_Free (messages); + delete_memsuper (exprctx.memsuper); + ctx->hashlinks = exprctx.hashlinks; + renderpass = QFV_CreateRenderPass (device, renderpass_data.attachments, renderpass_data.subpasses, @@ -299,3 +315,10 @@ QFV_ParseRenderPass (qfv_device_t *device, plitem_t *plist) free (renderpass_data.dependencies); return renderpass; } + +void +QFV_InitParse (void) +{ + exprctx_t context = {}; + vkgen_init_symtabs (&context); +} diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index 0d14eecbe..ae8a30af9 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -2,9 +2,9 @@ #define __vkparse_h #include "QF/Vulkan/renderpass.h" +#include "libs/video/renderer/vulkan/vkparse.hinc" -VkRenderPass -QFV_ParseRenderPass (qfv_device_t *device, plitem_t *plist); - +VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); +void QFV_InitParse (void); #endif//__vkparse_h diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index 017025426..1441a0267 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -3,8 +3,13 @@ VkAttachmentDescription, VkSubpassDescription, VkSubpassDependency, + qfv_swapchain_t, ); parse = { + qfv_swapchain_s = { + .name = qfv_swapchain_t; + format = auto; + }; VkSubpassDescription = { flags = auto; pipelineBindPoint = auto; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 6f0ba9892..b0d285ed6 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -39,6 +39,8 @@ # include #endif +#include "QF/cexpr.h" +#include "QF/cmem.h" #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/input.h" @@ -63,12 +65,14 @@ #include "vid_vulkan.h" #include "util.h" +#include "vkparse.h" static const char quakeforge_pipeline[] = #include "libs/video/renderer/vulkan/qfpipeline.plc" ; cvar_t *vulkan_presentation_mode; +cvar_t *msaaSamples; static void vulkan_presentation_mode_f (cvar_t *var) @@ -87,6 +91,19 @@ vulkan_presentation_mode_f (cvar_t *var) } } +static void +msaaSamples_f (cvar_t *var) +{ + exprctx_t context = {}; + context.memsuper = new_memsuper(); + + if (cexpr_parse_enum (&VkSampleCountFlagBits_enum, var->string, &context, + &var->int_val)) { + Sys_Printf ("Invalid MSAA samples, using 1\n"); + var->int_val = VK_SAMPLE_COUNT_1_BIT; + } +} + static void Vulkan_Init_Cvars (void) { @@ -100,6 +117,9 @@ Vulkan_Init_Cvars (void) CVAR_NONE, vulkan_presentation_mode_f, "desired presentation mode (may fall " "back to fifo)."); + msaaSamples = Cvar_Get ("msaaSamples", "VK_SAMPLE_COUNT_1_BIT", + CVAR_NONE, msaaSamples_f, + "desired MSAA sample size."); } static const char *instance_extensions[] = { @@ -116,8 +136,8 @@ void Vulkan_Init_Common (vulkan_ctx_t *ctx) { Sys_Printf ("Vulkan_Init_Common\n"); + QFV_InitParse (); Vulkan_Init_Cvars (); - ctx->instance = QFV_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version } From ac8206555ee145ad4a690432b6df1d5b6ffb638e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 21 Dec 2020 19:30:00 +0900 Subject: [PATCH 136/435] [vulkan] Get the parsed pipeline working It turned out the msaa setting defaulting to 1 instead of 8 was the problem no idea why at this stage (need to read up on just how that setting works). Once I understand just how it works, I'll rework the msaa handling. --- libs/video/renderer/vulkan/instance.c | 2 +- libs/video/renderer/vulkan/renderpass.c | 61 ++++++++++++++++ libs/video/renderer/vulkan/vkparse.c | 8 +-- .../video/renderer/vulkan/vulkan_vid_common.c | 69 +------------------ 4 files changed, 68 insertions(+), 72 deletions(-) diff --git a/libs/video/renderer/vulkan/instance.c b/libs/video/renderer/vulkan/instance.c index 4d23b5a75..b228df2fe 100644 --- a/libs/video/renderer/vulkan/instance.c +++ b/libs/video/renderer/vulkan/instance.c @@ -296,6 +296,6 @@ QFV_GetMaxSampleCount (qfv_physdev_t *physdev) while (maxSamples && maxSamples > counts) { maxSamples >>= 1; } - Sys_MaskPrintf (SYS_VULKAN, "Max samples: %x\n", maxSamples); + Sys_MaskPrintf (SYS_VULKAN, "Max samples: %x (%d)\n", maxSamples, counts); return maxSamples; } diff --git a/libs/video/renderer/vulkan/renderpass.c b/libs/video/renderer/vulkan/renderpass.c index 40bc095ad..78cc46563 100644 --- a/libs/video/renderer/vulkan/renderpass.c +++ b/libs/video/renderer/vulkan/renderpass.c @@ -71,6 +71,67 @@ QFV_CreateRenderPass (qfv_device_t *device, VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; + if (developer->int_val & SYS_VULKAN) { + Sys_Printf ("attachments: %ld\n", attachments->size); + for (size_t i = 0; i < attachments->size; i++) { + Sys_Printf (" flags: %x\n", attachments->a[i].flags); + Sys_Printf (" format: %d\n", attachments->a[i].format); + Sys_Printf (" samples: %x\n", attachments->a[i].samples); + Sys_Printf (" loadOp: %d\n", attachments->a[i].loadOp); + Sys_Printf (" storeOp: %d\n", attachments->a[i].storeOp); + Sys_Printf (" stencilLoadOp: %d\n", + attachments->a[i].stencilLoadOp); + Sys_Printf (" stencilStoreOp: %d\n", + attachments->a[i].stencilStoreOp); + Sys_Printf (" initialLayout: %d\n", + attachments->a[i].initialLayout); + Sys_Printf (" finalLayout: %d\n", + attachments->a[i].finalLayout); + } + Sys_Printf ("subpassparams: %ld\n", subpassparams->size); + for (size_t i = 0; i < subpassparams->size; i++) { + VkSubpassDescription *sp = &subpassparams->a[i]; + Sys_Printf (" flags: %x\n", sp->flags); + Sys_Printf (" piplineBindPoint: %d\n", sp->pipelineBindPoint); + Sys_Printf (" inputAttachmentCount: %d\n", + sp->inputAttachmentCount); + for (size_t j = 0; j < sp->inputAttachmentCount; j++) { + const VkAttachmentReference *ref = &sp->pInputAttachments[j]; + Sys_Printf (" c %d %d\n", ref->attachment, ref->layout); + } + Sys_Printf (" colorAttachmentCount: %d\n", + sp->colorAttachmentCount); + for (size_t j = 0; j < sp->colorAttachmentCount; j++) { + const VkAttachmentReference *ref = &sp->pColorAttachments[j]; + Sys_Printf (" c %d %d\n", ref->attachment, ref->layout); + } + for (size_t j = 0; j < sp->colorAttachmentCount; j++) { + const VkAttachmentReference *ref = &sp->pResolveAttachments[j]; + Sys_Printf (" r %d %d\n", ref->attachment, ref->layout); + } + Sys_Printf (" pDepthStencilAttachment: %p\n", + sp->pDepthStencilAttachment); + if (sp->pDepthStencilAttachment) { + const VkAttachmentReference *ref = sp->pDepthStencilAttachment; + Sys_Printf (" %d %d\n", ref->attachment, ref->layout); + } + Sys_Printf (" preserveAttachmentCount: %d\n", + sp->preserveAttachmentCount); + for (size_t j = 0; j < sp->preserveAttachmentCount; j++) { + Sys_Printf (" %d\n", sp->pPreserveAttachments[j]); + } + } + Sys_Printf ("dependencies: %ld\n", dependencies->size); + for (size_t i = 0; i < dependencies->size; i++) { + Sys_Printf (" srcSubpass: %d\n", dependencies->a[i].srcSubpass); + Sys_Printf (" dstSubpass: %d\n", dependencies->a[i].dstSubpass); + Sys_Printf (" srcStageMask: %x\n", dependencies->a[i].srcStageMask); + Sys_Printf (" dstStageMask: %x\n", dependencies->a[i].dstStageMask); + Sys_Printf (" srcAccessMask: %x\n", dependencies->a[i].srcAccessMask); + Sys_Printf (" dstAccessMask: %x\n", dependencies->a[i].dstAccessMask); + Sys_Printf (" dependencyFlags: %x\n", dependencies->a[i].dependencyFlags); + } + } VkRenderPassCreateInfo createInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 0, 0, attachments->size, attachments->a, diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 55798c185..b6512d041 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -155,11 +155,11 @@ static int parse_enum (const plfield_t *field, const plitem_t *item, ectx.symtab = enm->symtab; ectx.result = &result; const char *valstr = PL_String (item); - Sys_Printf ("parse_enum: %s %zd %d %p %p %s\n", - field->name, field->offset, field->type, field->parser, - field->data, valstr); + //Sys_Printf ("parse_enum: %s %zd %d %p %p %s\n", + // field->name, field->offset, field->type, field->parser, + // field->data, valstr); ret = !cexpr_parse_enum (enm, valstr, &ectx, data); - Sys_Printf (" %d\n", *(int *)data); + //Sys_Printf (" %d\n", *(int *)data); return ret; } diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index b0d285ed6..ee0a209a1 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -117,7 +117,7 @@ Vulkan_Init_Cvars (void) CVAR_NONE, vulkan_presentation_mode_f, "desired presentation mode (may fall " "back to fifo)."); - msaaSamples = Cvar_Get ("msaaSamples", "VK_SAMPLE_COUNT_1_BIT", + msaaSamples = Cvar_Get ("msaaSamples", "VK_SAMPLE_COUNT_8_BIT", CVAR_NONE, msaaSamples_f, "desired MSAA sample size."); } @@ -366,72 +366,7 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) ctx->renderpass.colorImage = colorImage; ctx->renderpass.depthImage = depthImage; - - __auto_type attachments = QFV_AllocAttachmentDescription (3, alloca); - __auto_type attachmentRefs = QFV_AllocAttachmentReference (3, alloca); - - // color attachment - attachments->a[0].flags = 0; - attachments->a[0].format = sc->format; - attachments->a[0].samples = msaaSamples; - attachments->a[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachments->a[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments->a[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments->a[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments->a[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachments->a[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachmentRefs->a[0].attachment = 0; - attachmentRefs->a[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - // depth attachment - attachments->a[1].flags = 0; - attachments->a[1].format = depthFormat; - attachments->a[1].samples = msaaSamples; - attachments->a[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachments->a[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments->a[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments->a[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments->a[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachments->a[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachmentRefs->a[1].attachment = 1; - attachmentRefs->a[1].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - // resolve attachment - attachments->a[2].flags = 0; - attachments->a[2].format = sc->format; - attachments->a[2].samples = VK_SAMPLE_COUNT_1_BIT; - attachments->a[2].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments->a[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments->a[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments->a[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments->a[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachments->a[2].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - attachmentRefs->a[2].attachment = 2; - attachmentRefs->a[2].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - __auto_type subpasses = QFV_AllocSubpassParametersSet (1, alloca); - subpasses->a[0].flags = 0; - subpasses->a[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpasses->a[0].inputAttachmentCount = 0; - subpasses->a[0].pInputAttachments = 0; - subpasses->a[0].colorAttachmentCount = 1; - subpasses->a[0].pColorAttachments = &attachmentRefs->a[0]; - subpasses->a[0].pResolveAttachments = &attachmentRefs->a[2]; - subpasses->a[0].pDepthStencilAttachment = &attachmentRefs->a[1]; - subpasses->a[0].preserveAttachmentCount = 0; - subpasses->a[0].pPreserveAttachments = 0; - - __auto_type depenencies = QFV_AllocSubpassDependencies (1, alloca); - depenencies->a[0].srcSubpass = VK_SUBPASS_EXTERNAL; - depenencies->a[0].dstSubpass = 0; - depenencies->a[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - depenencies->a[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - depenencies->a[0].srcAccessMask = 0; - depenencies->a[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - depenencies->a[0].dependencyFlags = 0; - - ctx->renderpass.renderpass = QFV_CreateRenderPass (device, attachments, - subpasses, depenencies); + ctx->renderpass.renderpass = QFV_ParseRenderPass (ctx, item); } void From 79f22ffebfb6c698624100b4383fab8ef285e454 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 21 Dec 2020 20:15:43 +0900 Subject: [PATCH 137/435] [util] Propagate cexpr errors back to the caller Not much point in error detection when it's ignored. --- include/QF/cexpr.h | 1 + libs/util/cexpr-lex.l | 7 +++++-- libs/util/cexpr-vars.c | 3 +-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index fcdeaad57..7524dec0c 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -82,6 +82,7 @@ typedef struct exprctx_s { const struct plitem_s *item; struct plitem_s *messages; struct hashlink_s *hashlinks; + int errors; } exprctx_t; typedef struct exprenum_s { diff --git a/libs/util/cexpr-lex.l b/libs/util/cexpr-lex.l index cfb1b99c6..cdae1ee04 100644 --- a/libs/util/cexpr-lex.l +++ b/libs/util/cexpr-lex.l @@ -82,6 +82,8 @@ cexpr_error(exprctx_t *ctx, const char *fmt, ...) va_list args; dstring_t *string; + ctx->errors++; + string = dstring_new (); va_start (args, fmt); @@ -211,6 +213,7 @@ cexpr_eval_string (const char *str, exprctx_t *context) yylex_init_extra (context, &scanner); yy_scan_string (str, scanner); + context->errors = 0; do { CEXPR_YYSTYPE lval; int token = yylex (&lval, scanner); @@ -219,7 +222,7 @@ cexpr_eval_string (const char *str, exprctx_t *context) yylex_destroy (scanner); cexpr_yypstate_delete (ps); - return status; + return status || context->errors; } static exprval_t *parse_int (const char *str, exprctx_t *context) @@ -271,7 +274,7 @@ parse_variable (const char *name, exprctx_t *context) if (sym) { val = cexpr_value_reference (sym->type, sym->value, context); } else { - val = cexpr_cvar (name, context); + //val = cexpr_cvar (name, context); } } if (!val) { diff --git a/libs/util/cexpr-vars.c b/libs/util/cexpr-vars.c index 9f01e3134..6ec8ce3d9 100644 --- a/libs/util/cexpr-vars.c +++ b/libs/util/cexpr-vars.c @@ -34,7 +34,6 @@ #include "QF/cmem.h" #include "QF/cvar.h" #include "QF/hash.h" -#include "QF/qfplist.h" #include "libs/util/cexpr-parse.h" @@ -65,7 +64,7 @@ cvar_get (const exprval_t *a, const exprval_t *b, exprval_t *c, exprctx_t *ctx) __auto_type name = (const char *) b->value; exprval_t *var = cexpr_cvar (name, ctx); if (!var) { - PL_Message (ctx->messages, ctx->item, "unknown cvar %s", name); + cexpr_error (ctx, "unknown cvar %s", name); } *(exprval_t **) c->value = var; } From 80aec45e35b5f7704dd65f7b39104ef80b1e48ca Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 21 Dec 2020 20:17:27 +0900 Subject: [PATCH 138/435] [vulkan] Ensure msaa settings are consistent I had forgotten that msaa samples was governed by the driver (as a max) and the renderpass setup code simply took the max. Thus why 1 vs 8 caused the display to render incorrectly. --- include/vid_vulkan.h | 1 + libs/video/renderer/vulkan/qfpipeline.plist | 2 +- libs/video/renderer/vulkan/vkparse.c | 1 + libs/video/renderer/vulkan/vulkan_vid_common.c | 10 +++++----- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 411fcf4db..1886730c6 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -41,6 +41,7 @@ typedef struct vulkan_ctx_s { struct qfv_instance_s *instance; struct qfv_device_s *device; struct qfv_swapchain_s *swapchain; + VkSampleCountFlagBits msaaSamples; // FIXME not here? struct hashlink_s *hashlinks; //FIXME want per thread VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index a8e1c36c9..66c9e0adb 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -15,7 +15,7 @@ { flags = 0; format = VK_FORMAT_D32_SFLOAT; - samples = $cvars.msaaSamples; + samples = $msaaSamples; loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index b6512d041..b62637796 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -275,6 +275,7 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) VkRenderPass renderpass; exprsym_t var_syms[] = { {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, + {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, {} }; exprtab_t vars_tab = { var_syms, 0 }; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index ee0a209a1..9c2b021f4 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -117,7 +117,7 @@ Vulkan_Init_Cvars (void) CVAR_NONE, vulkan_presentation_mode_f, "desired presentation mode (may fall " "back to fifo)."); - msaaSamples = Cvar_Get ("msaaSamples", "VK_SAMPLE_COUNT_8_BIT", + msaaSamples = Cvar_Get ("msaaSamples", "VK_SAMPLE_COUNT_1_BIT", CVAR_NONE, msaaSamples_f, "desired MSAA sample size."); } @@ -284,13 +284,13 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) VkExtent3D extent = {sc->extent.width, sc->extent.height, 1}; - VkSampleCountFlagBits msaaSamples - = QFV_GetMaxSampleCount (device->physDev); + //FIXME incorporate cvar setting + ctx->msaaSamples = QFV_GetMaxSampleCount (device->physDev); Sys_MaskPrintf (SYS_VULKAN, "color resource\n"); colorImage->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, - sc->format, extent, 1, 1, msaaSamples, + sc->format, extent, 1, 1, ctx->msaaSamples, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); colorImage->object @@ -308,7 +308,7 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) VkFormat depthFormat = VK_FORMAT_D32_SFLOAT; depthImage->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, - depthFormat, extent, 1, 1, msaaSamples, + depthFormat, extent, 1, 1, ctx->msaaSamples, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); depthImage->object = QFV_AllocImageMemory (device, depthImage->image, From 91c5baa7089741c9a9e7746004058f2572ee5fd6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 23 Dec 2020 14:06:20 +0900 Subject: [PATCH 139/435] [util] Add size_t support to cexpr --- include/QF/cexpr.h | 1 + libs/util/cexpr-type.c | 46 ++++++++++++++++++++++ libs/video/renderer/vulkan/vkgen/vkalias.r | 7 +++- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index 7524dec0c..0d2b4a8a4 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -109,6 +109,7 @@ char *cexpr_yyget_text (void *scanner); extern exprtype_t cexpr_int; extern exprtype_t cexpr_uint; +extern exprtype_t cexpr_size_t; extern exprtype_t cexpr_float; extern exprtype_t cexpr_double; extern exprtype_t cexpr_exprval; diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index 35c62ee85..c0610b13d 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -160,6 +160,52 @@ exprtype_t cexpr_uint = { uint_unops, }; +BINOP(size_t, shl, unsigned, <<) +BINOP(size_t, shr, unsigned, >>) +BINOP(size_t, add, unsigned, +) +BINOP(size_t, sub, unsigned, -) +BINOP(size_t, mul, unsigned, *) +BINOP(size_t, div, unsigned, /) +BINOP(size_t, band, unsigned, &) +BINOP(size_t, bor, unsigned, |) +BINOP(size_t, xor, unsigned, ^) +BINOP(size_t, rem, unsigned, %) + +UNOP(size_t, pos, unsigned, +) +UNOP(size_t, neg, unsigned, -) +UNOP(size_t, tnot, unsigned, !) +UNOP(size_t, bnot, unsigned, ~) + +binop_t size_t_binops[] = { + { SHL, &cexpr_size_t, &cexpr_size_t, size_t_shl }, + { SHR, &cexpr_size_t, &cexpr_size_t, size_t_shr }, + { '+', &cexpr_size_t, &cexpr_size_t, size_t_add }, + { '-', &cexpr_size_t, &cexpr_size_t, size_t_sub }, + { '*', &cexpr_size_t, &cexpr_size_t, size_t_mul }, + { '/', &cexpr_size_t, &cexpr_size_t, size_t_div }, + { '&', &cexpr_size_t, &cexpr_size_t, size_t_band }, + { '|', &cexpr_size_t, &cexpr_size_t, size_t_bor }, + { '^', &cexpr_size_t, &cexpr_size_t, size_t_xor }, + { '%', &cexpr_size_t, &cexpr_size_t, size_t_rem }, + { MOD, &cexpr_size_t, &cexpr_size_t, size_t_rem }, + {} +}; + +unop_t size_t_unops[] = { + { '+', &cexpr_size_t, size_t_pos }, + { '-', &cexpr_size_t, size_t_neg }, + { '!', &cexpr_size_t, size_t_tnot }, + { '~', &cexpr_size_t, size_t_bnot }, + {} +}; + +exprtype_t cexpr_size_t = { + "size_t", + sizeof (size_t), + size_t_binops, + size_t_unops, +}; + BINOP(float, add, float, +) BINOP(float, sub, float, -) BINOP(float, mul, float, *) diff --git a/libs/video/renderer/vulkan/vkgen/vkalias.r b/libs/video/renderer/vulkan/vkgen/vkalias.r index 132e6291a..be783b207 100644 --- a/libs/video/renderer/vulkan/vkgen/vkalias.r +++ b/libs/video/renderer/vulkan/vkgen/vkalias.r @@ -65,6 +65,9 @@ if (name == "uint32_t") { return "cexpr_uint"; } + if (name == "size_t") { + return "cexpr_size_t"; + } return [alias cexprType]; } @@ -80,7 +83,7 @@ return [enumObj parseType]; } } - if (name == "uint32_t") { + if (name == "uint32_t" || name == "size_t") { return "QFString"; } return [alias parseType]; @@ -116,7 +119,7 @@ return [enumObj parseData]; } } - if (name == "uint32_t") { + if (name == "uint32_t" || name == "size_t") { return "0"; } return [alias parseData]; From 5864b553ef95cdff5c3e038d32ff7441b9982f17 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 23 Dec 2020 14:07:30 +0900 Subject: [PATCH 140/435] [util] Add accessors for binary plist objects --- include/QF/qfplist.h | 17 +++++++++++++++++ libs/util/qfplist.c | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 70a1b8302..1d45426d2 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -141,6 +141,23 @@ pltype_t PL_Type (const plitem_t *item) __attribute__((pure)); */ int PL_Line (const plitem_t *item) __attribute__((pure)); +/** Retrieve the data size from a binary object. + + \param binary The binary object + \return the size in bytes of the binary object 0 if binary isn't a binary + object. +*/ +size_t PL_BinarySize (const plitem_t *item) __attribute__((pure)); + +/** Retrieve the data from a binary object. + + \param binary The binary object + \return pointer to the actual data or NULL if binary isn't a binary object. + \note You are NOT responsible for freeing the returned object. It will + be destroyed when its container is. +*/ +const void *PL_BinaryData (const plitem_t *binary) __attribute__((pure)); + /** Retrieve a string from a string object. \param string The string object diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 2f71d42bc..b33d22084 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -231,6 +231,26 @@ PL_Free (plitem_t *item) free (item); } +VISIBLE size_t +PL_BinarySize (const plitem_t *binary) +{ + plbinary_t *bin = (plbinary_t *) binary->data; + + if (binary->type != QFBinary) + return 0; + return bin->size; +} + +VISIBLE const void * +PL_BinaryData (const plitem_t *binary) +{ + plbinary_t *bin = (plbinary_t *) binary->data; + + if (binary->type != QFBinary) + return 0; + return bin->data; +} + VISIBLE const char * PL_String (const plitem_t *string) { From f1848bb5b77299bdbf487fb86122ea520616d397 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 23 Dec 2020 14:08:53 +0900 Subject: [PATCH 141/435] [vulkan] Add support for parsing binary data --- libs/video/renderer/vulkan/vkgen/vkstruct.r | 34 ++++++++++++++++----- libs/video/renderer/vulkan/vkparse.c | 29 ++++++++++++++++++ 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index 4c9040cb6..6e6908bb8 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -80,14 +80,17 @@ field_type = [[Type lookup: type_type] dereference]; fprintf (output_file, "static parse_%s_t parse_%s_%s_data = {\n", type_record, name, field_name); - fprintf (output_file, "\t%s,\n", [field_type parseType]); - fprintf (output_file, "\tsizeof (%s),\n", type_type); - fprintf (output_file, "\tparse_%s,\n", type_type); if (type_record == "single") { + fprintf (output_file, "\t%s,\n", [field_type parseType]); + fprintf (output_file, "\tsizeof (%s),\n", type_type); + fprintf (output_file, "\tparse_%s,\n", type_type); value_field = [[field_def getObjectForKey:"value"] string]; fprintf (output_file, "\tfield_offset (%s, %s),\n", name, value_field); - } else { + } else if (type_record == "array") { + fprintf (output_file, "\t%s,\n", [field_type parseType]); + fprintf (output_file, "\tsizeof (%s),\n", type_type); + fprintf (output_file, "\tparse_%s,\n", type_type); value_field = [[field_def getObjectForKey:"values"] string]; size_field = [[field_def getObjectForKey:"size"] string]; fprintf (output_file, "\tfield_offset (%s, %s),\n", @@ -98,6 +101,19 @@ } else { fprintf (output_file, "\t-1,\n"); } + } else if (type_record == "data") { + value_field = [[field_def getObjectForKey:"data"] string]; + size_field = [[field_def getObjectForKey:"size"] string]; + fprintf (output_file, "\tfield_offset (%s, %s),\n", + name, value_field); + if (size_field) { + fprintf (output_file, "\tfield_offset (%s, %s),\n", + name, size_field); + } else { + fprintf (output_file, "\t-1,\n"); + } + } else { + fprintf (output_file, "\tno type,\n"); } fprintf (output_file, "};\n"); } @@ -128,7 +144,7 @@ PLItem *type_desc = [field_def getObjectForKey:"type"]; string type_record; string type_type; - string parseType; + string parseType = "no type"; type_record = [[type_desc getObjectAtIndex:0] string]; type_type = [[type_desc getObjectAtIndex:1] string]; @@ -136,8 +152,10 @@ field_type = [[Type lookup: type_type] dereference]; if (type_record == "single") { parseType = [field_type parseType]; - } else { + } else if (type_record == "array") { parseType = "QFArray"; + } else if (type_record == "data") { + parseType = "QFBinary"; } fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", @@ -208,8 +226,10 @@ type_record = [[type_desc getObjectAtIndex:0] string]; if (type_record == "single") { value_field = [[field_def getObjectForKey:"value"] string]; - } else { + } else if (type_record == "array") { value_field = [[field_def getObjectForKey:"values"] string]; + } else if (type_record == "data") { + value_field = [[field_def getObjectForKey:"data"] string]; } if (!value_field) { value_field = field_name; diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index b62637796..fbe46d512 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -117,6 +117,11 @@ typedef struct parse_array_s { size_t size_offset; } parse_array_t; +typedef struct parse_data_s { + size_t value_offset; + size_t size_offset; +} parse_data_t; + static int parse_uint32_t (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context) { @@ -224,6 +229,30 @@ static int parse_array (const plfield_t *field, const plitem_t *item, return 1; } +static int parse_data (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type datad = (parse_data_t *) field->data; + __auto_type value = (void **) ((byte *)data + datad->value_offset); + __auto_type size = (size_t *) ((byte *)data + datad->size_offset); + + const void *bindata = PL_BinaryData (item); + size_t binsize = PL_BinarySize (item); + + Sys_Printf ("parse_array: %s %zd %d %p %p %p\n", + field->name, field->offset, field->type, field->parser, + field->data, data); + Sys_Printf (" %zd %zd\n", datad->value_offset, datad->size_offset); + Sys_Printf (" %zd %p\n", binsize, bindata); + + *value = malloc (binsize); + memcpy (*value, bindata, binsize); + if ((void *) size > data) { + *size = binsize; + } + return 1; +} + #include "libs/video/renderer/vulkan/vkparse.cinc" typedef struct qfv_renderpass_s { From 7fb335a21559f3944b259111521e0470a2ea2677 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 23 Dec 2020 14:32:29 +0900 Subject: [PATCH 142/435] [vulkan] Add support for building and loading shaders Shaders can be built as spv files and installed into $libdir/quakeforge/shaders or as spvc files and compiled into the engine. Loading supports $builtin/name to access builtin shaders, $shader/path to access external standard shaders and quake filesystem access for all other paths. --- Makefile.am | 22 +++ config.d/paths.m4 | 13 ++ config.d/vulkan.m4 | 1 + include/QF/Vulkan/shader.h | 13 ++ include/vid_vulkan.h | 2 + libs/video/renderer/Makemodule.am | 42 ++++- libs/video/renderer/vulkan/passthrough.vert | 8 + libs/video/renderer/vulkan/pushcolor.frag | 12 ++ libs/video/renderer/vulkan/shader.c | 192 ++++++++++++++++++++ 9 files changed, 296 insertions(+), 9 deletions(-) create mode 100644 include/QF/Vulkan/shader.h create mode 100644 libs/video/renderer/vulkan/passthrough.vert create mode 100644 libs/video/renderer/vulkan/pushcolor.frag create mode 100644 libs/video/renderer/vulkan/shader.c diff --git a/Makefile.am b/Makefile.am index 71e429956..b59b21eb7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -107,6 +107,27 @@ qcautodep = $(join $(addsuffix $(DEPDIR)/,$(dir $(basename $(1)))),$(addsuffix . r_depfiles_remade= pas_depfiles_remade= +V_GLSLANG = $(V_GLSLANG_@AM_V@) +V_GLSLANG_ = $(V_GLSLANG_@AM_DEFAULT_V@) +V_GLSLANG_0 = @echo " GLSLANG " $@; +V_GLSLANG_1 = + +V_XXD = $(V_XXD_@AM_V@) +V_XXD_ = $(V_XXD_@AM_DEFAULT_V@) +V_XXD_0 = @echo " XXD " $@; +V_XXD_1 = + +%.spv: % + @$(mkdir_p) $(builddir)/`dirname $@` + $(V_GLSLANG)$(GLSLANGVALIDATOR) -V $< -o $@ > /dev/null + +%.spvc: % + @$(mkdir_p) $(builddir)/`dirname $@` + $(V_GLSLANG)$(GLSLANGVALIDATOR) --vn `basename $< | tr . _` -V $< -o $@ > /dev/null + +shaderdir = @shaderdir@ +shader_DATA = + include doc/Makemodule.am include RPM/Makemodule.am include debian/Makemodule.am @@ -122,6 +143,7 @@ include tools/Makemodule.am include ruamoko/Makemodule.am DISTCLEANFILES += $(r_depfiles_remade) $(pas_depfiles_remade) +CLEANFILES += $(shader_DATA) $(r_depfiles_remade): $(MKDIR_P) $(@D) diff --git a/config.d/paths.m4 b/config.d/paths.m4 index f340eda78..c5ce432ce 100644 --- a/config.d/paths.m4 +++ b/config.d/paths.m4 @@ -98,6 +98,19 @@ eval expanded_plugindir="$expanded_plugindir" AC_DEFINE_UNQUOTED(FS_PLUGINPATH, "$expanded_plugindir", [Define this to the path from which to load plugins]) AC_SUBST(plugindir) +SHADERDIR="\${libdir}/quakeforge/shaders" +if test "x$shaderdir" = "xauto" -o "x$shaderdir" = "xyes" -o "x$shaderdir" = "x"; then + shaderdir="$SHADERDIR" +elif test "x$shaderdir" = xno; then + shaderdir="." +else + SHADERDIR="$shaderdir" +fi +eval expanded_shaderdir="$shaderdir" +eval expanded_shaderdir="$expanded_shaderdir" +AC_DEFINE_UNQUOTED(FS_SHADERPATH, "$expanded_shaderdir", [Define this to the path from which to load shaders]) +AC_SUBST(plugindir) + AC_ARG_WITH(gl-driver, [ --with-gl-driver=NAME Name of OpenGL driver DLL/DSO], gl_driver=$withval, diff --git a/config.d/vulkan.m4 b/config.d/vulkan.m4 index 4c9df43f4..0c780e98a 100644 --- a/config.d/vulkan.m4 +++ b/config.d/vulkan.m4 @@ -16,5 +16,6 @@ if test "x$HAVE_VULKAN" = xyes; then AC_DEFINE([HAVE_VULKAN], [1], [Define if yhou have the Vulkan libs]) fi AC_SUBST(VULKAN_LIBS) +AC_SUBST(GLSLANGVALIDATOR, [$glslangvalidator]) AM_CONDITIONAL(X11_VULKAN, test "x$HAVE_VULKAN" = "xyes") diff --git a/include/QF/Vulkan/shader.h b/include/QF/Vulkan/shader.h new file mode 100644 index 000000000..6b8321cdd --- /dev/null +++ b/include/QF/Vulkan/shader.h @@ -0,0 +1,13 @@ +#ifndef __QF_Vulkan_shader_h +#define __QF_Vulkan_shader_h + +struct qfv_device_s; +struct vulkan_ctx_s; + +VkShaderModule QFV_CreateShaderModule (struct qfv_device_s *device, + const char *path); +void QFV_RegisterShaderModule (struct vulkan_ctx_s *ctx, const char *name, + VkShaderModule module); +void QFV_DeregisterShaderModule (struct vulkan_ctx_s *ctx, const char *name); + +#endif//__QF_Vulkan_shader_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 1886730c6..5eb2dd157 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -44,6 +44,8 @@ typedef struct vulkan_ctx_s { VkSampleCountFlagBits msaaSamples; // FIXME not here? struct hashlink_s *hashlinks; //FIXME want per thread VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain + struct hashtab_s *shadermodules; + struct shadermodule_s *shadermodule_freelist; VkCommandPool cmdpool; VkCommandBuffer cmdbuffer; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index e2b71bf07..b5ca83cf5 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -78,7 +78,7 @@ V_SED_ = $(V_SED_@AM_DEFAULT_V@) V_SED_0 = @echo " SED " $@; V_SED_1 = -SUFFICES=.frag .vert .fc .vc .slc .glsl .plist .plc +SUFFICES=.frag .vert .spv .spvc .fc .vc .slc .glsl .plist .plc .glsl.slc: $(V_SED)sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@.t &&\ $(am__mv) $@.t $@ @@ -224,6 +224,7 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/namehack.h \ libs/video/renderer/vulkan/pipeline.c \ libs/video/renderer/vulkan/renderpass.c \ + libs/video/renderer/vulkan/shader.c \ libs/video/renderer/vulkan/swapchain.c \ libs/video/renderer/vulkan/util.c \ libs/video/renderer/vulkan/util.h \ @@ -233,29 +234,44 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/vkparse.lo: libs/video/renderer/vulkan/vkparse.c $(vkparse_src) -libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c ${vkparse_src} $(pipeline_gen) +libs/video/renderer/vulkan/shader.lo: libs/video/renderer/vulkan/shader.c $(vkshader_c) + +libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c $(vkparse_src) $(pipeline_gen) qwaq_curses = ruamoko/qwaq/qwaq-curses$(EXEEXT) vkparse_cinc = libs/video/renderer/vulkan/vkparse.cinc vkparse_hinc = libs/video/renderer/vulkan/vkparse.hinc vkparse_src = \ - ${vkparse_cinc} \ - ${vkparse_hinc} + $(vkparse_cinc) \ + $(vkparse_hinc) vkparse_plist = \ $(srcdir)/libs/video/renderer/vulkan/vkparse.plist +passthrough_src = libs/video/renderer/vulkan/passthrough.vert +passthrough_c = libs/video/renderer/vulkan/passthrough.vert.spvc +pushcolor_src = libs/video/renderer/vulkan/pushcolor.frag +pushcolor_c = libs/video/renderer/vulkan/pushcolor.frag.spvc + +$(passthrough_c): $(passthrough_src) + +$(pushcolor_c): $(pushcolor_src) + +vkshader_c = \ + $(passthrough_c) \ + $(pushcolor_c) + V_VKGEN = $(V_VKGEN_@AM_V@) V_VKGEN_ = $(V_VKGEN_@AM_DEFAULT_V@) V_VKGEN_0 = @echo " VKGEN " $@; V_VKGEN_1 = -${vkparse_cinc}: $(vkgen) $(qwaq_curses) $(vkparse_plist) - $(V_VKGEN)$(qwaq_curses) $(vkgen) -- $(vkparse_plist) ${vkparse_cinc}.t ${vkparse_hinc}.t &&\ - $(am__mv) ${vkparse_cinc}.t ${vkparse_cinc} &&\ - $(am__mv) ${vkparse_hinc}.t ${vkparse_hinc} +$(vkparse_cinc): $(vkgen) $(qwaq_curses) $(vkparse_plist) + $(V_VKGEN)$(qwaq_curses) $(vkgen) -- $(vkparse_plist) $(vkparse_cinc).t $(vkparse_hinc).t &&\ + $(am__mv) $(vkparse_cinc).t $(vkparse_cinc) &&\ + $(am__mv) $(vkparse_hinc).t $(vkparse_hinc) -${vkparse_hinc}: ${vkparse_cinc} +$(vkparse_hinc): $(vkparse_cinc) # do nothing: hinc generated at the same time as cinc CLEANFILES += \ @@ -263,7 +279,15 @@ CLEANFILES += \ libs/video/renderer/glsl/*.fc \ libs/video/renderer/glsl/*.slc \ libs/video/renderer/vulkan/*.plc \ + libs/video/renderer/vulkan/*.spv \ + libs/video/renderer/vulkan/*.spvc \ libs/video/renderer/vulkan/vkgen.sym \ $(vkparse_src) BUILT_SOURCES += $(shader_gen) + +#shader_DATA += \ +# libs/video/renderer/vulkan/passthrough.vert.spv \ +# libs/video/renderer/vulkan/pushcolor.frag.spv + +EXTRA_DIST += $(shader_DATA:.spv=) diff --git a/libs/video/renderer/vulkan/passthrough.vert b/libs/video/renderer/vulkan/passthrough.vert new file mode 100644 index 000000000..0283a53b3 --- /dev/null +++ b/libs/video/renderer/vulkan/passthrough.vert @@ -0,0 +1,8 @@ +#version 450 + +layout (location = 0) in vec4 app_position; + +void main() +{ + gl_Position = app_position; +} diff --git a/libs/video/renderer/vulkan/pushcolor.frag b/libs/video/renderer/vulkan/pushcolor.frag new file mode 100644 index 000000000..d19413fe1 --- /dev/null +++ b/libs/video/renderer/vulkan/pushcolor.frag @@ -0,0 +1,12 @@ +#version 450 + +layout (location = 0) out vec4 frag_color; + +layout (push_constant) uniform ColorBlock { + vec4 Color; +} PushConstant; + +void main() +{ + frag_color = PushConstant.Color; +} diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c new file mode 100644 index 000000000..704e01996 --- /dev/null +++ b/libs/video/renderer/vulkan/shader.c @@ -0,0 +1,192 @@ +/* + shader.c + + Vulkan shader manager + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/renderpass.h" +#include "QF/Vulkan/shader.h" + +#include "vid_vulkan.h" + +static +#include "libs/video/renderer/vulkan/passthrough.vert.spvc" +static +#include "libs/video/renderer/vulkan/pushcolor.frag.spvc" + +typedef struct shaderdata_s { + const char *name; + const uint32_t *data; + size_t size; +} shaderdata_t; + +typedef struct shadermodule_s { + char *name; + union { + VkShaderModule module; + struct shadermodule_s *next; + }; +} shadermodule_t; + +static shaderdata_t builtin_shaders[] = { + { "passthrough.vert", passthrough_vert, sizeof (passthrough_vert) }, + { "pushcolor.frag", pushcolor_frag, sizeof (pushcolor_frag) }, + {} +}; + +#define BUILTIN "$builtin/" +#define BUILTIN_SIZE (sizeof (BUILTIN) - 1) +#define SHADER "$shader/" +#define SHADER_SIZE (sizeof (SHADER) - 1) + +VkShaderModule +QFV_CreateShaderModule (qfv_device_t *device, const char *shader_path) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + shaderdata_t _data = {}; + shaderdata_t *data = 0; + dstring_t *path = 0; + QFile *file; + VkShaderModule shader = 0; + + if (strncmp (shader_path, BUILTIN, BUILTIN_SIZE) == 0) { + const char *name = shader_path + BUILTIN_SIZE; + + for (int i = 0; builtin_shaders[i].name; i++) { + if (strcmp (builtin_shaders[i].name, name) == 0) { + data = &builtin_shaders[i]; + break; + } + } + } else if (strncmp (shader_path, SHADER, SHADER_SIZE)) { + path = dstring_new (); + dsprintf (path, "%s/%s", FS_SHADERPATH, shader_path + SHADER_SIZE); + file = Qopen (path->str, "rbz"); + } else { + file = QFS_FOpenFile (shader_path); + } + + if (file) { + _data.size = Qfilesize (file); + _data.data = malloc (_data.size); + Qread (file, (void *) _data.data, _data.size); + Qclose (file); + data = &_data; + } + + if (data) { + VkShaderModuleCreateInfo createInfo = { + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0, + 0, data->size, data->data + }; + + dfunc->vkCreateShaderModule (dev, &createInfo, 0, &shader); + } else { + Sys_MaskPrintf (SYS_VULKAN, + "QFV_CreateShaderModule: could not find shader %s\n", + shader_path); + } + + if (path) { + dstring_delete (path); + } + if (_data.data) { + free ((void *) _data.data); + } + return shader; +} + +static shadermodule_t * +new_module (vulkan_ctx_t *ctx) +{ + shadermodule_t *shadermodule; + ALLOC (128, shadermodule_t, ctx->shadermodule, shadermodule); + return shadermodule; +} + +static void +del_module (shadermodule_t *shadermodule, vulkan_ctx_t *ctx) +{ + free (shadermodule->name); + FREE (ctx->shadermodule, shadermodule); +} + +static const char * +sm_getkey (const void *sm, void *unused) +{ + return ((shadermodule_t *) sm)->name; +} + +static void +sm_free (void *sm, void *ctx) +{ + del_module (sm, ctx); +} + +void +QFV_RegisterShaderModule (vulkan_ctx_t *ctx, const char *name, + VkShaderModule module) +{ + if (!ctx->shadermodules) { + ctx->shadermodules = Hash_NewTable (127, sm_getkey, sm_free, ctx, 0); + } + shadermodule_t *shadermodule = new_module (ctx); + shadermodule->name = strdup (name); + shadermodule->module = module; + Hash_Add (ctx->shadermodules, shadermodule); +} + +void +QFV_DeregisterShaderModule (vulkan_ctx_t *ctx, const char *name) +{ + if (!ctx->shadermodules) { + return; + } + Hash_Free (ctx->shadermodules, Hash_Del (ctx->shadermodules, name)); +} From e1e2a0e71263022def45eba305a312ba98fe6912 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 23 Dec 2020 21:52:42 +0900 Subject: [PATCH 143/435] [ruamoko] Add a wrapper for PL_Line Makes error reporting in rua code easier. --- libs/ruamoko/rua_plist.c | 10 ++++++++++ ruamoko/include/PropertyList.h | 1 + ruamoko/include/plist.h | 1 + ruamoko/lib/PropertyList.r | 5 +++++ ruamoko/lib/plist.r | 1 + 5 files changed, 18 insertions(+) diff --git a/libs/ruamoko/rua_plist.c b/libs/ruamoko/rua_plist.c index b71af2ead..d45ee1b8d 100644 --- a/libs/ruamoko/rua_plist.c +++ b/libs/ruamoko/rua_plist.c @@ -229,6 +229,15 @@ bi_PL_Type (progs_t *pr) R_INT (pr) = PL_Type (plist->plitem); } +static void +bi_PL_Line (progs_t *pr) +{ + int handle = P_INT (pr, 0); + bi_plist_t *plist = get_plist (pr, __FUNCTION__, handle); + + R_INT (pr) = PL_Line (plist->plitem); +} + static void bi_PL_String (progs_t *pr) { @@ -432,6 +441,7 @@ static builtin_t builtins[] = { {"PL_GetPropertyList", bi_PL_GetPropertyList, -1}, {"PL_WritePropertyList", bi_PL_WritePropertyList, -1}, {"PL_Type", bi_PL_Type, -1}, + {"PL_Line", bi_PL_Line, -1}, {"PL_String", bi_PL_String, -1}, {"PL_ObjectForKey", bi_PL_ObjectForKey, -1}, {"PL_RemoveObjectForKey", bi_PL_RemoveObjectForKey, -1}, diff --git a/ruamoko/include/PropertyList.h b/ruamoko/include/PropertyList.h index c0c4bed35..d2494a94a 100644 --- a/ruamoko/include/PropertyList.h +++ b/ruamoko/include/PropertyList.h @@ -42,6 +42,7 @@ - initWithOwnItem:(plitem_t) item; - (string) write; - (pltype_t) type; +- (int) line; @end @interface PLDictionary: PLItem diff --git a/ruamoko/include/plist.h b/ruamoko/include/plist.h index 4544e00ff..bfaa25516 100644 --- a/ruamoko/include/plist.h +++ b/ruamoko/include/plist.h @@ -10,6 +10,7 @@ typedef enum {QFDictionary, QFArray, QFBinary, QFString} pltype_t; // possible t @extern plitem_t PL_GetPropertyList (string str); @extern string PL_WritePropertyList (plitem_t pl); @extern pltype_t PL_Type (plitem_t str); +@extern int PL_Line (plitem_t str); @extern string PL_String (plitem_t str); @extern plitem_t PL_ObjectForKey (plitem_t item, string key); @extern plitem_t PL_RemoveObjectForKey (plitem_t item, string key); diff --git a/ruamoko/lib/PropertyList.r b/ruamoko/lib/PropertyList.r index b8469e473..c6df13070 100644 --- a/ruamoko/lib/PropertyList.r +++ b/ruamoko/lib/PropertyList.r @@ -94,6 +94,11 @@ return PL_Type (item); } +- (int) line +{ + return PL_Line (item); +} + - (int) count { if ([self class] == [PLDictionary class]) { diff --git a/ruamoko/lib/plist.r b/ruamoko/lib/plist.r index 40ab2e1fc..34f0ce6c1 100644 --- a/ruamoko/lib/plist.r +++ b/ruamoko/lib/plist.r @@ -4,6 +4,7 @@ plitem_t PL_GetFromFile (QFile file) = #0; plitem_t PL_GetPropertyList (string str) = #0; string PL_WritePropertyList (plitem_t pl) = #0; pltype_t PL_Type (plitem_t str) = #0; +int PL_Line (plitem_t str) = #0; string PL_String (plitem_t str) = #0; plitem_t PL_ObjectForKey (plitem_t item, string key) = #0; plitem_t PL_RemoveObjectForKey (plitem_t item, string key) = #0; From 017d2c1f4453daa7802e031958fab96a9ef7316d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 23 Dec 2020 22:13:50 +0900 Subject: [PATCH 144/435] [vulkan] Refactor vkgen struct generation The addition of data an then string support made keeping track of things in struct's writeTable a nightmare. --- .../video/renderer/vulkan/vkgen/Makemodule.am | 6 + libs/video/renderer/vulkan/vkgen/vkenum.h | 2 +- libs/video/renderer/vulkan/vkgen/vkenum.r | 2 +- .../renderer/vulkan/vkgen/vkfieldarray.h | 12 + .../renderer/vulkan/vkgen/vkfieldarray.r | 52 ++++ .../video/renderer/vulkan/vkgen/vkfieldauto.h | 9 + .../video/renderer/vulkan/vkgen/vkfieldauto.r | 43 ++++ .../video/renderer/vulkan/vkgen/vkfielddata.h | 9 + .../video/renderer/vulkan/vkgen/vkfielddata.r | 45 ++++ libs/video/renderer/vulkan/vkgen/vkfielddef.h | 28 +++ libs/video/renderer/vulkan/vkgen/vkfielddef.r | 95 ++++++++ .../renderer/vulkan/vkgen/vkfieldsingle.h | 12 + .../renderer/vulkan/vkgen/vkfieldsingle.r | 46 ++++ .../renderer/vulkan/vkgen/vkfieldstring.h | 9 + .../renderer/vulkan/vkgen/vkfieldstring.r | 36 +++ libs/video/renderer/vulkan/vkgen/vkgen.h | 1 + libs/video/renderer/vulkan/vkgen/vkgen.r | 9 +- libs/video/renderer/vulkan/vkgen/vkstruct.h | 7 +- libs/video/renderer/vulkan/vkgen/vkstruct.r | 229 +++++------------- libs/video/renderer/vulkan/vkparse.c | 24 +- 20 files changed, 499 insertions(+), 177 deletions(-) create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldarray.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldarray.r create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldauto.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldauto.r create mode 100644 libs/video/renderer/vulkan/vkgen/vkfielddata.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkfielddata.r create mode 100644 libs/video/renderer/vulkan/vkgen/vkfielddef.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkfielddef.r create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldsingle.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldsingle.r create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldstring.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldstring.r diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am index 66971a2c3..31c22d936 100644 --- a/libs/video/renderer/vulkan/vkgen/Makemodule.am +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -4,6 +4,12 @@ noinst_PROGRAMS += $(vkgen) vkgen_dat_src= \ libs/video/renderer/vulkan/vkgen/vkalias.r \ libs/video/renderer/vulkan/vkgen/vkenum.r \ + libs/video/renderer/vulkan/vkgen/vkfieldarray.r \ + libs/video/renderer/vulkan/vkgen/vkfieldauto.r \ + libs/video/renderer/vulkan/vkgen/vkfielddata.r \ + libs/video/renderer/vulkan/vkgen/vkfielddef.r \ + libs/video/renderer/vulkan/vkgen/vkfieldsingle.r \ + libs/video/renderer/vulkan/vkgen/vkfieldstring.r \ libs/video/renderer/vulkan/vkgen/vkgen.r \ libs/video/renderer/vulkan/vkgen/vkstruct.r \ libs/video/renderer/vulkan/vkgen/vktype.r \ diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.h b/libs/video/renderer/vulkan/vkgen/vkenum.h index 6694c24cb..4df770b92 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.h +++ b/libs/video/renderer/vulkan/vkgen/vkenum.h @@ -10,7 +10,7 @@ int prefix_length; } -(void) writeTable; --(void) writeSymtabInit:(PLItem *) parse; +-(void) writeSymtabInit; @end #endif//__renderer_vulkan_vkgen_vkenum_h diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.r b/libs/video/renderer/vulkan/vkgen/vkenum.r index e3894902a..234c99b61 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.r +++ b/libs/video/renderer/vulkan/vkgen/vkenum.r @@ -123,7 +123,7 @@ skip_value(string name) fprintf (header_file, "extern exprenum_t %s_enum;\n", [self name]); } --(void) writeSymtabInit:(PLItem *) parse +-(void) writeSymtabInit { fprintf (output_file, "\tcexpr_init_symtab (&%s_symtab, context);\n", [self name]); diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldarray.h b/libs/video/renderer/vulkan/vkgen/vkfieldarray.h new file mode 100644 index 000000000..5cf31880b --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldarray.h @@ -0,0 +1,12 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldarray_h +#define __renderer_vulkan_vkgen_vkfieldarray_h + +#include "vkfielddef.h" + +@interface ArrayField: FieldDef +{ + string type; +} +@end + +#endif//__renderer_vulkan_vkgen_vkfieldarray_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldarray.r b/libs/video/renderer/vulkan/vkgen/vkfieldarray.r new file mode 100644 index 000000000..dd81dd9f4 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldarray.r @@ -0,0 +1,52 @@ +#include + +#include "vkfieldarray.h" +#include "vkgen.h" +#include "vktype.h" + +@implementation ArrayField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + + PLItem *desc = [item getObjectForKey:"type"]; + type = [[desc getObjectAtIndex:1] string]; + + value_field = [[item getObjectForKey:"values"] string]; + size_field = [[item getObjectForKey:"size"] string]; + return self; +} + +-writeParseData +{ + Type *field_type = [[Type lookup: type] dereference]; + + fprintf (output_file, "static parse_array_t parse_%s_%s_data = {\n", + struct_name, field_name); + fprintf (output_file, "\t%s,\n", [field_type parseType]); + fprintf (output_file, "\tsizeof (%s),\n", type); + fprintf (output_file, "\tparse_%s,\n", type); + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, value_field); + if (size_field) { + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, size_field); + } else { + fprintf (output_file, "\t-1,\n"); + } + fprintf (output_file, "};\n"); + return self; +} + +-writeField +{ + fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, "QFArray", "array", struct_name, field_name); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldauto.h b/libs/video/renderer/vulkan/vkgen/vkfieldauto.h new file mode 100644 index 000000000..a2e05deb8 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldauto.h @@ -0,0 +1,9 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldauto_h +#define __renderer_vulkan_vkgen_vkfieldauto_h + +#include "vkfielddef.h" + +@interface AutoField: FieldDef +@end + +#endif//__renderer_vulkan_vkgen_vkfieldauto_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldauto.r b/libs/video/renderer/vulkan/vkgen/vkfieldauto.r new file mode 100644 index 000000000..dab844c92 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldauto.r @@ -0,0 +1,43 @@ +#include "vkfieldauto.h" +#include "vkgen.h" +#include "vkstruct.h" + +@implementation AutoField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + field = [strct findField:field_name]; + + return self; +} + +-writeParseData +{ + printf("FieldDef: '%s' '%s'\n", struct_name, field_name); + return self; +} + +-writeField +{ + Type *field_type = [Type findType: field.type]; + fprintf (output_file, "\t{\"%s\", field_offset (%s, %s), %s, %s, %s},\n", + field_name, struct_name, field_name, + [field_type parseType], [field_type parseFunc], + [field_type parseData]); + return self; +} + +-writeSymbol +{ + Type *field_type = [Type findType: field.type]; + fprintf (output_file, + "\t{\"%s\", &%s, (void *) field_offset (%s, %s)},\n", + field_name, [field_type cexprType], struct_name, field_name); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfielddata.h b/libs/video/renderer/vulkan/vkgen/vkfielddata.h new file mode 100644 index 000000000..cf8356262 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfielddata.h @@ -0,0 +1,9 @@ +#ifndef __renderer_vulkan_vkgen_vkfielddata_h +#define __renderer_vulkan_vkgen_vkfielddata_h + +#include "vkfielddef.h" + +@interface DataField: FieldDef +@end + +#endif//__renderer_vulkan_vkgen_vkfielddata_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfielddata.r b/libs/video/renderer/vulkan/vkgen/vkfielddata.r new file mode 100644 index 000000000..d13ff8965 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfielddata.r @@ -0,0 +1,45 @@ +#include + +#include "vkfielddata.h" +#include "vkgen.h" +#include "vkstruct.h" +#include "vktype.h" + +@implementation DataField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + + value_field = [[item getObjectForKey:"data"] string]; + size_field = [[item getObjectForKey:"size"] string]; + return self; +} + +-writeParseData +{ + fprintf (output_file, "static parse_data_t parse_%s_%s_data = {\n", + struct_name, field_name); + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, value_field); + if (size_field) { + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, size_field); + } else { + fprintf (output_file, "\tt-1,\n"); + } + fprintf (output_file, "};\n"); + return self; +} + +-writeField +{ + fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, "QFBinary", "data", struct_name, field_name); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfielddef.h b/libs/video/renderer/vulkan/vkgen/vkfielddef.h new file mode 100644 index 000000000..0363a9e7f --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfielddef.h @@ -0,0 +1,28 @@ +#ifndef __renderer_vulkan_vkgen_vkfielddef_h +#define __renderer_vulkan_vkgen_vkfielddef_h + +#include +#include + +@class PLItem; +@class Struct; +@class Type; + +@interface FieldDef: Object +{ + int line; + qfot_var_t *field; + string struct_name; + string field_name; + string value_field; + string size_field; +} ++fielddef:(PLItem *)item struct:(Struct *)strct field:(string)fname; +-init:(PLItem *)item struct:(Struct *)strct field:(string)fname; +-writeParseData; +-writeField; +-writeSymbol; +-(string) name; +@end + +#endif//__renderer_vulkan_vkgen_vkfielddef_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfielddef.r b/libs/video/renderer/vulkan/vkgen/vkfielddef.r new file mode 100644 index 000000000..9cc35c13a --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfielddef.r @@ -0,0 +1,95 @@ +#include +#include + +#include "vkfieldarray.h" +#include "vkfieldauto.h" +#include "vkfielddata.h" +#include "vkfielddef.h" +#include "vkfieldsingle.h" +#include "vkfieldstring.h" +#include "vkstruct.h" + +@implementation FieldDef + ++fielddef:(PLItem *)item struct:(Struct *)strct field:(string)fname +{ + string record = [item string]; + PLItem *type_desc = [item getObjectForKey:"type"]; + + if (!item) { + record = "auto"; + } + if (!record) { + if (item && !type_desc) { + return nil; + } + record = [type_desc string]; + if (!record) { + record = [[type_desc getObjectAtIndex:0] string]; + } + } + switch (record) { + case "auto": + return [[[AutoField alloc] init:item struct:strct field:fname] autorelease]; + case "string": + return [[[StringField alloc] init:item struct:strct field:fname] autorelease]; + case "data": + return [[[DataField alloc] init:item struct:strct field:fname] autorelease]; + case "single": + return [[[SingleField alloc] init:item struct:strct field:fname] autorelease]; + case "array": + return [[[ArrayField alloc] init:item struct:strct field:fname] autorelease]; + } + return nil; +} + +-init:(PLItem *)item struct:(Struct *)strct field:(string)fname +{ + self = [super init]; + if (!self) { + return self; + } + + line = [item line]; + struct_name = str_hold ([strct outname]); + field_name = str_hold (fname); + return self; +} + +-fromField:(qfot_var_t *)field struct:(Struct *)strct +{ + return self; +} + +-(void)dealloc +{ + str_free (struct_name); + str_free (field_name); +} + +-writeParseData +{ + fprintf (output_file, "undefined record type parse: %d\n", line); + return self; +} + +-writeField +{ + fprintf (output_file, "undefined record type field: %d\n", line); + return self; +} + +-writeSymbol +{ + fprintf (output_file, + "\t{\"%s\", 0/*FIXME*/, (void *) field_offset (%s, %s)},\n", + field_name, struct_name, value_field); + return self; +} + +-(string) name +{ + return field_name; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldsingle.h b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.h new file mode 100644 index 000000000..2fcd312c4 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.h @@ -0,0 +1,12 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldsingle_h +#define __renderer_vulkan_vkgen_vkfieldsingle_h + +#include "vkfielddef.h" + +@interface SingleField: FieldDef +{ + string type; +} +@end + +#endif//__renderer_vulkan_vkgen_vkfieldsingle_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldsingle.r b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.r new file mode 100644 index 000000000..e30ced3dd --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.r @@ -0,0 +1,46 @@ +#include + +#include "vkfieldsingle.h" +#include "vkgen.h" +#include "vktype.h" + +@implementation SingleField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + + PLItem *desc = [item getObjectForKey:"type"]; + type = [[desc getObjectAtIndex:1] string]; + + value_field = [[item getObjectForKey:"value"] string]; + return self; +} + +-writeParseData +{ + Type *field_type = [[Type lookup: type] dereference]; + + fprintf (output_file, "static parse_single_t parse_%s_%s_data = {\n", + struct_name, field_name); + fprintf (output_file, "\t%s,\n", [field_type parseType]); + fprintf (output_file, "\tsizeof (%s),\n", type); + fprintf (output_file, "\tparse_%s,\n", type); + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, value_field); + fprintf (output_file, "};\n"); + return self; +} + +-writeField +{ + string parse_type = [[[Type lookup: type] dereference] parseType]; + fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, parse_type, "single", struct_name, field_name); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldstring.h b/libs/video/renderer/vulkan/vkgen/vkfieldstring.h new file mode 100644 index 000000000..fead71504 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldstring.h @@ -0,0 +1,9 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldstring_h +#define __renderer_vulkan_vkgen_vkfieldstring_h + +#include "vkfielddef.h" + +@interface StringField: FieldDef +@end + +#endif//__renderer_vulkan_vkgen_vkfieldstring_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldstring.r b/libs/video/renderer/vulkan/vkgen/vkfieldstring.r new file mode 100644 index 000000000..ff0ba525d --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldstring.r @@ -0,0 +1,36 @@ +#include + +#include "vkfieldstring.h" +#include "vkgen.h" + +@implementation StringField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + + value_field = [[item getObjectForKey:"string"] string]; + return self; +} + +-writeParseData +{ + fprintf (output_file, "static parse_string_t parse_%s_%s_data = {\n", + struct_name, field_name); + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, value_field); + fprintf (output_file, "};\n"); + return self; +} + +-writeField +{ + fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, "QFString", "string", struct_name, field_name); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.h b/libs/video/renderer/vulkan/vkgen/vkgen.h index e60499f25..8f9cd5c93 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.h +++ b/libs/video/renderer/vulkan/vkgen/vkgen.h @@ -12,6 +12,7 @@ void printf (string fmt, ...); void fprintf (QFile file, string format, ...); extern Array *queue; extern Array *output_types; +extern PLItem *parse; extern QFile output_file; extern QFile header_file; extern hashtab_t *processed_types; diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r index 025e3d2cc..7a1edab8a 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.r +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -37,6 +37,7 @@ hashtab_t *processed_types; Array *queue; Array *output_types; +PLItem *parse; QFile output_file; QFile header_file; @@ -147,7 +148,6 @@ main(int argc, string *argv) QFile plist_file; PLItem *plist; PLItem *search; - PLItem *parse; arp_start (); @@ -199,6 +199,9 @@ main(int argc, string *argv) id obj = [queue objectAtIndex:0]; [queue removeObjectAtIndex:0]; if ([obj class] == [Struct class]) { + if ([[parse getObjectForKey:[obj name]] string] == "skip") { + continue; + } [obj forEachFieldCall:struct_func]; } [output_types addObject:obj]; @@ -235,7 +238,7 @@ main(int argc, string *argv) } arp_start (); - [obj writeTable:parse]; + [obj writeTable]; arp_end (); } fprintf (output_file, "static void\n"); @@ -247,7 +250,7 @@ main(int argc, string *argv) continue; } arp_start (); - [obj writeSymtabInit:parse]; + [obj writeSymtabInit]; arp_end (); } fprintf (output_file, "}\n"); diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.h b/libs/video/renderer/vulkan/vkgen/vkstruct.h index c251cb4c0..048b3332f 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.h +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.h @@ -10,10 +10,13 @@ @interface Struct: Type { + string outname; } -(void) forEachFieldCall: (varfunc) func; --(void) writeTable: (PLItem *) parse; --(void) writeSymtabInit:(PLItem *) parse; +-(qfot_var_t *)findField:(string) fieldName; +-(void) writeTable; +-(void) writeSymtabInit; +-(string) outname; @end #endif//__renderer_vulkan_vkgen_vkstruct_h diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index 6e6908bb8..6a8b21caa 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -6,6 +6,7 @@ #include #include +#include "vkfielddef.h" #include "vkgen.h" #include "vkstruct.h" @@ -46,122 +47,33 @@ return nil; } --(void) writeTable: (PLItem *) parse +-(void) writeTable { - string name = [self name]; - PLItem *field_dict = [parse getObjectForKey:name]; - PLItem *field_defs = [field_dict allKeys]; - Type *field_type; + PLItem *field_dict = [parse getObjectForKey:[self name]]; PLItem *new_name = [field_dict getObjectForKey:".name"]; + Array *field_defs = [Array array]; + if ([parse string] == "skip") { + return; + } if (new_name) { - name = [new_name string]; + outname = str_hold ([new_name string]); } - if (field_defs) { - PLItem *field_def; - qfot_var_t *field; + if (field_dict) { + PLItem *field_keys = [field_dict allKeys]; - for (int i = [field_defs count]; i-- > 0; ) { - string field_name = [[field_defs getObjectAtIndex:i] string]; - field_def = [field_dict getObjectForKey:field_name]; - PLItem *type_desc = [field_def getObjectForKey:"type"]; - string type_record; - string type_type; - string size_field = nil; - string value_field = nil; + for (int i = [field_keys count]; i-- > 0; ) { + string field_name = [[field_keys getObjectAtIndex:i] string]; - if (!type_desc || str_mid(field_name, 0, 1) == ".") { - continue; - } - type_record = [[type_desc getObjectAtIndex:0] string]; - type_type = [[type_desc getObjectAtIndex:1] string]; - - field_type = [[Type lookup: type_type] dereference]; - fprintf (output_file, "static parse_%s_t parse_%s_%s_data = {\n", - type_record, name, field_name); - if (type_record == "single") { - fprintf (output_file, "\t%s,\n", [field_type parseType]); - fprintf (output_file, "\tsizeof (%s),\n", type_type); - fprintf (output_file, "\tparse_%s,\n", type_type); - value_field = [[field_def getObjectForKey:"value"] string]; - fprintf (output_file, "\tfield_offset (%s, %s),\n", - name, value_field); - } else if (type_record == "array") { - fprintf (output_file, "\t%s,\n", [field_type parseType]); - fprintf (output_file, "\tsizeof (%s),\n", type_type); - fprintf (output_file, "\tparse_%s,\n", type_type); - value_field = [[field_def getObjectForKey:"values"] string]; - size_field = [[field_def getObjectForKey:"size"] string]; - fprintf (output_file, "\tfield_offset (%s, %s),\n", - name, value_field); - if (size_field) { - fprintf (output_file, "\tfield_offset (%s, %s),\n", - name, size_field); - } else { - fprintf (output_file, "\t-1,\n"); - } - } else if (type_record == "data") { - value_field = [[field_def getObjectForKey:"data"] string]; - size_field = [[field_def getObjectForKey:"size"] string]; - fprintf (output_file, "\tfield_offset (%s, %s),\n", - name, value_field); - if (size_field) { - fprintf (output_file, "\tfield_offset (%s, %s),\n", - name, size_field); - } else { - fprintf (output_file, "\t-1,\n"); - } - } else { - fprintf (output_file, "\tno type,\n"); - } - fprintf (output_file, "};\n"); - } - } - fprintf (output_file, "static plfield_t %s_fields[] = {\n", name); - if (field_defs) { - PLItem *field_def; - qfot_var_t *field; - - for (int i = [field_defs count]; i-- > 0; ) { - string field_name = [[field_defs getObjectAtIndex:i] string]; if (str_mid(field_name, 0, 1) == ".") { continue; } - field_def = [field_dict getObjectForKey:field_name]; - if ([field_def string] == "auto") { - field = [self findField:field_name]; - if (!field) { - continue; - } - field_type = [Type findType: field.type]; - fprintf (output_file, - "\t{\"%s\", field_offset (%s, %s), %s, %s, %s},\n", - field_name, name, field_name, - [field_type parseType], [field_type parseFunc], - [field_type parseData]); - } else { - PLItem *type_desc = [field_def getObjectForKey:"type"]; - string type_record; - string type_type; - string parseType = "no type"; - - type_record = [[type_desc getObjectAtIndex:0] string]; - type_type = [[type_desc getObjectAtIndex:1] string]; - - field_type = [[Type lookup: type_type] dereference]; - if (type_record == "single") { - parseType = [field_type parseType]; - } else if (type_record == "array") { - parseType = "QFArray"; - } else if (type_record == "data") { - parseType = "QFBinary"; - } - fprintf (output_file, - "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", - field_name, parseType, type_record, - name, field_name); - } + PLItem *field_item = [field_dict getObjectForKey:field_name]; + FieldDef *field_def = [FieldDef fielddef:field_item + struct:self + field:field_name]; + [field_defs addObject: field_def]; } } else { for (int i = 0; i < type.strct.num_fields; i++) { @@ -169,76 +81,47 @@ if (field.name == "sType" || field.name == "pNext") { continue; } - field_type = [Type findType: field.type]; - fprintf (output_file, - "\t{\"%s\", field_offset (%s, %s), %s, %s, %s},\n", - field.name, name, field.name, - [field_type parseType], [field_type parseFunc], - [field_type parseData]); + FieldDef *field_def = [FieldDef fielddef:nil + struct:self + field:field.name]; + [field_defs addObject: field_def]; } } + for (int i = [field_defs count]; i-- > 0; ) { + FieldDef *field_def = [field_defs objectAtIndex:i]; + [field_def writeParseData]; + } + fprintf (output_file, "static plfield_t %s_fields[] = {\n", [self outname]); + for (int i = [field_defs count]; i-- > 0; ) { + FieldDef *field_def = [field_defs objectAtIndex:i]; + [field_def writeField]; + } fprintf (output_file, "\t{ }\n"); fprintf (output_file, "};\n"); fprintf (header_file, "int parse_%s (const plfield_t *field," " const plitem_t *item, void *data, plitem_t *messages," " void *context);\n", - name); + [self outname]); fprintf (output_file, "int parse_%s (const plfield_t *field," " const plitem_t *item, void *data, plitem_t *messages," " void *context)\n", - name); + [self outname]); fprintf (output_file, "{\n"); fprintf (output_file, "\treturn PL_ParseDictionary (%s_fields, item, data, messages," " context);\n", - name); + [self outname]); fprintf (output_file, "}\n"); - fprintf (output_file, "static exprsym_t %s_symbols[] = {\n", name); + fprintf (output_file, "static exprsym_t %s_symbols[] = {\n", [self outname]); if (field_defs) { PLItem *field_def; qfot_var_t *field; for (int i = [field_defs count]; i-- > 0; ) { - string field_name = [[field_defs getObjectAtIndex:i] string]; - field_def = [field_dict getObjectForKey:field_name]; - PLItem *type_desc = [field_def getObjectForKey:"type"]; - string type_record; - string type_type; - string size_field = nil; - string value_field = nil; - - if (str_mid(field_name, 0, 1) == ".") { - continue; - } - field_def = [field_dict getObjectForKey:field_name]; - if ([field_def string] == "auto") { - field = [self findField:field_name]; - if (!field) { - continue; - } - field_type = [Type findType: field.type]; - fprintf (output_file, - "\t{\"%s\", &%s, (void *) field_offset (%s, %s)},\n", - field_name, [field_type cexprType], name, field_name); - } else { - type_record = [[type_desc getObjectAtIndex:0] string]; - if (type_record == "single") { - value_field = [[field_def getObjectForKey:"value"] string]; - } else if (type_record == "array") { - value_field = [[field_def getObjectForKey:"values"] string]; - } else if (type_record == "data") { - value_field = [[field_def getObjectForKey:"data"] string]; - } - if (!value_field) { - value_field = field_name; - } - fprintf (output_file, - "\t{\"%s\", 0/*FIXME*/," - " (void *) field_offset (%s, %s)},\n", - field_name, name, value_field); - } + FieldDef *field_def = [field_defs objectAtIndex:i]; + [field_def writeSymbol]; } } else { for (int i = 0; i < type.strct.num_fields; i++) { @@ -246,40 +129,48 @@ if (field.name == "sType" || field.name == "pNext") { continue; } - field_type = [Type findType: field.type]; + Type *field_type = [Type findType: field.type]; fprintf (output_file, "\t{\"%s\", &%s, (void *) field_offset (%s, %s)},\n", - field.name, [field_type cexprType], name, field.name); + field.name, [field_type cexprType], [self outname], field.name); } } fprintf (output_file, "\t{ }\n"); fprintf (output_file, "};\n"); - fprintf (output_file, "static exprtab_t %s_symtab = {\n", name); - fprintf (output_file, "\t%s_symbols,\n", name); + fprintf (output_file, "static exprtab_t %s_symtab = {\n", [self outname]); + fprintf (output_file, "\t%s_symbols,\n", [self outname]); fprintf (output_file, "};\n"); - fprintf (output_file, "exprtype_t %s_type = {\n", name); - fprintf (output_file, "\t\"%s\",\n", name); - fprintf (output_file, "\tsizeof (%s),\n", name); + fprintf (output_file, "exprtype_t %s_type = {\n", [self outname]); + fprintf (output_file, "\t\"%s\",\n", [self outname]); + fprintf (output_file, "\tsizeof (%s),\n", [self outname]); fprintf (output_file, "\tcexpr_struct_binops,\n"); fprintf (output_file, "\t0,\n"); - fprintf (output_file, "\t&%s_symtab,\n", name); + fprintf (output_file, "\t&%s_symtab,\n", [self outname]); fprintf (output_file, "};\n"); - fprintf (header_file, "extern exprtype_t %s_type;\n", name); + fprintf (output_file, "\n"); + fprintf (header_file, "extern exprtype_t %s_type;\n", [self outname]); } --(void) writeSymtabInit:(PLItem *) parse +-(void) writeSymtabInit { - string name = [self name]; - PLItem *field_dict = [parse getObjectForKey:name]; - PLItem *new_name = [field_dict getObjectForKey:".name"]; + PLItem *field_dict = [parse getObjectForKey:[self outname]]; - if (new_name) { - name = [new_name string]; + if ([parse string] == "skip") { + return; } - fprintf (output_file, "\tcexpr_init_symtab (&%s_symtab, context);\n", name); + fprintf (output_file, "\tcexpr_init_symtab (&%s_symtab, context);\n", + [self outname]); +} + +-(string) outname +{ + if (outname) { + return outname; + } + return [self name]; } -(string) cexprType diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index fbe46d512..fbfbdf226 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -122,6 +122,10 @@ typedef struct parse_data_s { size_t size_offset; } parse_data_t; +typedef struct parse_string_s { + size_t value_offset; +} parse_string_t; + static int parse_uint32_t (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context) { @@ -239,7 +243,7 @@ static int parse_data (const plfield_t *field, const plitem_t *item, const void *bindata = PL_BinaryData (item); size_t binsize = PL_BinarySize (item); - Sys_Printf ("parse_array: %s %zd %d %p %p %p\n", + Sys_Printf ("parse_data: %s %zd %d %p %p %p\n", field->name, field->offset, field->type, field->parser, field->data, data); Sys_Printf (" %zd %zd\n", datad->value_offset, datad->size_offset); @@ -253,6 +257,24 @@ static int parse_data (const plfield_t *field, const plitem_t *item, return 1; } +static int parse_string (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type string = (parse_string_t *) field->data; + __auto_type value = (char **) ((byte *)data + string->value_offset); + + const char *str = PL_BinaryData (item); + + Sys_Printf ("parse_string: %s %zd %d %p %p %p\n", + field->name, field->offset, field->type, field->parser, + field->data, data); + Sys_Printf (" %zd\n", string->value_offset); + Sys_Printf (" %s\n", str); + + *value = strdup (str); + return 1; +} + #include "libs/video/renderer/vulkan/vkparse.cinc" typedef struct qfv_renderpass_s { From 25ade4c0f3ab289f4b04946dc2701fbee4f81b84 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 24 Dec 2020 01:36:17 +0900 Subject: [PATCH 145/435] [vulkan] Add support for custom parsers And provisionally parse shader stage defs. --- include/QF/Vulkan/pipeline.h | 3 - include/QF/Vulkan/qf_vid.h | 3 +- include/QF/Vulkan/shader.h | 9 +++ libs/video/renderer/vid_render_vulkan.c | 3 + libs/video/renderer/vulkan/pipeline.c | 17 ------ libs/video/renderer/vulkan/qfpipeline.plist | 15 +++++ libs/video/renderer/vulkan/shader.c | 39 +++++++++++- .../video/renderer/vulkan/vkgen/Makemodule.am | 1 + .../renderer/vulkan/vkgen/vkfieldcustom.h | 14 +++++ .../renderer/vulkan/vkgen/vkfieldcustom.r | 60 +++++++++++++++++++ libs/video/renderer/vulkan/vkgen/vkfielddef.r | 3 + libs/video/renderer/vulkan/vkparse.c | 55 ++++++++++++----- libs/video/renderer/vulkan/vkparse.h | 6 ++ libs/video/renderer/vulkan/vkparse.plist | 33 +++++++++- .../video/renderer/vulkan/vulkan_vid_common.c | 40 ++++++++++++- 15 files changed, 261 insertions(+), 40 deletions(-) create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldcustom.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldcustom.r diff --git a/include/QF/Vulkan/pipeline.h b/include/QF/Vulkan/pipeline.h index f77585217..c7d5013de 100644 --- a/include/QF/Vulkan/pipeline.h +++ b/include/QF/Vulkan/pipeline.h @@ -128,9 +128,6 @@ typedef struct qfv_pipelinecacheset_s #define QFV_AllocPipelineCacheSet(num, allocator) \ DARRAY_ALLOCFIXED (qfv_pipelinecacheset_t, num, allocator) -VkShaderModule QFV_CreateShaderModule (struct qfv_device_s *device, - size_t size, const uint32_t *code); - struct dstring_s; VkPipelineCache QFV_CreatePipelineCache (struct qfv_device_s *device, struct dstring_s *cacheData); diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index d7ef64a97..d380d1236 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -38,8 +38,9 @@ struct vulkan_ctx_s; void Vulkan_DestroyFramebuffers (struct vulkan_ctx_s *ctx); void Vulkan_CreateFramebuffers (struct vulkan_ctx_s *ctx); -void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx); void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx); +void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx); +void Vulkan_CreatePipelines (struct vulkan_ctx_s *ctx); void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx); void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx); void Vulkan_Init_Common (struct vulkan_ctx_s *ctx); diff --git a/include/QF/Vulkan/shader.h b/include/QF/Vulkan/shader.h index 6b8321cdd..b13f6a618 100644 --- a/include/QF/Vulkan/shader.h +++ b/include/QF/Vulkan/shader.h @@ -3,11 +3,20 @@ struct qfv_device_s; struct vulkan_ctx_s; +struct plitem_s; +struct parsectx_s; VkShaderModule QFV_CreateShaderModule (struct qfv_device_s *device, const char *path); +void QFV_DestroyShaderModule (struct qfv_device_s *device, + VkShaderModule module); +VkShaderModule QFV_FindShaderModule (struct vulkan_ctx_s *ctx, + const char *name); void QFV_RegisterShaderModule (struct vulkan_ctx_s *ctx, const char *name, VkShaderModule module); void QFV_DeregisterShaderModule (struct vulkan_ctx_s *ctx, const char *name); +int parse_VkShaderModule (const struct plitem_s *item, void **data, + struct plitem_s *messages, + struct parsectx_s *context); #endif//__QF_Vulkan_shader_h diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 85181547c..52246162b 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -64,6 +64,9 @@ vulkan_R_Init (void) Vulkan_CreateSwapchain (vulkan_ctx); Vulkan_CreateRenderPass (vulkan_ctx); Vulkan_CreateFramebuffers (vulkan_ctx); + // FIXME this should be staged so screen updates can begin while pipelines + // are being built + Vulkan_CreatePipelines (vulkan_ctx); qfv_swapchain_t *sc = vulkan_ctx->swapchain; diff --git a/libs/video/renderer/vulkan/pipeline.c b/libs/video/renderer/vulkan/pipeline.c index 119fbf303..bfe48ce9f 100644 --- a/libs/video/renderer/vulkan/pipeline.c +++ b/libs/video/renderer/vulkan/pipeline.c @@ -64,23 +64,6 @@ #include "util.h" -VkShaderModule -QFV_CreateShaderModule (qfv_device_t *device, - size_t size, const uint32_t *code) -{ - VkDevice dev = device->dev; - qfv_devfuncs_t *dfunc = device->funcs; - - VkShaderModuleCreateInfo createInfo = { - VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0, 0, - size, code, - }; - - VkShaderModule module; - dfunc->vkCreateShaderModule (dev, &createInfo, 0, &module); - return module; -} - VkPipelineCache QFV_CreatePipelineCache (qfv_device_t *device, dstring_t *cacheData) { diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 66c9e0adb..7af624b99 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -1,4 +1,19 @@ { + modules = ( + // specify shader modules to load into memory + { + // the name of the module for referecy by the pipeline + name = passthrough; + // the path to the spv file to load + // $shader refers to the shader install path + // $builtin refers to compiled-in shaders + file = $builtin/passthrough.vert; + }, + { + name = pushcolor; + file = $builtin/pushcolor.frag; + }, + ); renderpass = { attachments = ( { diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index 704e01996..5ee89ca25 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -42,6 +42,7 @@ #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/hash.h" +#include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/Vulkan/qf_vid.h" @@ -52,6 +53,7 @@ #include "QF/Vulkan/shader.h" #include "vid_vulkan.h" +#include "vkparse.h" static #include "libs/video/renderer/vulkan/passthrough.vert.spvc" @@ -92,7 +94,7 @@ QFV_CreateShaderModule (qfv_device_t *device, const char *shader_path) shaderdata_t _data = {}; shaderdata_t *data = 0; dstring_t *path = 0; - QFile *file; + QFile *file = 0; VkShaderModule shader = 0; if (strncmp (shader_path, BUILTIN, BUILTIN_SIZE) == 0) { @@ -142,6 +144,15 @@ QFV_CreateShaderModule (qfv_device_t *device, const char *shader_path) return shader; } +void +QFV_DestroyShaderModule (qfv_device_t *device, VkShaderModule module) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyShaderModule (dev, module, 0); +} + static shadermodule_t * new_module (vulkan_ctx_t *ctx) { @@ -169,10 +180,21 @@ sm_free (void *sm, void *ctx) del_module (sm, ctx); } +VkShaderModule +QFV_FindShaderModule (vulkan_ctx_t *ctx, const char *name) +{ + //FIXME + if (!ctx->shadermodules) { + ctx->shadermodules = Hash_NewTable (127, sm_getkey, sm_free, ctx, 0); + } + return Hash_Find (ctx->shadermodules, name); +} + void QFV_RegisterShaderModule (vulkan_ctx_t *ctx, const char *name, VkShaderModule module) { + //FIXME if (!ctx->shadermodules) { ctx->shadermodules = Hash_NewTable (127, sm_getkey, sm_free, ctx, 0); } @@ -190,3 +212,18 @@ QFV_DeregisterShaderModule (vulkan_ctx_t *ctx, const char *name) } Hash_Free (ctx->shadermodules, Hash_Del (ctx->shadermodules, name)); } + +int +parse_VkShaderModule (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) +{ + vulkan_ctx_t *ctx = context->vctx; + const char *name = PL_String (item); + __auto_type mptr = (VkShaderModule *)data[0]; + VkShaderModule module = QFV_FindShaderModule (ctx, name); + if (module) { + *mptr = module; + return 1; + } + return 0; +} diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am index 31c22d936..4847bf6fd 100644 --- a/libs/video/renderer/vulkan/vkgen/Makemodule.am +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -6,6 +6,7 @@ vkgen_dat_src= \ libs/video/renderer/vulkan/vkgen/vkenum.r \ libs/video/renderer/vulkan/vkgen/vkfieldarray.r \ libs/video/renderer/vulkan/vkgen/vkfieldauto.r \ + libs/video/renderer/vulkan/vkgen/vkfieldcustom.r \ libs/video/renderer/vulkan/vkgen/vkfielddata.r \ libs/video/renderer/vulkan/vkgen/vkfielddef.r \ libs/video/renderer/vulkan/vkgen/vkfieldsingle.r \ diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.h b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.h new file mode 100644 index 000000000..4b7672a9e --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.h @@ -0,0 +1,14 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldcustom_h +#define __renderer_vulkan_vkgen_vkfieldcustom_h + +#include "vkfielddef.h" + +@interface CustomField: FieldDef +{ + string pltype; + string parser; + PLItem *fields; +} +@end + +#endif//__renderer_vulkan_vkgen_vkfieldcustom_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r new file mode 100644 index 000000000..e00085ac1 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r @@ -0,0 +1,60 @@ +#include + +#include "vkfieldcustom.h" +#include "vkgen.h" +#include "vktype.h" + +@implementation CustomField + +-init:(PLItem *) item struct:(Struct *)strct field:(string)fname +{ + self = [super init:item struct:strct field:fname]; + if (!self) { + return self; + } + + PLItem *desc = [item getObjectForKey:"type"]; + pltype = [[desc getObjectAtIndex:1] string]; + parser = [[desc getObjectAtIndex:2] string]; + + fields = [item getObjectForKey:"fields"]; + return self; +} + +-writeParseData +{ + fprintf (output_file, "static size_t parse_%s_%s_offsets = {\n", + struct_name, field_name); + for (int i = 0, count = [fields count]; i < count; i++) { + string field = [[fields getObjectAtIndex:i] string]; + fprintf (output_file, "\tfield_offset (%s, %s),\n", + struct_name, field); + } + fprintf (output_file, "};\n"); + + fprintf (output_file, "static parse_custom_t parse_%s_%s_data = {\n", + struct_name, field_name); + fprintf (output_file, "\t%s,\n", parser); + fprintf (output_file, "\t&parse_%s_%s_offsets,\n", + struct_name, field_name); + fprintf (output_file, "\t%d,\n", [fields count]); + fprintf (output_file, "};\n"); + return self; +} + +-writeField +{ + fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", + field_name, pltype, "custom", struct_name, field_name); + return self; +} + +-writeSymbol +{ + fprintf (output_file, + "\t{\"%s\", 0/*FIXME*/, 0/*(void *) field_offset (%s, %s)*/},\n", + field_name, struct_name, "FIXME"); + return self; +} + +@end diff --git a/libs/video/renderer/vulkan/vkgen/vkfielddef.r b/libs/video/renderer/vulkan/vkgen/vkfielddef.r index 9cc35c13a..6aba1df05 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfielddef.r +++ b/libs/video/renderer/vulkan/vkgen/vkfielddef.r @@ -3,6 +3,7 @@ #include "vkfieldarray.h" #include "vkfieldauto.h" +#include "vkfieldcustom.h" #include "vkfielddata.h" #include "vkfielddef.h" #include "vkfieldsingle.h" @@ -31,6 +32,8 @@ switch (record) { case "auto": return [[[AutoField alloc] init:item struct:strct field:fname] autorelease]; + case "custom": + return [[[CustomField alloc] init:item struct:strct field:fname] autorelease]; case "string": return [[[StringField alloc] init:item struct:strct field:fname] autorelease]; case "data": diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index fbfbdf226..5b198a807 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -56,6 +56,7 @@ #include "QF/Vulkan/instance.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/renderpass.h" +#include "QF/Vulkan/shader.h" #include "QF/Vulkan/swapchain.h" #include "compat.h" @@ -126,8 +127,16 @@ typedef struct parse_string_s { size_t value_offset; } parse_string_t; -static int parse_uint32_t (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +typedef struct parse_custom_s { + int (*parse) (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context); + size_t *offsets; + size_t num_offsets; +} parse_custom_t; + +static int +parse_uint32_t (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { int ret = 1; const char *valstr = PL_String (item); @@ -154,12 +163,13 @@ static int parse_uint32_t (const plfield_t *field, const plitem_t *item, return ret; } -static int parse_enum (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +static int +parse_enum (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { int ret = 1; __auto_type enm = (exprenum_t *) field->data; - exprctx_t ectx = *(exprctx_t *)context; + exprctx_t ectx = *((parsectx_t *)context)->ectx; exprval_t result = { enm->type, data }; ectx.symtab = enm->symtab; ectx.result = &result; @@ -172,8 +182,9 @@ static int parse_enum (const plfield_t *field, const plitem_t *item, return ret; } -static int parse_single (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +static int +parse_single (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { __auto_type single = (parse_single_t *) field->data; void *flddata = (byte *)data + single->value_offset; @@ -197,8 +208,9 @@ static int parse_single (const plfield_t *field, const plitem_t *item, return 1; } -static int parse_array (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +static int +parse_array (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { __auto_type array = (parse_array_t *) field->data; __auto_type value = (void **) ((byte *)data + array->value_offset); @@ -233,8 +245,9 @@ static int parse_array (const plfield_t *field, const plitem_t *item, return 1; } -static int parse_data (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +static int +parse_data (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { __auto_type datad = (parse_data_t *) field->data; __auto_type value = (void **) ((byte *)data + datad->value_offset); @@ -257,8 +270,9 @@ static int parse_data (const plfield_t *field, const plitem_t *item, return 1; } -static int parse_string (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +static int +parse_string (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { __auto_type string = (parse_string_t *) field->data; __auto_type value = (char **) ((byte *)data + string->value_offset); @@ -275,6 +289,18 @@ static int parse_string (const plfield_t *field, const plitem_t *item, return 1; } +static int +parse_custom (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type custom = (parse_custom_t *) field->data; + void **offsets = alloca (custom->num_offsets * sizeof (void *)); + for (size_t i = 0; i < custom->num_offsets; i++) { + offsets[i] = data + custom->offsets[i]; + } + return custom->parse (item, offsets, messages, context); +} + #include "libs/video/renderer/vulkan/vkparse.cinc" typedef struct qfv_renderpass_s { @@ -331,6 +357,7 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) }; exprtab_t vars_tab = { var_syms, 0 }; exprctx_t exprctx = {}; + parsectx_t parsectx = { &exprctx, ctx }; exprctx.external_variables = &vars_tab; exprctx.memsuper = new_memsuper (); @@ -340,7 +367,7 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) cexpr_init_symtab (&vars_tab, &exprctx); if (!PL_ParseDictionary (renderpass_fields, plist, - &renderpass_data, messages, &exprctx)) { + &renderpass_data, messages, &parsectx)) { for (int i = 0; i < PL_A_NumObjects (messages); i++) { Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); } diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index ae8a30af9..b95475bda 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -1,9 +1,15 @@ #ifndef __vkparse_h #define __vkparse_h +#include "QF/cexpr.h" #include "QF/Vulkan/renderpass.h" #include "libs/video/renderer/vulkan/vkparse.hinc" +typedef struct parsectx_s { + struct exprctx_s *ectx; + struct vulkan_ctx_s *vctx; +} parsectx_t; + VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); void QFV_InitParse (void); diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index 1441a0267..1ba7e8bb4 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -3,6 +3,8 @@ VkAttachmentDescription, VkSubpassDescription, VkSubpassDependency, + VkSpecializationInfo, + VkPipelineShaderStageCreateInfo, qfv_swapchain_t, ); parse = { @@ -37,6 +39,35 @@ size = preserveAttachmentCount; values = pPreserveAttachments; }; - } + }; + VkSpecializationInfo = { + mapEntries = { + type = (array, VkSpecializationMapEntry); + size = mapEntryCount; + values = pMapEntries; + }; + data = { + type = data; + size = dataSize; + data = pData; + }; + }; + VkPipelineShaderStageCreateInfo = { + flags = auto; + stage = auto; + name = { + type = string; + string = pName; + }; + module = { + type = (custom, QFString, parse_VkShaderModule); + fields = (module); + }; + specializationInfo = { + type = (single, VkSpecializationInfo); + value = pSpecializationInfo; + }; + }; + VkShaderModuleCreateInfo = skip; } } diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 9c2b021f4..78c4e9add 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -57,6 +57,7 @@ #include "QF/Vulkan/instance.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/renderpass.h" +#include "QF/Vulkan/shader.h" #include "QF/Vulkan/swapchain.h" #include "compat.h" @@ -260,7 +261,12 @@ static qfv_pipelinestagepair_t imageLayoutTransitionStages[] = { static plitem_t * qfv_load_pipeline (void) { - return PL_GetPropertyList (quakeforge_pipeline); + static plitem_t *pipeline; + + if (!pipeline) { + pipeline = PL_GetPropertyList (quakeforge_pipeline); + } + return pipeline; } void @@ -269,9 +275,9 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) plitem_t *item = qfv_load_pipeline (); if (!item || !(item = PL_ObjectForKey (item, "renderpass"))) { - Sys_Printf ("error loading pipeline\n"); + Sys_Printf ("error loading renderpass\n"); } else { - Sys_Printf ("Found renderer def\n"); + Sys_Printf ("Found renderpass def\n"); } qfv_device_t *device = ctx->device; VkDevice dev = device->dev; @@ -391,6 +397,34 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) ctx->renderpass.depthImage = 0; } +void +Vulkan_CreatePipelines (vulkan_ctx_t *ctx) +{ + plitem_t *item = qfv_load_pipeline (); + + if (!item || !(item = PL_ObjectForKey (item, "modules"))) { + Sys_Printf ("error loading modules\n"); + } else { + Sys_Printf ("Found modules def\n"); + } + for (int i = PL_A_NumObjects (item); i-- > 0; ) { + plitem_t *mod = PL_ObjectAtIndex (item, i); + const char *name = PL_String (PL_ObjectForKey (mod, "name")); + const char *file = PL_String (PL_ObjectForKey (mod, "file")); + if (!name || !file) { + continue; + } + if (QFV_FindShaderModule (ctx, name)) { + continue; + } + VkShaderModule module = QFV_CreateShaderModule (ctx->device, file); + if (module) { + Sys_Printf ("registering shader %s %p\n", name, module); + QFV_RegisterShaderModule (ctx, name, module); + } + } +} + void Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) { From 5b0da2b14ce2402a102875a3d7209f7a31774271 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 24 Dec 2020 09:57:24 +0900 Subject: [PATCH 146/435] [util] Add an int to uint cast for cexpr --- libs/util/cexpr-parse.y | 6 +----- libs/util/cexpr-type.c | 8 ++++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y index e789a40e9..eb56ed588 100644 --- a/libs/util/cexpr-parse.y +++ b/libs/util/cexpr-parse.y @@ -150,11 +150,7 @@ assign_expr (exprval_t *dst, const exprval_t *src, exprctx_t *context) if (!src) { return; } - for (binop = dst->type->binops; binop && binop->op; binop++) { - if (binop->op == '=' && binop->other == src->type) { - break; - } - } + binop = cexpr_find_cast (dst->type, src->type); if (binop && binop->op) { binop->func (dst, src, dst, context); } else { diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index c0610b13d..c1dbbafb0 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -125,6 +125,13 @@ BINOP(uint, bor, unsigned, |) BINOP(uint, xor, unsigned, ^) BINOP(uint, rem, unsigned, %) +static void +uint_cast_int (const exprval_t *val1, const exprval_t *src, exprval_t *result, + exprctx_t *ctx) +{ + *(unsigned *) result->value = *(int *) src->value; +} + UNOP(uint, pos, unsigned, +) UNOP(uint, neg, unsigned, -) UNOP(uint, tnot, unsigned, !) @@ -142,6 +149,7 @@ binop_t uint_binops[] = { { '^', &cexpr_uint, &cexpr_uint, uint_xor }, { '%', &cexpr_uint, &cexpr_uint, uint_rem }, { MOD, &cexpr_uint, &cexpr_uint, uint_rem }, + { '=', &cexpr_int, &cexpr_uint, uint_cast_int }, {} }; From 2430f44d7b0330d49db79c32726f8dbbe76d9cb3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 24 Dec 2020 09:58:27 +0900 Subject: [PATCH 147/435] [vulkan] Support parsing numeric types --- libs/video/renderer/vulkan/vkgen/vktype.r | 12 +++++ libs/video/renderer/vulkan/vkparse.c | 54 +++++++++++++++++------ 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/libs/video/renderer/vulkan/vkgen/vktype.r b/libs/video/renderer/vulkan/vkgen/vktype.r index 5d6c1b7ae..fbe44e350 100644 --- a/libs/video/renderer/vulkan/vkgen/vktype.r +++ b/libs/video/renderer/vulkan/vkgen/vktype.r @@ -74,6 +74,9 @@ static string get_type_key (void *type, void *unused) -(string) name { + if (type.meta == ty_basic) { + return pr_type_name[type.type]; + } //FIXME extract alias name and return proper type name return type.encoding; } @@ -98,16 +101,25 @@ static string get_type_key (void *type, void *unused) -(string) parseType { + if (type.meta == ty_basic) { + return "QFString"; + } return "no parse"; } -(string) parseFunc { + if (type.meta == ty_basic) { + return "parse_basic"; + } return "0"; } -(string) parseData { + if (type.meta == ty_basic) { + return "&cexpr_" + pr_type_name[type.type]; + } return "0"; } diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 5b198a807..ac198e756 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -135,29 +135,55 @@ typedef struct parse_custom_s { } parse_custom_t; static int -parse_uint32_t (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +parse_basic (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { int ret = 1; + __auto_type etype = (exprtype_t *) field->data; + exprctx_t ectx = *((parsectx_t *) context)->ectx; + exprval_t result = { etype, data }; + ectx.symtab = 0; + ectx.result = &result; const char *valstr = PL_String (item); //Sys_Printf ("parse_uint32_t: %s %zd %d %p %p: %s\n", // field->name, field->offset, field->type, field->parser, // field->data, valstr); if (strcmp (valstr, "VK_SUBPASS_EXTERNAL") == 0) { + //FIXME handle subpass in a separate parser? *(uint32_t *) data = VK_SUBPASS_EXTERNAL; } else { - char *end; - unsigned long val = strtoul (valstr, &end, 0); - if (*valstr && !*end && val <= 0xffffffff) { - *(uint32_t *) data = val; - } else if (val > 0xffffffff) { - PL_Message (messages, item, "%lu bigger than 32 bits", val); - ret = 0; - } else { - PL_Message (messages, item, "invalid char at %d in '%s'\n", - (int) (end - valstr), valstr); - ret = 0; - } + Sys_Printf ("parse_uint32_t: %s %zd %d %p %p %s\n", + field->name, field->offset, field->type, field->parser, + field->data, valstr); + ret = !cexpr_eval_string (valstr, &ectx); + Sys_Printf (" %x\n", *(uint32_t *)data); + } + + return ret; +} + +static int +parse_uint32_t (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + int ret = 1; + exprctx_t ectx = *((parsectx_t *) context)->ectx; + exprval_t result = { &cexpr_uint, data }; + ectx.symtab = 0; + ectx.result = &result; + const char *valstr = PL_String (item); + //Sys_Printf ("parse_uint32_t: %s %zd %d %p %p: %s\n", + // field->name, field->offset, field->type, field->parser, + // field->data, valstr); + if (strcmp (valstr, "VK_SUBPASS_EXTERNAL") == 0) { + //FIXME handle subpass in a separate parser? + *(uint32_t *) data = VK_SUBPASS_EXTERNAL; + } else { + Sys_Printf ("parse_uint32_t: %s %zd %d %p %p %s\n", + field->name, field->offset, field->type, field->parser, + field->data, valstr); + ret = !cexpr_eval_string (valstr, &ectx); + Sys_Printf (" %d\n", *(uint32_t *)data); } return ret; From 5c0ce2c414527e8bac3a84f79bb18e6312ccc3df Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 24 Dec 2020 11:50:52 +0900 Subject: [PATCH 148/435] [vulkan] Correct the usage of custom field offsets I had missed the array declaration and thus initialized the pointer to the offset array incorrectly. Didn't show up until I tried using multiple offsets. --- libs/video/renderer/vulkan/vkgen/vkfieldcustom.r | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r index e00085ac1..3e9e56c74 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r +++ b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r @@ -23,7 +23,7 @@ -writeParseData { - fprintf (output_file, "static size_t parse_%s_%s_offsets = {\n", + fprintf (output_file, "static size_t parse_%s_%s_offsets[] = {\n", struct_name, field_name); for (int i = 0, count = [fields count]; i < count; i++) { string field = [[fields getObjectAtIndex:i] string]; @@ -35,7 +35,7 @@ fprintf (output_file, "static parse_custom_t parse_%s_%s_data = {\n", struct_name, field_name); fprintf (output_file, "\t%s,\n", parser); - fprintf (output_file, "\t&parse_%s_%s_offsets,\n", + fprintf (output_file, "\tparse_%s_%s_offsets,\n", struct_name, field_name); fprintf (output_file, "\t%d,\n", [fields count]); fprintf (output_file, "};\n"); From cb2bdb0224c915b8f8dcd2e59781a9ecb6bb57de Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 24 Dec 2020 13:33:37 +0900 Subject: [PATCH 149/435] [util] Rename PL_ParseDictionary to PL_ParseStruct Struct is far more appropriate for its function, and I need to parse a dictionary into a hash table. --- include/QF/qfplist.h | 4 ++-- libs/util/qfplist.c | 4 ++-- libs/video/renderer/vulkan/vkgen/vkstruct.r | 2 +- libs/video/renderer/vulkan/vkparse.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 1d45426d2..e8a64f054 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -342,8 +342,8 @@ void PL_Free (plitem_t *item); \param context Additional context data passed to the parser. \return 0 if there are any errors, 1 if there are no errors. */ -int PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, - void *data, plitem_t *messages, void *context); +int PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, + void *data, plitem_t *messages, void *context); int PL_ParseArray (const plfield_t *fields, const plitem_t *dict, void *data, plitem_t *messages, void *context); void __attribute__((format(printf,3,4))) diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index b33d22084..d8338a332 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1144,8 +1144,8 @@ pl_default_parser (const plfield_t *field, const plitem_t *item, void *data, } VISIBLE int -PL_ParseDictionary (const plfield_t *fields, const plitem_t *dict, void *data, - plitem_t *messages, void *context) +PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data, + plitem_t *messages, void *context) { void **list, **l; dictkey_t *current; diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index 6a8b21caa..761cbdade 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -109,7 +109,7 @@ [self outname]); fprintf (output_file, "{\n"); fprintf (output_file, - "\treturn PL_ParseDictionary (%s_fields, item, data, messages," + "\treturn PL_ParseStruct (%s_fields, item, data, messages," " context);\n", [self outname]); fprintf (output_file, "}\n"); diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index ac198e756..d2ae12949 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -392,8 +392,8 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) cexpr_init_symtab (&vars_tab, &exprctx); - if (!PL_ParseDictionary (renderpass_fields, plist, - &renderpass_data, messages, &parsectx)) { + if (!PL_ParseStruct (renderpass_fields, plist, &renderpass_data, + messages, &parsectx)) { for (int i = 0; i < PL_A_NumObjects (messages); i++) { Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); } From 55c1ed124df99fec8737c8e4d1f5cd6fc0232409 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 24 Dec 2020 15:52:32 +0900 Subject: [PATCH 150/435] [doxygen] Fix some missed issues for doc building --- doc/Makemodule.am | 3 ++- doc/quakeforge.dox.conf.in | 13 +++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/doc/Makemodule.am b/doc/Makemodule.am index b26d57841..91d9270b7 100644 --- a/doc/Makemodule.am +++ b/doc/Makemodule.am @@ -76,5 +76,6 @@ doc/progs/vm-mem.eps: doc/progs/vm-mem.fig doc/qtv/qwtv.svg: doc/qtv/qwtv.fig doc/qtv/qwtv.eps: doc/qtv/qwtv.fig -doc: doc/quakeforge.dox.conf doc/progs/vm-mem.svg doc/progs/vm-mem.eps doc/qtv/qwtv.svg qtv/qwtv.eps ${DOX} +.PHONY: doc +doc: doc/quakeforge.dox.conf doc/progs/vm-mem.svg doc/progs/vm-mem.eps doc/qtv/qwtv.svg doc/qtv/qwtv.eps ${DOX} doxygen doc/quakeforge.dox.conf diff --git a/doc/quakeforge.dox.conf.in b/doc/quakeforge.dox.conf.in index a235a895d..1e925e354 100644 --- a/doc/quakeforge.dox.conf.in +++ b/doc/quakeforge.dox.conf.in @@ -253,12 +253,6 @@ TAB_SIZE = 4 ALIASES = QF=QuakeForge -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -937,8 +931,8 @@ EXAMPLE_RECURSIVE = NO # \image command). IMAGE_PATH = @TOPSRC@/doc \ - @builddir@/progs \ - @builddir@/qtv + @builddir@/doc/progs \ + @builddir@/doc/qtv # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -1756,7 +1750,7 @@ COMPACT_LATEX = YES # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. -PAPER_TYPE = a4wide +PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names # that should be included in the LaTeX output. The package can be specified just @@ -2144,7 +2138,6 @@ SEARCH_INCLUDES = YES # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @TOPSRC@/include \ - @TOPSRC@/hw/include \ @TOPSRC@/nq/include \ @TOPSRC@/qw/include \ @TOPSRC@/qtv/include From fefb32bf13bd4d553465c5599403d190cf9f5262 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 24 Dec 2020 15:59:33 +0900 Subject: [PATCH 151/435] [util] Add a PL dictionary to hash table parser --- include/QF/qfplist.h | 88 ++++++++++++++++++++++++++++++++++++++++++-- libs/util/qfplist.c | 62 +++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 3 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index e8a64f054..972f69dc3 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -147,7 +147,7 @@ int PL_Line (const plitem_t *item) __attribute__((pure)); \return the size in bytes of the binary object 0 if binary isn't a binary object. */ -size_t PL_BinarySize (const plitem_t *item) __attribute__((pure)); +size_t PL_BinarySize (const plitem_t *binary) __attribute__((pure)); /** Retrieve the data from a binary object. @@ -323,9 +323,9 @@ void PL_Free (plitem_t *item); Can be used recursively to parse deep hierarchies. - \param dict The dictionary object to parse \param fields Array of field items describing the structure. Terminated by a field item with a null \a name pointer. + \param dict The dictionary object to parse \param data Pointer to the structure into which the data will be parsed. \param messages Array object supplied by the caller used for storing @@ -344,8 +344,90 @@ void PL_Free (plitem_t *item); */ int PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data, plitem_t *messages, void *context); -int PL_ParseArray (const plfield_t *fields, const plitem_t *dict, + +/** Parse an array object into a dynamic arrah (see darray.h). + + For each object in the array, the field item is used to determine how to + parse the object. If the array is empty, the destination will be + initialized to an empty array. + + When an error occurs (incorrect item type (item type does not match the + type specified in the element object) or the element object's \a parser + returns 0), processing continues but the error result is returned. + + Can be used recursively to parse deep hierarchies. + + \param field Pointer to a single field that has the field data pointer + set to reference a plelement_t object used to describe + the contents of the array. + \param array The array object to parse + \param data Pointer to the pointer to which the dynamic array will + be written. The dynamic array is allocated using + DARRAY_ALLOCFIXED(). + \param messages Array object supplied by the caller used for storing + messages. The messages may or may not indicate errors (its + contents are not checked). This function itself will add + only string objects. + If there are any errors, suitable messages will be found in + the \a messages object. However, just because there are no + errors doesn't mean that \a messages will remain empty as + a field's \a parser may add other messages. The standard + message format is "[line number]: [message]". If the line + number is 0, then the actual line is unknown (due to the + source item not being parsed from a file or string). + \param context Additional context data passed to the parser. + \return 0 if there are any errors, 1 if there are no errors. +*/ +int PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, plitem_t *messages, void *context); + +/** Parse a dictionary object into a hash table. + + For each key in the dictionary, the element object is used to determine + how to parse the object associated with that key. Duplicate keys are an + error: they must be unique. A suitable message is added to the + \a messages object. If the dictionary object is empty, the destination + table is left unmodified. + + When an error occurs (duplicate keys, incorrect type, or the element + object's \a parser returns 0), processing continues but the error + result is returned. + + Can be used recursively to parse deep hierarchies. + + Hash_Add() is used to add objects to the hash table, and Hash_Find() is + used to check for duplicates. Hash_Free() is used to free unused + objects. The means that the hash table is expected to use standard + objects with embedded keys (the parser is expected to put the key in the + object) and to have a free function. + + The parser's data paramenter points to a pre-allocated block of memory + of the sized indicated by the element object's size field, using the + element object's alloc callback. The name field in the field paramenter + is set to the object's key and remains owned by the dictionary. + + \param field Pointer to a single field that has the field data pointer + set to reference a plelement_t object used to describe + the contents of the dictionary. + \param dict The dictionary object to parse + \param data Pointer to the structure into which the data will be + parsed. + \param messages Array object supplied by the caller used for storing + messages. The messages may or may not indicate errors (its + contents are not checked). This function itself will add + only string objects. + If there are any errors, suitable messages will be found in + the \a messages object. However, just because there are no + errors doesn't mean that \a messages will remain empty as + a field's \a parser may add other messages. The standard + message format is "[line number]: [message]". If the line + number is 0, then the actual line is unknown (due to the + source item not being parsed from a file or string). + \param context Additional context data passed to the parser. + \return 0 if there are any errors, 1 if there are no errors. +*/ +int PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, + void *data, plitem_t *messages, void *context); void __attribute__((format(printf,3,4))) PL_Message (plitem_t *messages, const plitem_t *item, const char *fmt, ...); diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index d8338a332..e789435ef 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1247,3 +1247,65 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, *(arr_t **) data = arr; return result; } + +VISIBLE int +PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, + plitem_t *messages, void *context) +{ + void **list, **l; + dictkey_t *current; + int result = 1; + plparser_t parser; + __auto_type tab = (hashtab_t *) data; + + plelement_t *element = (plelement_t *) field->data; + plfield_t f = { 0, 0, element->type, element->parser, element->data }; + + if (dict->type != QFDictionary) { + PL_Message (messages, dict, "error: not a dictionary object"); + return 0; + } + + if (f.parser) { + parser = f.parser; + } else { + PL_Message (messages, dict, "no parser set"); + return 0; + } + + if (!(l = list = Hash_GetList ((hashtab_t *) dict->data))) { + // empty struct: leave as default + return 1; + } + + void *obj = element->alloc (element->stride); + while ((current = (dictkey_t *) *l++)) { + const char *key = current->key; + plitem_t *item = current->value; + + if (item->type != element->type) { + PL_Message (messages, item, + "error: element %s is the wrong type" + " Got %s, expected %s", key, + pl_types[element->type], + pl_types[item->type]); + result = 0; + continue; + } + f.name = key; + if (Hash_Find (tab, key)) { + PL_Message (messages, item, "duplicate name"); + result = 0; + } else { + if (!parser (&f, item, obj, messages, context)) { + result = 0; + } else { + Hash_Add (tab, obj); + obj = element->alloc (element->stride); + } + } + } + Hash_Free (tab, obj); + free (list); + return result; +} From 9db80259d1c75f937f08677f729563fc17488590 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 24 Dec 2020 16:39:05 +0900 Subject: [PATCH 152/435] [gl,glsl] Copy fog color rather than return pointer The static variable meant that Fog_GetColor was not thread-safe (though multiple calls in the one thread look to be ok for now). However, this change takes it one step closer to being more generally usable. Patch found in an old stash. --- include/r_internal.h | 2 +- libs/video/renderer/gl/gl_fog.c | 37 ++++++++++++----------- libs/video/renderer/glsl/glsl_alias.c | 2 +- libs/video/renderer/glsl/glsl_bsp.c | 8 ++--- libs/video/renderer/glsl/glsl_fog.c | 25 +++++++-------- libs/video/renderer/glsl/glsl_iqm.c | 2 +- libs/video/renderer/glsl/glsl_particles.c | 4 +-- libs/video/renderer/glsl/glsl_sprite.c | 2 +- 8 files changed, 41 insertions(+), 41 deletions(-) diff --git a/include/r_internal.h b/include/r_internal.h index 31272a5a8..547d4d1bf 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -31,7 +31,7 @@ void Fog_Update (float density, float red, float green, float blue, struct plitem_s; void Fog_ParseWorldspawn (struct plitem_s *worldspawn); -float *Fog_GetColor (void); +void Fog_GetColor (quat_t fogcolor); float Fog_GetDensity (void) __attribute__((pure)); void Fog_SetupFrame (void); void Fog_EnableGFog (void); diff --git a/libs/video/renderer/gl/gl_fog.c b/libs/video/renderer/gl/gl_fog.c index fe63419b5..b8747e37b 100644 --- a/libs/video/renderer/gl/gl_fog.c +++ b/libs/video/renderer/gl/gl_fog.c @@ -189,32 +189,29 @@ gl_Fog_ParseWorldspawn (plitem_t *worldspawn) calculates fog color for this frame, taking into account fade times */ -float * -gl_Fog_GetColor (void) +void +gl_Fog_GetColor (quat_t fogcolor) { - static float c[4]; float f; int i; if (fade_done > vr_data.realtime) { f = (fade_done - vr_data.realtime) / fade_time; - c[0] = f * old_red + (1.0 - f) * fog_red; - c[1] = f * old_green + (1.0 - f) * fog_green; - c[2] = f * old_blue + (1.0 - f) * fog_blue; - c[3] = 1.0; + fogcolor[0] = f * old_red + (1.0 - f) * fog_red; + fogcolor[1] = f * old_green + (1.0 - f) * fog_green; + fogcolor[2] = f * old_blue + (1.0 - f) * fog_blue; + fogcolor[3] = 1.0; } else { - c[0] = fog_red; - c[1] = fog_green; - c[2] = fog_blue; - c[3] = 1.0; + fogcolor[0] = fog_red; + fogcolor[1] = fog_green; + fogcolor[2] = fog_blue; + fogcolor[3] = 1.0; } //find closest 24-bit RGB value, so solid-colored sky can match the fog //perfectly for (i = 0; i < 3; i++) - c[i] = (float) (rint (c[i] * 255)) / 255.0f; - - return c; + fogcolor[i] = (float) (rint (fogcolor[i] * 255)) / 255.0f; } /* @@ -243,7 +240,10 @@ gl_Fog_GetDensity (void) void gl_Fog_SetupFrame (void) { - qfglFogfv (GL_FOG_COLOR, gl_Fog_GetColor ()); + quat_t fogcolor; + + gl_Fog_GetColor (fogcolor); + qfglFogfv (GL_FOG_COLOR, fogcolor); qfglFogf (GL_FOG_DENSITY, gl_Fog_GetDensity () / 64.0); } @@ -294,8 +294,11 @@ gl_Fog_StartAdditive (void) void gl_Fog_StopAdditive (void) { - if (gl_Fog_GetDensity () > 0) - qfglFogfv (GL_FOG_COLOR, gl_Fog_GetColor ()); + if (gl_Fog_GetDensity () > 0) { + quat_t fogcolor; + gl_Fog_GetColor (fogcolor); + qfglFogfv (GL_FOG_COLOR, fogcolor); + } } //============================================================================== diff --git a/libs/video/renderer/glsl/glsl_alias.c b/libs/video/renderer/glsl/glsl_alias.c index 3fdd50b66..155845450 100644 --- a/libs/video/renderer/glsl/glsl_alias.c +++ b/libs/video/renderer/glsl/glsl_alias.c @@ -333,7 +333,7 @@ glsl_R_AliasBegin (void) qfeglDisableVertexAttribArray (quake_mdl.colora.location); qfeglDisableVertexAttribArray (quake_mdl.colorb.location); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_mdl.fog.location, 1, fog); diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index 682ffb628..767000b12 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -360,7 +360,7 @@ static void update_lightmap (msurface_t *surf) { int maps; - +return; for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) if (d_lightstylevalue[surf->styles[maps]] != surf->cached_light[maps]) goto dynamic; @@ -871,7 +871,7 @@ bsp_begin (void) qfeglVertexAttrib4fv (quake_bsp.color.location, default_color); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_bsp.fog.location, 1, fog); @@ -926,7 +926,7 @@ turb_begin (void) qfeglVertexAttrib4fv (quake_turb.color.location, default_color); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_turb.fog.location, 1, fog); @@ -1030,7 +1030,7 @@ sky_begin (void) qfeglEnable (GL_TEXTURE_2D); } - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (sky_params.fog->location, 1, fog); diff --git a/libs/video/renderer/glsl/glsl_fog.c b/libs/video/renderer/glsl/glsl_fog.c index 8e246b6b7..8118b8497 100644 --- a/libs/video/renderer/glsl/glsl_fog.c +++ b/libs/video/renderer/glsl/glsl_fog.c @@ -189,32 +189,29 @@ glsl_Fog_ParseWorldspawn (plitem_t *worldspawn) calculates fog color for this frame, taking into account fade times */ -float * -glsl_Fog_GetColor (void) +void +glsl_Fog_GetColor (quat_t fogcolor) { - static float c[4]; float f; int i; if (fade_done > vr_data.realtime) { f = (fade_done - vr_data.realtime) / fade_time; - c[0] = f * old_red + (1.0 - f) * fog_red; - c[1] = f * old_green + (1.0 - f) * fog_green; - c[2] = f * old_blue + (1.0 - f) * fog_blue; - c[3] = 1.0; + fogcolor[0] = f * old_red + (1.0 - f) * fog_red; + fogcolor[1] = f * old_green + (1.0 - f) * fog_green; + fogcolor[2] = f * old_blue + (1.0 - f) * fog_blue; + fogcolor[3] = 1.0; } else { - c[0] = fog_red; - c[1] = fog_green; - c[2] = fog_blue; - c[3] = 1.0; + fogcolor[0] = fog_red; + fogcolor[1] = fog_green; + fogcolor[2] = fog_blue; + fogcolor[3] = 1.0; } //find closest 24-bit RGB value, so solid-colored sky can match the fog //perfectly for (i = 0; i < 3; i++) - c[i] = (float) (rint (c[i] * 255)) / 255.0f; - - return c; + fogcolor[i] = (float) (rint (fogcolor[i] * 255)) / 255.0f; } /* diff --git a/libs/video/renderer/glsl/glsl_iqm.c b/libs/video/renderer/glsl/glsl_iqm.c index d189a4cbe..e757cf087 100644 --- a/libs/video/renderer/glsl/glsl_iqm.c +++ b/libs/video/renderer/glsl/glsl_iqm.c @@ -278,7 +278,7 @@ glsl_R_IQMBegin (void) qfeglUseProgram (iqm_shader.program); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (iqm_shader.fog.location, 1, fog); diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index c4e214c50..b1461f208 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -1579,7 +1579,7 @@ draw_qf_particles (void) qfeglEnableVertexAttribArray (quake_part.color.location); qfeglEnableVertexAttribArray (quake_part.st.location); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_part.fog.location, 1, fog); @@ -1725,7 +1725,7 @@ draw_id_particles (void) qfeglUniformMatrix4fv (quake_point.mvp_matrix.location, 1, false, vp_mat); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_point.fog.location, 1, fog); diff --git a/libs/video/renderer/glsl/glsl_sprite.c b/libs/video/renderer/glsl/glsl_sprite.c index 69c67335a..c0acdc078 100644 --- a/libs/video/renderer/glsl/glsl_sprite.c +++ b/libs/video/renderer/glsl/glsl_sprite.c @@ -335,7 +335,7 @@ R_SpriteBegin (void) qfeglDisableVertexAttribArray (quake_sprite.colorb.location); qfeglDisableVertexAttribArray (quake_sprite.blend.location); - VectorCopy (glsl_Fog_GetColor (), fog); + glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_sprite.fog.location, 1, fog); From c0c728b188c6c0a7c44f18ec8b0b9ea878137669 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 25 Dec 2020 00:17:20 +0900 Subject: [PATCH 153/435] [vulkan] Fix a few code generation issues QC's int type is named "integer" (didn't feel like changing that right now), so special case it to be "int". Output the parse func name (instead of "fix me"). Output a parse func for enums (needed for arrays of enums (VkDynamicState)). --- libs/video/renderer/vulkan/vkgen/vkenum.r | 18 ++++++++++++++++++ libs/video/renderer/vulkan/vkgen/vkstruct.r | 4 ++-- libs/video/renderer/vulkan/vkgen/vktype.r | 6 ++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.r b/libs/video/renderer/vulkan/vkgen/vkenum.r index 234c99b61..9f12c013e 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.r +++ b/libs/video/renderer/vulkan/vkgen/vkenum.r @@ -120,6 +120,24 @@ skip_value(string name) fprintf (output_file, "\t&%s_symtab,\n", [self name]); fprintf (output_file, "};\n"); + fprintf (output_file, "static plfield_t %s_field = { 0, 0, QFString," + " parse_enum, &%s_enum};\n", + [self name], [self name]); + fprintf (output_file, "int parse_%s (const plfield_t *field," + " const plitem_t *item, void *data, plitem_t *messages," + " void *context)\n", + [self name]); + fprintf (output_file, "{\n"); + fprintf (output_file, + "\treturn parse_enum (&%s_field, item, data, messages," + " context);\n", + [self name]); + fprintf (output_file, "}\n"); + + fprintf (header_file, "int parse_%s (const plfield_t *field," + " const plitem_t *item, void *data, plitem_t *messages," + " void *context);\n", + [self name]); fprintf (header_file, "extern exprenum_t %s_enum;\n", [self name]); } diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index 761cbdade..ac03d8f41 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -175,7 +175,7 @@ -(string) cexprType { - return [self name] + "_type"; + return [self outname] + "_type"; } -(string) parseType @@ -185,7 +185,7 @@ -(string) parseFunc { - return "fix me"; + return "parse_" + [self outname]; } -(string) parseData diff --git a/libs/video/renderer/vulkan/vkgen/vktype.r b/libs/video/renderer/vulkan/vkgen/vktype.r index fbe44e350..735e88339 100644 --- a/libs/video/renderer/vulkan/vkgen/vktype.r +++ b/libs/video/renderer/vulkan/vkgen/vktype.r @@ -75,6 +75,9 @@ static string get_type_key (void *type, void *unused) -(string) name { if (type.meta == ty_basic) { + if (type.type == ev_integer) { + return "int"; + } return pr_type_name[type.type]; } //FIXME extract alias name and return proper type name @@ -118,6 +121,9 @@ static string get_type_key (void *type, void *unused) -(string) parseData { if (type.meta == ty_basic) { + if (type.type == ev_integer) { + return "&cexpr_int"; + } return "&cexpr_" + pr_type_name[type.type]; } return "0"; From d824db68a5df60bafd7359032d2ec9e9bbd623d4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 25 Dec 2020 00:28:26 +0900 Subject: [PATCH 154/435] [util] Zero plist symtabl object memory --- libs/util/qfplist.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index e789435ef..3e64e3c3e 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1279,6 +1279,7 @@ PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, } void *obj = element->alloc (element->stride); + memset (obj, 0, element->stride); while ((current = (dictkey_t *) *l++)) { const char *key = current->key; plitem_t *item = current->value; @@ -1302,6 +1303,7 @@ PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, } else { Hash_Add (tab, obj); obj = element->alloc (element->stride); + memset (obj, 0, element->stride); } } } From 09a10f80e1a5ec8111dd28745aabec459cd52f84 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 28 Dec 2020 12:29:04 +0900 Subject: [PATCH 155/435] [util] Add basic SIMD implemented vector functions They take advantage of gcc's vector_size attribute and so only cross, dot, qmul, qvmul and qrot (create rotation quaternion from two vectors) are needed at this stage as basic (per-component) math is supported natively by gcc. The provided functions work on horizontal (array-of-structs) data, ie a vec4d_t or vec4f_t represents a single vector, or traditional vector layout. Vertical layout (struct-of-arrays) does not need any special functions as the regular math can be used to operate on four vectors at a time. Functions are provided for loading a vec4 from a vec3 (4th element set to 0) and storing a vec4 into a vec3 (discarding the 4th element). With this, QF will require AVX2 support (needed for vec4d_t). Without support for doubles, SSE is possible, but may not be worthwhile for horizontal data. Fused-multiply-add is NOT used because it alters the results between unoptimized and optimized code, resulting in -mfma really meaning -mfast-math-anyway. I really do not want to have to debug issues that occur only in optimized code. --- config.d/compiling.m4 | 5 + include/QF/simd/types.h | 85 +++++++++++ include/QF/simd/vec4d.h | 156 +++++++++++++++++++ include/QF/simd/vec4f.h | 159 +++++++++++++++++++ libs/util/test/Makemodule.am | 5 + libs/util/test/test-simd.c | 289 +++++++++++++++++++++++++++++++++++ 6 files changed, 699 insertions(+) create mode 100644 include/QF/simd/types.h create mode 100644 include/QF/simd/vec4d.h create mode 100644 include/QF/simd/vec4f.h create mode 100644 libs/util/test/test-simd.c diff --git a/config.d/compiling.m4 b/config.d/compiling.m4 index 343218d35..d9ba92887 100644 --- a/config.d/compiling.m4 +++ b/config.d/compiling.m4 @@ -82,6 +82,11 @@ AC_ARG_ENABLE(optimize, optimize=yes ) +QF_CC_OPTION(-mavx2) +dnl fma is not used as it is the equivalent of turning on +dnl -funsafe-math-optimizations +dnl QF_CC_OPTION(-mfma) + AC_MSG_CHECKING(for optimization) if test "x$optimize" = xyes -a "x$leave_cflags_alone" != "xyes"; then AC_MSG_RESULT(yes) diff --git a/include/QF/simd/types.h b/include/QF/simd/types.h new file mode 100644 index 000000000..cd8b0da9d --- /dev/null +++ b/include/QF/simd/types.h @@ -0,0 +1,85 @@ +/* + QF/simd/types.h + + Type definitions for QF SIMD values + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_simd_types_h +#define __QF_simd_types_h + +#define VEC_TYPE(t,n) typedef t n __attribute__ ((vector_size (4*sizeof (t)))) + +/** Three element vector type for interfacing with compact data. + * + * This cannot be used directly by SIMD code and must be loaded and stored + * using load_vec3d() and store_vec3d() respectively. + */ +typedef double vec3d_t[3]; + +#ifdef __AVX__ +/** Four element vector type for horizontal (AOS) vector data. + * + * This is used for both vectors (3D and 4D) and quaternions. 3D vectors + * are simply vec4d_t values with 0 in the 4th element. + * + * Also usable with vertical (SOA) code, in which case each vec4d_t represents + * a single component from four vectors, or a single row/column (depending on + * context) of an Nx4 or 4xN matrix. + */ +VEC_TYPE (double, vec4d_t); + +/** Used mostly for __builtin_shuffle. + */ +VEC_TYPE (long, vec4l_t); +#endif + +/** Three element vector type for interfacing with compact data. + * + * This cannot be used directly by SIMD code and must be loaded and stored + * using load_vec3f() and store_vec3f() respectively. + */ +typedef float vec3f_t[3]; + +/** Four element vector type for horizontal (AOS) vector data. + * + * This is used for both vectors (3D and 4D) and quaternions. 3D vectors + * are simply vec4f_t values with 0 in the 4th element. + * + * Also usable with vertical (SOA) code, in which case each vec4f_t represents + * a single component from four vectors, or a single row/column (depending on + * context) of an Nx4 or 4xN matrix. + */ +VEC_TYPE (float, vec4f_t); + +/** Used mostly for __builtin_shuffle. + */ +VEC_TYPE (int, vec4i_t); + +#define VEC4D_FMT "[%.17g, %.17g, %.17g, %.17g]" +#define VEC4L_FMT "[%ld, %ld, %ld, %ld]" +#define VEC4F_FMT "[%.9g, %.9g, %.9g, %.9g]" +#define VEC4I_FMT "[%d, %d, %d, %d]" +#define VEC4_EXP(v) (v)[0], (v)[1], (v)[2], (v)[3] + +#endif//__QF_simd_types_h diff --git a/include/QF/simd/vec4d.h b/include/QF/simd/vec4d.h new file mode 100644 index 000000000..d608933f5 --- /dev/null +++ b/include/QF/simd/vec4d.h @@ -0,0 +1,156 @@ +/* + QF/simd/vec4d.h + + Vector functions for vec4d_t (ie, double precision) + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_simd_vec4d_h +#define __QF_simd_vec4d_h + +#include + +#include "QF/simd/types.h" + +/** 3D vector cross product. + * + * The w (4th) component can be any value on input, and is guaranteed to be 0 + * in the result. The result is not affected in any way by either vector's w + * componemnt + */ +vec4d_t crossd (vec4d_t a, vec4d_t b) __attribute__((const)); +vec4d_t +crossd (vec4d_t a, vec4d_t b) +{ + static const vec4l_t A = {1, 2, 0, 3}; + vec4d_t c = a * __builtin_shuffle (b, A); + vec4d_t d = __builtin_shuffle (a, A) * b; + c = c - d; + return __builtin_shuffle(c, A); +} + +/** 4D vector dot product. + * + * The w component *IS* significant, but if it is 0 in either vector, then + * the result will be as for a 3D dot product. + * + * Note that the dot product is in all 4 of the return value's elements. This + * helps optimize vector math as the scalar is already pre-spread. If just the + * scalar is required, use result[0]. + */ +vec4d_t dotd (vec4d_t a, vec4d_t b) __attribute__((const)); +vec4d_t +dotd (vec4d_t a, vec4d_t b) +{ + vec4d_t c = a * b; + c = _mm256_hadd_pd (c, c); + static const vec4l_t A = {2, 3, 0, 1}; + c += __builtin_shuffle(c, A); + return c; +} + +/** Quaternion product. + * + * The vector is interpreted as a quaternion instead of a regular 4D vector. + * The quaternion may be of any magnitude, so this is more generally useful. + * than if the quaternion was required to be unit length. + */ +vec4d_t qmuld (vec4d_t a, vec4d_t b) __attribute__((const)); +vec4d_t +qmuld (vec4d_t a, vec4d_t b) +{ + // results in [2*as*bs, as*b + bs*a + a x b] ([scalar, vector] notation) + // doesn't seem to adversly affect precision + vec4d_t c = crossd (a, b) + a * b[3] + a[3] * b; + vec4d_t d = dotd (a, b); + // zero out the vector component of dot product so only the scalar remains + d = _mm256_permute2f128_pd (d, d, 0x18); + d = _mm256_permute4x64_pd (d, 0xc0); + return c - d; +} + +/** Optimized quaterion-vector multiplication for vector rotation. + * + * If the vector's w component is not zero, then the result's w component + * is the cosine of the full rotation angle scaled by the vector's w component. + * The quaternion is assumed to be unit. If the quaternion is not unit, the + * vector will be scaled by the square of the quaternion's magnitude. + */ +vec4d_t qvmuld (vec4d_t q, vec4d_t v) __attribute__((const)); +vec4d_t +qvmuld (vec4d_t q, vec4d_t v) +{ + double s = q[3]; + // zero the scalar of the quaternion. Results in an extra operation, but + // avoids adding precision issues. + vec4d_t z = {}; + q = _mm256_blend_pd (q, z, 0x08); + vec4d_t c = crossd (q, v); + vec4d_t qv = dotd (q, v); // q.w is 0 so v.w is irrelevant + vec4d_t qq = dotd (q, q); + + return (s * s - qq) * v + 2 * (qv * q + s * c); +} + +/** Create the quaternion representing the shortest rotation from a to b. + * + * Both a and b are assumed to be 3D vectors (w components 0), but a resonable + * (but incorrect) result will still be produced if either a or b is a 4D + * vector. The rotation axis will be the same as if both vectors were 3D, but + * the magnitude of the rotation will be different. + */ +vec4d_t qrotd (vec4d_t a, vec4d_t b) __attribute__((const)); +vec4d_t +qrotd (vec4d_t a, vec4d_t b) +{ + vec4d_t ma = _mm256_sqrt_pd (dotd (a, a)); + vec4d_t mb = _mm256_sqrt_pd (dotd (b, b)); + vec4d_t den = 2 * ma * mb; + vec4d_t t = mb * a + ma * b; + vec4d_t mba_mab = _mm256_sqrt_pd (dotd (t, t)); + vec4d_t q = crossd (a, b) / mba_mab; + q[3] = (mba_mab / den)[0]; + return q; +} + +vec4d_t loadvec3d (const double v3[]) __attribute__((pure, access(read_only, 1))); +vec4d_t +loadvec3d (const double v3[]) +{ + vec4d_t v4 = {}; + + v4[0] = v3[0]; + v4[1] = v3[1]; + v4[2] = v3[2]; + return v4; +} + +void storevec3d (double v3[3], vec4d_t v4) __attribute__((access (write_only, 1))); +void storevec3d (double v3[3], vec4d_t v4) +{ + v3[0] = v4[0]; + v3[1] = v4[1]; + v3[2] = v4[2]; +} + +#endif//__QF_simd_vec4d_h diff --git a/include/QF/simd/vec4f.h b/include/QF/simd/vec4f.h new file mode 100644 index 000000000..ea92b81d9 --- /dev/null +++ b/include/QF/simd/vec4f.h @@ -0,0 +1,159 @@ +/* + QF/simd/vec4f.h + + Vector functions for vec4f_t (ie, float precision) + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_simd_vec4f_h +#define __QF_simd_vec4f_h + +#include + +#include "QF/simd/types.h" + +/** 3D vector cross product. + * + * The w (4th) component can be any value on input, and is guaranteed to be 0 + * in the result. The result is not affected in any way by either vector's w + * componemnt + */ +vec4f_t crossf (vec4f_t a, vec4f_t b) __attribute__((const)); +vec4f_t +crossf (vec4f_t a, vec4f_t b) +{ + static const vec4i_t A = {1, 2, 0, 3}; + vec4f_t c = a * __builtin_shuffle (b, A) - __builtin_shuffle (a, A) * b; + return __builtin_shuffle(c, A); +} + +/** 4D vector dot product. + * + * The w component *IS* significant, but if it is 0 in either vector, then + * the result will be as for a 3D dot product. + * + * Note that the dot product is in all 4 of the return value's elements. This + * helps optimize vector math as the scalar is already pre-spread. If just the + * scalar is required, use result[0]. + */ +vec4f_t dotf (vec4f_t a, vec4f_t b) __attribute__((const)); +vec4f_t +dotf (vec4f_t a, vec4f_t b) +{ + vec4f_t c = a * b; + c = _mm_hadd_ps (c, c); + c = _mm_hadd_ps (c, c); + return c; +} + +/** Quaternion product. + * + * The vector is interpreted as a quaternion instead of a regular 4D vector. + * The quaternion may be of any magnitude, so this is more generally useful. + * than if the quaternion was required to be unit length. + */ +vec4f_t qmulf (vec4f_t a, vec4f_t b) __attribute__((const)); +vec4f_t +qmulf (vec4f_t a, vec4f_t b) +{ + // results in [2*as*bs, as*b + bs*a + a x b] ([scalar, vector] notation) + // doesn't seem to adversly affect precision + vec4f_t c = crossf (a, b) + a * b[3] + a[3] * b; + vec4f_t d = dotf (a, b); + // zero out the vector component of dot product so only the scalar remains + d = _mm_insert_ps (d, d, 0xf7); + return c - d; +} + +/** Optimized quaterion-vector multiplication for vector rotation. + * + * If the vector's w component is not zero, then the result's w component + * is the cosine of the full rotation angle scaled by the vector's w component. + * The quaternion is assumed to be unit. + */ +vec4f_t qvmulf (vec4f_t q, vec4f_t v) __attribute__((const)); +vec4f_t +qvmulf (vec4f_t q, vec4f_t v) +{ + float s = q[3]; + // zero the scalar of the quaternion. Results in an extra operation, but + // avoids adding precision issues. + q = _mm_insert_ps (q, q, 0xf8); + vec4f_t c = crossf (q, v); // q.w is 0 so v.w is irrelevant + vec4f_t qv = dotf (q, v); + vec4f_t qq = dotf (q, q); + + return (s * s - qq) * v + 2 * (qv * q + s * c); +} + +/** Create the quaternion representing the shortest rotation from a to b. + * + * Both a and b are assumed to be 3D vectors (w components 0), but a resonable + * (but incorrect) result will still be produced if either a or b is a 4D + * vector. The rotation axis will be the same as if both vectors were 3D, but + * the magnitude of the rotation will be different. + */ +vec4f_t qrotf (vec4f_t a, vec4f_t b) __attribute__((const)); +vec4f_t +qrotf (vec4f_t a, vec4f_t b) +{ + vec4f_t ma = _mm_sqrt_ps (dotf (a, a)); + vec4f_t mb = _mm_sqrt_ps (dotf (b, b)); + vec4f_t den = 2 * ma * mb; + vec4f_t t = mb * a + ma * b; + vec4f_t mba_mab = _mm_sqrt_ps (dotf (t, t)); + vec4f_t q = crossf (a, b) / mba_mab; + q[3] = (mba_mab / den)[0]; + return q; +} + +vec4f_t loadvec3f (const float v3[3]) __attribute__((pure, access(read_only, 1))); +vec4f_t +loadvec3f (const float v3[3]) +{ + vec4f_t v4; + + // this had to be in asm otherwise gcc thinks v4 is only partially + // initialized, and gcc 10 does not use the zero flags when generating + // the code, resulting in a memory access to load a 0 into v4[3] + // + // The first instruction zeros v4[3] while loading v4[0] + asm ("\n\ + vinsertps $0x08, %1, %0, %0 \n\ + vinsertps $0x10, %2, %0, %0 \n\ + vinsertps $0x20, %3, %0, %0 \n\ + " + : "=v"(v4) + : "m"(v3[0]), "m"(v3[1]), "m"(v3[2])); + return v4; +} + +void storevec3f (float v3[3], vec4f_t v4) __attribute__((access (write_only, 1))); +void storevec3f (float v3[3], vec4f_t v4) +{ + v3[0] = v4[0]; + v3[1] = v4[1]; + v3[2] = v4[2]; +} + +#endif//__QF_simd_vec4f_h diff --git a/libs/util/test/Makemodule.am b/libs/util/test/Makemodule.am index 9447a7807..ca777f864 100644 --- a/libs/util/test/Makemodule.am +++ b/libs/util/test/Makemodule.am @@ -14,6 +14,7 @@ libs_util_tests = \ libs/util/test/test-seb \ libs/util/test/test-seg \ libs/util/test/test-set \ + libs/util/test/test-simd \ libs/util/test/test-txtbuffer \ libs/util/test/test-vrect @@ -81,6 +82,10 @@ libs_util_test_test_set_SOURCES=libs/util/test/test-set.c libs_util_test_test_set_LDADD=libs/util/libQFutil.la libs_util_test_test_set_DEPENDENCIES=libs/util/libQFutil.la +libs_util_test_test_simd_SOURCES=libs/util/test/test-simd.c +libs_util_test_test_simd_LDADD=libs/util/libQFutil.la +libs_util_test_test_simd_DEPENDENCIES=libs/util/libQFutil.la + libs_util_test_test_txtbuffer_SOURCES=libs/util/test/test-txtbuffer.c libs_util_test_test_txtbuffer_LDADD=libs/util/libQFutil.la libs_util_test_test_txtbuffer_DEPENDENCIES=libs/util/libQFutil.la diff --git a/libs/util/test/test-simd.c b/libs/util/test/test-simd.c new file mode 100644 index 000000000..ec1b145ac --- /dev/null +++ b/libs/util/test/test-simd.c @@ -0,0 +1,289 @@ +#include +#include +#include +#include + +#include "QF/simd/vec4d.h" +#include "QF/simd/vec4f.h" + +#define right { 1, 0, 0 } +#define forward { 0, 1, 0 } +#define up { 0, 0, 1 } +#define one { 1, 1, 1, 1 } +#define half { 0.5, 0.5, 0.5, 0.5 } +#define zero { 0, 0, 0, 0 } +#define qident { 0, 0, 0, 1 } +#define qtest { 0.64, 0.48, 0, 0.6 } + +#define nright { -1, 0, 0 } +#define nforward { 0, -1, 0 } +#define nup { 0, 0, -1 } +#define none { -1, -1, -1, -1 } +#define nqident { 0, 0, 0, -1 } + +#define s05 0.70710678118654757 + +typedef struct { + vec4d_t (*op) (vec4d_t a, vec4d_t b); + vec4d_t a; + vec4d_t b; + vec4d_t expect; + vec4d_t ulp_errors; +} vec4d_test_t; + +typedef struct { + vec4f_t (*op) (vec4f_t a, vec4f_t b); + vec4f_t a; + vec4f_t b; + vec4f_t expect; + vec4f_t ulp_errors; +} vec4f_test_t; + +static vec4d_test_t vec4d_tests[] = { + // 3D dot products + { dotd, right, right, one }, + { dotd, right, forward, zero }, + { dotd, right, up, zero }, + { dotd, forward, right, zero }, + { dotd, forward, forward, one }, + { dotd, forward, up, zero }, + { dotd, up, right, zero }, + { dotd, up, forward, zero }, + { dotd, up, up, one }, + + // one is 4D, so its self dot product is 4 + { dotd, one, one, { 4, 4, 4, 4} }, + { dotd, one, none, {-4, -4, -4, -4} }, + + // 3D cross products + { crossd, right, right, zero }, + { crossd, right, forward, up }, + { crossd, right, up, nforward }, + { crossd, forward, right, nup }, + { crossd, forward, forward, zero }, + { crossd, forward, up, right }, + { crossd, up, right, forward }, + { crossd, up, forward, nright }, + { crossd, up, up, zero }, + // double whammy tests: cross product with an angled vector and + // ensuring that a 4d vector (non-zero w component) does not affect + // the result, including the result's w component remaining zero. + { crossd, right, one, { 0, -1, 1} }, + { crossd, forward, one, { 1, 0, -1} }, + { crossd, up, one, {-1, 1, 0} }, + { crossd, one, right, { 0, 1, -1} }, + { crossd, one, forward, {-1, 0, 1} }, + { crossd, one, up, { 1, -1, 0} }, + // This one fails when optimizing with -mfma (which is why fma is not + // used): ulp errors in z and w + { crossd, qtest, qtest, {0, 0, 0, 0} }, + + { qmuld, qident, qident, qident }, + { qmuld, qident, right, right }, + { qmuld, qident, forward, forward }, + { qmuld, qident, up, up }, + { qmuld, right, qident, right }, + { qmuld, forward, qident, forward }, + { qmuld, up, qident, up }, + { qmuld, right, right, nqident }, + { qmuld, right, forward, up }, + { qmuld, right, up, nforward }, + { qmuld, forward, right, nup }, + { qmuld, forward, forward, nqident }, + { qmuld, forward, up, right }, + { qmuld, up, right, forward }, + { qmuld, up, forward, nright }, + { qmuld, up, up, nqident }, + { qmuld, one, one, { 2, 2, 2, -2 } }, + { qmuld, one, { 2, 2, 2, -2 }, { 0, 0, 0, -8 } }, + // This one fails when optimizing with -mfma (which is why fma is not + // used): ulp error in z + { qmuld, qtest, qtest, {0.768, 0.576, 0, -0.28} }, + + // The one vector is not unit (magnitude 2), so using it as a rotation + // quaternion results in scaling by 4. However, it still has the effect + // of rotating 120 degrees around the axis equidistant from the three + // orthogonal axes such that x->y->z->x + { qvmuld, one, right, { 0, 4, 0, 0 } }, + { qvmuld, one, forward, { 0, 0, 4, 0 } }, + { qvmuld, one, up, { 4, 0, 0, 0 } }, + { qvmuld, one, {1,1,1,0}, { 4, 4, 4, 0 } }, + { qvmuld, one, one, { 4, 4, 4, -2 } }, + // The half vector is unit. + { qvmuld, half, right, forward }, + { qvmuld, half, forward, up }, + { qvmuld, half, up, right }, + { qvmuld, half, {1,1,1,0}, { 1, 1, 1, 0 } }, + // one is a 4D vector and qvmuld is meant for 3D vectors. However, it + // seems that the vector's w has no effect on the 3d portion of the + // result, but the result's w is cosine of the full rotation angle + // scaled by quaternion magnitude and vector w + { qvmuld, half, one, { 1, 1, 1, -0.5 } }, + { qvmuld, half, {2,2,2,2}, { 2, 2, 2, -1 } }, + { qvmuld, qtest, right, {0.5392, 0.6144, -0.576, 0} }, + { qvmuld, qtest, forward, {0.6144, 0.1808, 0.768, 0}, + {0, -2.7e-17, 0, 0} }, + { qvmuld, qtest, up, {0.576, -0.768, -0.28, 0} }, + + { qrotd, right, right, qident }, + { qrotd, right, forward, { 0, 0, s05, s05 }, + {0, 0, -1.1e-16, 0} }, + { qrotd, right, up, { 0, -s05, 0, s05 }, + {0, 1.1e-16, 0, 0} }, + { qrotd, forward, right, { 0, 0, -s05, s05 }, + {0, 0, 1.1e-16, 0} }, + { qrotd, forward, forward, qident }, + { qrotd, forward, up, { s05, 0, 0, s05 }, + {-1.1e-16, 0, 0, 0} }, + { qrotd, up, right, { 0, s05, 0, s05 }, + {0, -1.1e-16, 0, 0} }, + { qrotd, up, forward, { -s05, 0, 0, s05 }, + { 1.1e-16, 0, 0, 0} }, + { qrotd, up, up, qident }, +}; +#define num_vec4d_tests (sizeof (vec4d_tests) / (sizeof (vec4d_tests[0]))) + +static vec4f_test_t vec4f_tests[] = { + // 3D dot products + { dotf, right, right, one }, + { dotf, right, forward, zero }, + { dotf, right, up, zero }, + { dotf, forward, right, zero }, + { dotf, forward, forward, one }, + { dotf, forward, up, zero }, + { dotf, up, right, zero }, + { dotf, up, forward, zero }, + { dotf, up, up, one }, + + // one is 4D, so its self dot product is 4 + { dotf, one, one, { 4, 4, 4, 4} }, + { dotf, one, none, {-4, -4, -4, -4} }, + + // 3D cross products + { crossf, right, right, zero }, + { crossf, right, forward, up }, + { crossf, right, up, nforward }, + { crossf, forward, right, nup }, + { crossf, forward, forward, zero }, + { crossf, forward, up, right }, + { crossf, up, right, forward }, + { crossf, up, forward, nright }, + { crossf, up, up, zero }, + // double whammy tests: cross product with an angled vector and + // ensuring that a 4d vector (non-zero w component) does not affect + // the result, including the result's w component remaining zero. + { crossf, right, one, { 0, -1, 1} }, + { crossf, forward, one, { 1, 0, -1} }, + { crossf, up, one, {-1, 1, 0} }, + { crossf, one, right, { 0, 1, -1} }, + { crossf, one, forward, {-1, 0, 1} }, + { crossf, one, up, { 1, -1, 0} }, + { crossf, qtest, qtest, {0, 0, 0, 0} }, + + { qmulf, qident, qident, qident }, + { qmulf, qident, right, right }, + { qmulf, qident, forward, forward }, + { qmulf, qident, up, up }, + { qmulf, right, qident, right }, + { qmulf, forward, qident, forward }, + { qmulf, up, qident, up }, + { qmulf, right, right, nqident }, + { qmulf, right, forward, up }, + { qmulf, right, up, nforward }, + { qmulf, forward, right, nup }, + { qmulf, forward, forward, nqident }, + { qmulf, forward, up, right }, + { qmulf, up, right, forward }, + { qmulf, up, forward, nright }, + { qmulf, up, up, nqident }, + { qmulf, one, one, { 2, 2, 2, -2 } }, + { qmulf, one, { 2, 2, 2, -2 }, { 0, 0, 0, -8 } }, + { qmulf, qtest, qtest, {0.768, 0.576, 0, -0.28}, + {0, 6e-8, 0, 3e-8} }, + + // The one vector is not unit (magnitude 2), so using it as a rotation + // quaternion results in scaling by 4. However, it still has the effect + // of rotating 120 degrees around the axis equidistant from the three + // orthogonal axes such that x->y->z->x + { qvmulf, one, right, { 0, 4, 0, 0 } }, + { qvmulf, one, forward, { 0, 0, 4, 0 } }, + { qvmulf, one, up, { 4, 0, 0, 0 } }, + { qvmulf, one, {1,1,1,0}, { 4, 4, 4, 0 } }, + { qvmulf, one, one, { 4, 4, 4, -2 } }, + { qvmulf, qtest, right, {0.5392, 0.6144, -0.576, 0}, + {0, -5.9e-08, -6e-8, 0} }, + { qvmulf, qtest, forward, {0.6144, 0.1808, 0.768, 0}, + {-5.9e-08, 1.5e-08, 0, 0} }, + { qvmulf, qtest, up, {0.576, -0.768, -0.28, 0}, + {6e-8, 0, 3e-8, 0} }, + + { qrotf, right, right, qident }, + { qrotf, right, forward, { 0, 0, s05, s05 } }, + { qrotf, right, up, { 0, -s05, 0, s05 } }, + { qrotf, forward, right, { 0, 0, -s05, s05 } }, + { qrotf, forward, forward, qident }, + { qrotf, forward, up, { s05, 0, 0, s05 } }, + { qrotf, up, right, { 0, s05, 0, s05 } }, + { qrotf, up, forward, { -s05, 0, 0, s05 } }, + { qrotf, up, up, qident }, +}; +#define num_vec4f_tests (sizeof (vec4f_tests) / (sizeof (vec4f_tests[0]))) + +static int +run_vec4d_tests (void) +{ + int ret = 0; + + for (size_t i = 0; i < num_vec4d_tests; i++) { + __auto_type test = &vec4d_tests[i]; + vec4d_t result = test->op (test->a, test->b); + vec4d_t expect = test->expect + test->ulp_errors; + vec4l_t res = result != expect; + if (res[0] || res[1] || res[2] || res[3]) { + ret |= 1; + printf ("\nrun_vec4d_tests\n"); + printf ("a: " VEC4D_FMT "\n", VEC4_EXP(test->a)); + printf ("b: " VEC4D_FMT "\n", VEC4_EXP(test->b)); + printf ("r: " VEC4D_FMT "\n", VEC4_EXP(result)); + printf ("t: " VEC4L_FMT "\n", VEC4_EXP(res)); + printf ("E: " VEC4D_FMT "\n", VEC4_EXP(expect)); + printf ("e: " VEC4D_FMT "\n", VEC4_EXP(test->expect)); + printf ("u: " VEC4D_FMT "\n", VEC4_EXP(test->ulp_errors)); + } + } + return ret; +} + +static int +run_vec4f_tests (void) +{ + int ret = 0; + + for (size_t i = 0; i < num_vec4f_tests; i++) { + __auto_type test = &vec4f_tests[i]; + vec4f_t result = test->op (test->a, test->b); + vec4f_t expect = test->expect + test->ulp_errors; + vec4i_t res = result != expect; + if (res[0] || res[1] || res[2] || res[3]) { + ret |= 1; + printf ("\nrun_vec4f_tests\n"); + printf ("a: " VEC4F_FMT "\n", VEC4_EXP(test->a)); + printf ("b: " VEC4F_FMT "\n", VEC4_EXP(test->b)); + printf ("r: " VEC4F_FMT "\n", VEC4_EXP(result)); + printf ("t: " VEC4I_FMT "\n", VEC4_EXP(res)); + printf ("E: " VEC4F_FMT "\n", VEC4_EXP(expect)); + printf ("e: " VEC4F_FMT "\n", VEC4_EXP(test->expect)); + printf ("u: " VEC4F_FMT "\n", VEC4_EXP(test->ulp_errors)); + } + } + return ret; +} + +int +main (void) +{ + int ret = 0; + ret |= run_vec4d_tests (); + ret |= run_vec4f_tests (); + return ret; +} From 03fcb530c71a7a107839598bba55f3a07b7a3953 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 28 Dec 2020 12:45:25 +0900 Subject: [PATCH 156/435] [util] Make quat test failure prints clearer --- libs/util/test/test-quat.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libs/util/test/test-quat.c b/libs/util/test/test-quat.c index 8e4738449..9144f56be 100644 --- a/libs/util/test/test-quat.c +++ b/libs/util/test/test-quat.c @@ -296,12 +296,12 @@ test_rotation4 (const vec3_t a, const vec3_t b, const quat_t expect) return 1; fail: printf ("\ntest_rotation4\n"); - printf ("%11.9g %11.9g %11.9g\n", VectorExpand(a)); - printf ("%11.9g %11.9g %11.9g\n", VectorExpand(b)); - printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand(quat)); - printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand(expect)); - printf ("%11.9g %11.9g %11.9g\n", VectorExpand(t)); - printf ("%11.9g\n", d); + printf ("a: %11.9g %11.9g %11.9g\n", VectorExpand(a)); + printf ("b: %11.9g %11.9g %11.9g\n", VectorExpand(b)); + printf ("q: %11.9g %11.9g %11.9g %11.9g\n", QuatExpand(quat)); + printf ("e: %11.9g %11.9g %11.9g %11.9g\n", QuatExpand(expect)); + printf ("t: %11.9g %11.9g %11.9g\n", VectorExpand(t)); + printf ("d: %11.9g\n", d); return 0; } @@ -351,6 +351,7 @@ test_quat_mat(const quat_t q, const quat_t expect) goto fail; return 1; fail: + printf ("\ntest_quat_mat\n"); printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (q)); printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", VectorExpand (m + 0), VectorExpand (expect + 0)); From 1ddd57b09ecdac19a7be6f322dd957541b0eda6f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 28 Dec 2020 14:52:36 +0900 Subject: [PATCH 157/435] [util] Add qconj, vtrunc, vceil and vfloor functions I had forgotten these rather critical functions. Both double and float versions are included. --- include/QF/simd/vec4d.h | 26 ++++++++++++++++++++ include/QF/simd/vec4f.h | 30 +++++++++++++++++++++++ libs/util/test/test-simd.c | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/include/QF/simd/vec4d.h b/include/QF/simd/vec4d.h index d608933f5..11e173eff 100644 --- a/include/QF/simd/vec4d.h +++ b/include/QF/simd/vec4d.h @@ -133,6 +133,14 @@ qrotd (vec4d_t a, vec4d_t b) return q; } +vec4d_t qconjd (vec4d_t q) __attribute__((const)); +vec4d_t +qconjd (vec4d_t q) +{ + const vec4l_t neg = { 1lu << 63, 1lu << 63, 1lu << 63, 0 }; + return _mm256_xor_pd (q, (__m256d) neg); +} + vec4d_t loadvec3d (const double v3[]) __attribute__((pure, access(read_only, 1))); vec4d_t loadvec3d (const double v3[]) @@ -153,4 +161,22 @@ void storevec3d (double v3[3], vec4d_t v4) v3[2] = v4[2]; } +vec4d_t vceild (vec4d_t v) __attribute__((const)); +vec4d_t vceild (vec4d_t v) +{ + return _mm256_ceil_pd (v); +} + +vec4d_t vfloord (vec4d_t v) __attribute__((const)); +vec4d_t vfloord (vec4d_t v) +{ + return _mm256_floor_pd (v); +} + +vec4d_t vtruncd (vec4d_t v) __attribute__((const)); +vec4d_t vtruncd (vec4d_t v) +{ + return _mm256_round_pd (v, _MM_FROUND_TRUNC); +} + #endif//__QF_simd_vec4d_h diff --git a/include/QF/simd/vec4f.h b/include/QF/simd/vec4f.h index ea92b81d9..e2e09c341 100644 --- a/include/QF/simd/vec4f.h +++ b/include/QF/simd/vec4f.h @@ -127,6 +127,18 @@ qrotf (vec4f_t a, vec4f_t b) return q; } +/** Return the conjugate of the quaternion. + * + * That is, [-x, -y, -z, w]. + */ +vec4f_t qconjf (vec4f_t q) __attribute__((const)); +vec4f_t +qconjf (vec4f_t q) +{ + const vec4i_t neg = { 1u << 31, 1u << 31, 1u << 31, 0 }; + return _mm_xor_ps (q, (__m128) neg); +} + vec4f_t loadvec3f (const float v3[3]) __attribute__((pure, access(read_only, 1))); vec4f_t loadvec3f (const float v3[3]) @@ -156,4 +168,22 @@ void storevec3f (float v3[3], vec4f_t v4) v3[2] = v4[2]; } +vec4f_t vceilf (vec4f_t v) __attribute__((const)); +vec4f_t vceilf (vec4f_t v) +{ + return _mm_ceil_ps (v); +} + +vec4f_t vfloorf (vec4f_t v) __attribute__((const)); +vec4f_t vfloorf (vec4f_t v) +{ + return _mm_floor_ps (v); +} + +vec4f_t vtruncf (vec4f_t v) __attribute__((const)); +vec4f_t vtruncf (vec4f_t v) +{ + return _mm_round_ps (v, _MM_FROUND_TRUNC); +} + #endif//__QF_simd_vec4f_h diff --git a/libs/util/test/test-simd.c b/libs/util/test/test-simd.c index ec1b145ac..8fcc6935c 100644 --- a/libs/util/test/test-simd.c +++ b/libs/util/test/test-simd.c @@ -39,6 +39,46 @@ typedef struct { vec4f_t ulp_errors; } vec4f_test_t; +static vec4d_t tvtruncd (vec4d_t v, vec4d_t ignore) +{ + return vtruncd (v); +} + +static vec4d_t tvceild (vec4d_t v, vec4d_t ignore) +{ + return vceild (v); +} + +static vec4d_t tvfloord (vec4d_t v, vec4d_t ignore) +{ + return vfloord (v); +} + +static vec4d_t tqconjd (vec4d_t v, vec4d_t ignore) +{ + return qconjd (v); +} + +static vec4f_t tvtruncf (vec4f_t v, vec4f_t ignore) +{ + return vtruncf (v); +} + +static vec4f_t tvceilf (vec4f_t v, vec4f_t ignore) +{ + return vceilf (v); +} + +static vec4f_t tvfloorf (vec4f_t v, vec4f_t ignore) +{ + return vfloorf (v); +} + +static vec4f_t tqconjf (vec4f_t v, vec4f_t ignore) +{ + return qconjf (v); +} + static vec4d_test_t vec4d_tests[] = { // 3D dot products { dotd, right, right, one }, @@ -140,6 +180,11 @@ static vec4d_test_t vec4d_tests[] = { { qrotd, up, forward, { -s05, 0, 0, s05 }, { 1.1e-16, 0, 0, 0} }, { qrotd, up, up, qident }, + + { tvtruncd, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -1, -2 } }, + { tvceild, { 1.1, 2.9, -1.1, -2.9 }, {}, { 2, 3, -1, -2 } }, + { tvfloord, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -2, -3 } }, + { tqconjd, one, {}, { -1, -1, -1, 1 } }, }; #define num_vec4d_tests (sizeof (vec4d_tests) / (sizeof (vec4d_tests[0]))) @@ -226,6 +271,11 @@ static vec4f_test_t vec4f_tests[] = { { qrotf, up, right, { 0, s05, 0, s05 } }, { qrotf, up, forward, { -s05, 0, 0, s05 } }, { qrotf, up, up, qident }, + + { tvtruncf, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -1, -2 } }, + { tvceilf, { 1.1, 2.9, -1.1, -2.9 }, {}, { 2, 3, -1, -2 } }, + { tvfloorf, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -2, -3 } }, + { tqconjf, one, {}, { -1, -1, -1, 1 } }, }; #define num_vec4f_tests (sizeof (vec4f_tests) / (sizeof (vec4f_tests[0]))) From 3125009a7c7779de7434deca6913b17ef5eb7eab Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 28 Dec 2020 14:56:59 +0900 Subject: [PATCH 158/435] [util] Add vector and quaternion types to cexpr Although there's no distinction between the two at the C level, I think it's probably best to separate them in a scripting language. --- include/QF/cexpr.h | 2 + include/QF/simd/vec4f.h | 4 +- libs/util/cexpr-type.c | 125 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 127 insertions(+), 4 deletions(-) diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index 0d2b4a8a4..e257412d6 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -112,6 +112,8 @@ extern exprtype_t cexpr_uint; extern exprtype_t cexpr_size_t; extern exprtype_t cexpr_float; extern exprtype_t cexpr_double; +extern exprtype_t cexpr_vector; +extern exprtype_t cexpr_quaternion; extern exprtype_t cexpr_exprval; extern exprtype_t cexpr_field; diff --git a/include/QF/simd/vec4f.h b/include/QF/simd/vec4f.h index e2e09c341..997127a94 100644 --- a/include/QF/simd/vec4f.h +++ b/include/QF/simd/vec4f.h @@ -99,8 +99,8 @@ qvmulf (vec4f_t q, vec4f_t v) // zero the scalar of the quaternion. Results in an extra operation, but // avoids adding precision issues. q = _mm_insert_ps (q, q, 0xf8); - vec4f_t c = crossf (q, v); // q.w is 0 so v.w is irrelevant - vec4f_t qv = dotf (q, v); + vec4f_t c = crossf (q, v); + vec4f_t qv = dotf (q, v); // q.w is 0 so v.w is irrelevant vec4f_t qq = dotf (q, q); return (s * s - qq) * v + 2 * (qv * q + s * c); diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index c1dbbafb0..81fc212cd 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -30,6 +30,8 @@ #include #include "QF/cexpr.h" +#include "QF/mathlib.h" +#include "QF/simd/vec4f.h" #include "libs/util/cexpr-parse.h" @@ -232,7 +234,7 @@ static void float_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, exprctx_t *ctx) { - // implement true modulo for integers: + // implement true modulo for floats: // 5 mod 3 = 2 // -5 mod 3 = 1 // 5 mod -3 = -1 @@ -242,6 +244,26 @@ float_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, *(float *) result->value = a - b * floorf (a / b); } +static void +float_mul_vec4f (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + float s = *(float *) val1->value; + __auto_type v = (vec4f_t *) val2->value; + __auto_type r = (vec4f_t *) result->value; + *r = s * *v; +} + +static void +float_div_quat (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + float a = *(float *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = a * qconjf (b) / dotf (b, b); +} + UNOP(float, pos, float, +) UNOP(float, neg, float, -) UNOP(float, tnot, float, !) @@ -250,7 +272,10 @@ binop_t float_binops[] = { { '+', &cexpr_float, &cexpr_float, float_add }, { '-', &cexpr_float, &cexpr_float, float_sub }, { '*', &cexpr_float, &cexpr_float, float_mul }, + { '*', &cexpr_vector, &cexpr_vector, float_mul_vec4f }, + { '*', &cexpr_quaternion, &cexpr_quaternion, float_mul_vec4f }, { '/', &cexpr_float, &cexpr_float, float_div }, + { '/', &cexpr_quaternion, &cexpr_quaternion, float_div_quat }, { '%', &cexpr_float, &cexpr_float, float_rem }, { MOD, &cexpr_float, &cexpr_float, float_mod }, {} @@ -288,7 +313,7 @@ static void double_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, exprctx_t *ctx) { - // implement true modulo for integers: + // implement true modulo for doubles: // 5 mod 3 = 2 // -5 mod 3 = 1 // 5 mod -3 = -1 @@ -326,6 +351,102 @@ exprtype_t cexpr_double = { double_unops, }; +BINOP(vector, add, vec4f_t, +) +BINOP(vector, sub, vec4f_t, -) +BINOP(vector, mul, vec4f_t, *) +BINOP(vector, div, vec4f_t, /) + +static void +vector_rem (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + vec4f_t a = *(vec4f_t *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = a - b * vtruncf (a / b); +} + +static void +vector_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, + exprctx_t *ctx) +{ + // implement true modulo for doubles: + // 5 mod 3 = 2 + // -5 mod 3 = 1 + // 5 mod -3 = -1 + // -5 mod -3 = -2 + vec4f_t a = *(vec4f_t *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = a - b * vfloorf (a / b); +} + +UNOP(vector, pos, vec4f_t, +) +UNOP(vector, neg, vec4f_t, -) + +static void +vector_tnot (const exprval_t *val, exprval_t *result, exprctx_t *ctx) +{ + vec4f_t v = *(vec4f_t *) val->value; + __auto_type c = (vec4i_t *) result->value; + *c = v != 0; +} + +binop_t vector_binops[] = { + { '+', &cexpr_vector, &cexpr_vector, vector_add }, + { '-', &cexpr_vector, &cexpr_vector, vector_sub }, + { '*', &cexpr_vector, &cexpr_vector, vector_mul }, + { '/', &cexpr_vector, &cexpr_vector, vector_div }, + { '%', &cexpr_vector, &cexpr_vector, vector_rem }, + { MOD, &cexpr_vector, &cexpr_vector, vector_mod }, + {} +}; + +unop_t vector_unops[] = { + { '+', &cexpr_vector, vector_pos }, + { '-', &cexpr_vector, vector_neg }, + { '!', &cexpr_vector, vector_tnot }, + {} +}; + +exprtype_t cexpr_vector = { + "vector", + sizeof (vec4f_t), + vector_binops, + vector_unops, +}; + +static void +quaternion_mul (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + vec4f_t a = *(vec4f_t *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = qmulf (a, b); +} + +binop_t quaternion_binops[] = { + { '+', &cexpr_quaternion, &cexpr_quaternion, vector_add }, + { '-', &cexpr_quaternion, &cexpr_quaternion, vector_sub }, + { '*', &cexpr_quaternion, &cexpr_quaternion, quaternion_mul }, + {} +}; + +unop_t quaternion_unops[] = { + { '+', &cexpr_vector, vector_pos }, + { '-', &cexpr_vector, vector_neg }, + { '!', &cexpr_vector, vector_tnot }, + {} +}; + +exprtype_t cexpr_quaternion = { + "quaterion", + sizeof (vec4f_t), + quaternion_binops, + quaternion_unops, +}; + exprtype_t cexpr_exprval = { "exprval", sizeof (exprval_t *), From 4039075f41dacb15a4a4f368bc433587f18b71b5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 29 Dec 2020 18:19:43 +0900 Subject: [PATCH 159/435] [util] Use a linked list of free cache lines The idea is to not search through blocks for an available allocation. While the goal was to speed up allocation of cache lines of varying cluster sizes, it's not enough due to fragmentation. --- include/QF/cmem.h | 18 +++- libs/util/cmem.c | 187 ++++++++++++++++++++++++------------- libs/util/test/test-cmem.c | 9 +- 3 files changed, 144 insertions(+), 70 deletions(-) diff --git a/include/QF/cmem.h b/include/QF/cmem.h index 966696d6c..dafdd97f9 100644 --- a/include/QF/cmem.h +++ b/include/QF/cmem.h @@ -32,9 +32,21 @@ #define MEM_LINE_SIZE 64 typedef struct memline_s { - struct memline_s *next; + /* chain of free line blocks for fast allocation + * chain begins in memsuper_t + */ + struct memline_s *free_next; + struct memline_s **free_prev; + /* chain of free line blocks within a membock for merging + * chain begins in memblock_t + */ + struct memline_s *block_next; + struct memline_s **block_prev; size_t size; - size_t pad[6]; + /* owning block + */ + struct memblock_s *block; + size_t pad[2]; } memline_t; typedef struct memsline_s { @@ -85,7 +97,7 @@ typedef struct memsuper_s { * allocated, and 64 bytes and up consume entire cache lines. */ memsline_t *last_freed[4]; - size_t pad; + memline_t *free_lines; } memsuper_t; memsuper_t *new_memsuper (void); diff --git a/libs/util/cmem.c b/libs/util/cmem.c index b446e58f0..d395eb78f 100644 --- a/libs/util/cmem.c +++ b/libs/util/cmem.c @@ -51,7 +51,32 @@ delete_memsuper (memsuper_t *super) free (super); } -static memblock_t * +static void +link_free_line (memsuper_t *super, memline_t *line) +{ + if (super->free_lines) { + super->free_lines->free_prev = &line->free_next; + } + line->free_next = super->free_lines; + line->free_prev = &super->free_lines; + super->free_lines = line; +} + +static void +unlink_line (memline_t *line) +{ + if (line->block_next) { + line->block_next->block_prev = line->block_prev; + } + *line->block_prev = line->block_next; + + if (line->free_next) { + line->free_next->free_prev = line->free_prev; + } + *line->free_prev = line->free_next; +} + +static memblock_t * __attribute__((noinline)) init_block (memsuper_t *super, void *mem, size_t alloc_size) { size_t size = super->page_size; @@ -78,14 +103,20 @@ init_block (memsuper_t *super, void *mem, size_t alloc_size) block->pre_size -= MEM_LINE_SIZE; } if (block->pre_size) { - block->free_lines = (memline_t *) ((size_t) block - block->pre_size); - block->free_lines->next = 0; - block->free_lines->size = block->pre_size; + memline_t *line = (memline_t *) ((size_t) block - block->pre_size); + + link_free_line (super, line); + + line->block = block; + line->block_next = 0; + line->block_prev = &block->free_lines; + block->free_lines = line; + line->size = block->pre_size; } return block; } -static memblock_t * +static memblock_t * __attribute__((noinline)) block_alloc (memsuper_t *super, size_t size) { memblock_t *block; @@ -111,38 +142,39 @@ block_alloc (memsuper_t *super, size_t size) return block; } -static void * -line_alloc (memblock_t *block, size_t size) +static void * __attribute__((noinline)) +alloc_line (memline_t *line, size_t size) { - memline_t **line = &block->free_lines; - memline_t **best = 0; - memline_t *mem; - size_t best_size = ~0u; + void *mem = line; - while (*line) { - if ((*line)->size >= size && (*line)->size < best_size) { - best_size = (*line)->size; - best = line; + if (line->size > size) { + // split the line block and insert the new block into the list + memline_t *split = (memline_t *)((size_t) line + size); + split->block = line->block; + split->size = line->size - size; + line->size = size; + + split->block_next = line->block_next; + if (split->block_next) { + split->block_next->block_prev = &split->block_next; } - line = &(*line)->next; + line->block_next = split; + split->block_prev = &line->block_next; + + split->free_next = line->free_next; + if (split->free_next) { + split->free_next->free_prev = &split->free_next; + } + line->free_next = split; + split->free_prev = &line->free_next; } - if (!best) { - return 0; - } - mem = *best; - if (size < best_size) { - *best = (memline_t *)((size_t) mem + size); - (*best)->next = mem->next; - (*best)->size = mem->size - size; - } else { - *best = (*best)->next; - } - block->pre_allocated += size; + line->block->pre_allocated += line->size; + unlink_line (line); return mem; } -static void -line_free (memblock_t *block, void *mem) +static void __attribute__((noinline)) +line_free (memsuper_t *super, memblock_t *block, void *mem) { //FIXME right now, can free only single lines (need allocated lines to // have a control block) @@ -152,37 +184,55 @@ line_free (memblock_t *block, void *mem) block->pre_allocated -= size; - for (l = &block->free_lines; *l; l = &(*l)->next) { + for (l = &block->free_lines; *l; l = &(*l)->block_next) { line = *l; - + if (line->block_next && line->block_next < line) { + *(int *)0 = 0; + } if ((size_t) mem + size < (size_t) line) { // line to be freed is below the free line break; } if ((size_t) mem + size == (size_t) line) { // line to be freed is immediately below the free line - // merge with the free line + // merge with the free line by "allocating" the line and then + // "freeing" it with the line to be freed size += line->size; - line = line->next; + unlink_line (line); // does not modify line->block_next + line = line->block_next; break; } if ((size_t) line + line->size == (size_t) mem) { // line to be freed is immediately above the free line - // merge with the free line + // merge with the free line by growing the line line->size += size; - if (line->next && (size_t) line->next == (size_t) mem + size) { - line->size += line->next->size; - line->next = line->next->next; + if (line->block_next + && (size_t) line->block_next == (size_t) mem + size) { + // the line to be freed connects two free lines + line->size += line->block_next->size; + unlink_line (line->block_next); } return; } + if ((size_t) mem >= (size_t) line + && (size_t) mem < (size_t) line + line->size) { + *(int *) 0 = 0; + } + line = 0; } - ((memline_t *) mem)->next = line; - ((memline_t *) mem)->size = size; - *l = mem; + memline_t *memline = (memline_t *) mem; + memline->block_next = line; + if (memline->block_next) { + memline->block_next->block_prev = &memline->block_next; + } + memline->block_prev = l; + memline->size = size; + memline->block = block; + *l = memline; + link_free_line (super, memline); } -static memsline_t * +static memsline_t * __attribute__((noinline)) sline_new (memsuper_t *super, size_t size_ind) { size_t size = 4 << size_ind; @@ -224,26 +274,29 @@ cmemalloc (memsuper_t *super, size_t size) size = 4 << ind; if (size >= MEM_LINE_SIZE) { // whole cache lines are required for this object - // FIXME slow - memblock_t *block = super->memblocks; - void *mem; + memline_t *line = super->free_lines; - while (block) { - if ((mem = line_alloc (block, size))) { - return mem; - } - block = block->next; + while (line && line->size < size) { + line = line->free_next; } - /* The cache-line pool is page aligned for two reasons: - * 1) so it fits exactly within a page - * 2) the control block can be found easily - * And the reason the pool is exactly one page large is so no - * allocated line is ever page-aligned as that would make the line - * indistinguishable from a large block. - */ - mem = aligned_alloc (super->page_size, super->page_size); - block = init_block (super, mem, super->page_size); - return line_alloc (block, size); + if (!line) { + // need a new line, one that doesn't make me fe... wrong song + void *mem; + /* The cache-line pool is page aligned for two reasons: + * 1) so it fits exactly within a page + * 2) the control block can be found easily + * And the reason the pool is exactly one page large is so no + * allocated line is ever page-aligned as that would make the + * line indistinguishable from a large block. + */ + mem = aligned_alloc (super->page_size, super->page_size); + // sets super->free_lines, the block is guarnateed to be big + // enough to hold the requested allocation as otherwise a full + // block allocation would have been used + init_block (super, mem, super->page_size); + line = super->free_lines; + } + return alloc_line (line, size);; } else { void *mem = 0; memsline_t **sline = &super->last_freed[ind]; @@ -273,9 +326,15 @@ cmemalloc (memsuper_t *super, size_t size) return 0; } -static void +static void __attribute__((noinline)) unlink_block (memblock_t *block) { + if (block->pre_size) { + if (!block->free_lines || block->free_lines->block_next) { + *(int *) 0 = 0; + } + unlink_line (block->free_lines); + } if (block->next) { block->next->prev = block->prev; } @@ -303,7 +362,9 @@ cmemfree (memsuper_t *super, void *mem) *(memsline_t **) (size_t)(sline->prev << 6) = sline->next; } - (*super_sline)->prev = (size_t) &sline->next >> 6; + if (*super_sline) { + (*super_sline)->prev = (size_t) &sline->next >> 6; + } sline->next = *super_sline; sline->prev = (size_t) super_sline >> 6; (*super_sline) = sline; @@ -314,7 +375,7 @@ cmemfree (memsuper_t *super, void *mem) size_t page_size = super->page_size; size_t page_mask = super->page_mask; block = (memblock_t *) (((size_t) mem + page_size) & ~page_mask) - 1; - line_free (block, mem); + line_free (super, block, mem); } else { // large block block = (memblock_t *) mem - 1; diff --git a/libs/util/test/test-cmem.c b/libs/util/test/test-cmem.c index c8c2ee7e3..6acd76c33 100644 --- a/libs/util/test/test-cmem.c +++ b/libs/util/test/test-cmem.c @@ -90,7 +90,7 @@ test_line (memsuper_t *super) fprintf (stderr, "line3 not contiguous with free lines\n"); return 0; } - if (block->free_lines->next) { + if (block->free_lines->block_next) { fprintf (stderr, "multiple free line blocks\n"); return 0; } @@ -117,11 +117,12 @@ test_line (memsuper_t *super) fprintf (stderr, "free lines not pointing to line2\n"); return 0; } - if (!block->free_lines->next || block->free_lines->next->next) { + if (!block->free_lines->block_next + || block->free_lines->block_next->block_next) { fprintf (stderr, "incorrect number of free blocks\n"); return 0; } - if (line2->next != old_line || old_line->size != old_size) { + if (line2->block_next != old_line || old_line->size != old_size) { fprintf (stderr, "free line blocks corrupted\n"); return 0; } @@ -254,7 +255,7 @@ main (void) if (sizeof (memsuper_t) != MEM_LINE_SIZE) { fprintf (stderr, "memsuper_t not cache size: %zd\n", - sizeof (memline_t)); + sizeof (memsuper_t)); return 1; } if (sizeof (memline_t) != MEM_LINE_SIZE) { From 73544f07908e18a29f12dd7261fe381d2e0a7160 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 29 Dec 2020 20:42:39 +0900 Subject: [PATCH 160/435] [util] Split cmem's free cache-line over size bins They're binned by powers of two (with in between sizes going to the smaller bin should I make cache-line allocations NPOT (which I think might be worthwhile). However, there seems to still be a bug somewhere causing a nasty leak as now my hacked qfvis consumes 40G in less than a minute. --- include/QF/cmem.h | 12 +++++++++++- libs/util/cmem.c | 38 +++++++++++++++++++++++++++----------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/include/QF/cmem.h b/include/QF/cmem.h index dafdd97f9..5f0d733ea 100644 --- a/include/QF/cmem.h +++ b/include/QF/cmem.h @@ -30,6 +30,7 @@ #include "QF/qtypes.h" #define MEM_LINE_SIZE 64 +#define MAX_CACHE_LINES 9 typedef struct memline_s { /* chain of free line blocks for fast allocation @@ -97,7 +98,16 @@ typedef struct memsuper_s { * allocated, and 64 bytes and up consume entire cache lines. */ memsline_t *last_freed[4]; - memline_t *free_lines; + /* Free chache lines grouped by size. + * + * The index is the base-2 log of the MINIMUM number of cache lines + * available in each block. ie, blocks with 4, 5, 6 and 7 lines will all + * be in the third list (index 2). For 4k page sizes, only 6 lists are + * needed (32-63 lines) because a page can hold only 62 lines (1 for the + * control block and one to avoid a cache-line being on a page boundary). + * Having 9 (MAX_CACHE_LINES) lists allows page sizes up to 16kB. + */ + memline_t *free_lines[MAX_CACHE_LINES]; } memsuper_t; memsuper_t *new_memsuper (void); diff --git a/libs/util/cmem.c b/libs/util/cmem.c index d395eb78f..c98eeb389 100644 --- a/libs/util/cmem.c +++ b/libs/util/cmem.c @@ -29,6 +29,15 @@ #include "QF/alloc.h" #include "QF/cmem.h" +static size_t __attribute__((const)) +ilog2 (size_t x) +{ + size_t l = 0; + while (x >>= 1) { + l++; + } + return l; +} memsuper_t * new_memsuper (void) @@ -54,12 +63,13 @@ delete_memsuper (memsuper_t *super) static void link_free_line (memsuper_t *super, memline_t *line) { - if (super->free_lines) { - super->free_lines->free_prev = &line->free_next; + size_t ind = ilog2 (line->size) - 6; + if (super->free_lines[ind]) { + super->free_lines[ind]->free_prev = &line->free_next; } - line->free_next = super->free_lines; - line->free_prev = &super->free_lines; - super->free_lines = line; + line->free_next = super->free_lines[ind]; + line->free_prev = &super->free_lines[ind]; + super->free_lines[ind] = line; } static void @@ -105,13 +115,14 @@ init_block (memsuper_t *super, void *mem, size_t alloc_size) if (block->pre_size) { memline_t *line = (memline_t *) ((size_t) block - block->pre_size); - link_free_line (super, line); - line->block = block; + line->size = block->pre_size; + line->block_next = 0; line->block_prev = &block->free_lines; block->free_lines = line; - line->size = block->pre_size; + + link_free_line (super, line); } return block; } @@ -274,8 +285,13 @@ cmemalloc (memsuper_t *super, size_t size) size = 4 << ind; if (size >= MEM_LINE_SIZE) { // whole cache lines are required for this object - memline_t *line = super->free_lines; + // convert from byte log2 to cache-line log2 + ind -= 4; + memline_t *line = 0; + while (!line && ind < MAX_CACHE_LINES) { + line = super->free_lines[ind++]; + } while (line && line->size < size) { line = line->free_next; } @@ -293,8 +309,8 @@ cmemalloc (memsuper_t *super, size_t size) // sets super->free_lines, the block is guarnateed to be big // enough to hold the requested allocation as otherwise a full // block allocation would have been used - init_block (super, mem, super->page_size); - line = super->free_lines; + memblock_t *block = init_block (super, mem, super->page_size); + line = block->free_lines; } return alloc_line (line, size);; } else { From d12abc513259b88898a933456a2fbbfcb9c51d4f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 30 Dec 2020 01:47:53 +0900 Subject: [PATCH 161/435] [util] Relink grown free line block This fixes one source of memory leaks, but it seems some are still lurking as qfvis still leaks like a sieve. --- libs/util/cmem.c | 17 +- libs/util/test/test-cmem.c | 337 ++++++++++++++++++++++++++++++++----- 2 files changed, 307 insertions(+), 47 deletions(-) diff --git a/libs/util/cmem.c b/libs/util/cmem.c index c98eeb389..cc55ef01a 100644 --- a/libs/util/cmem.c +++ b/libs/util/cmem.c @@ -72,6 +72,15 @@ link_free_line (memsuper_t *super, memline_t *line) super->free_lines[ind] = line; } +static void +unlink_free_line (memline_t *line) +{ + if (line->free_next) { + line->free_next->free_prev = line->free_prev; + } + *line->free_prev = line->free_next; +} + static void unlink_line (memline_t *line) { @@ -80,10 +89,7 @@ unlink_line (memline_t *line) } *line->block_prev = line->block_next; - if (line->free_next) { - line->free_next->free_prev = line->free_prev; - } - *line->free_prev = line->free_next; + unlink_free_line (line); } static memblock_t * __attribute__((noinline)) @@ -223,6 +229,9 @@ line_free (memsuper_t *super, memblock_t *block, void *mem) line->size += line->block_next->size; unlink_line (line->block_next); } + // the line changed size so needs to be relinked in the super + unlink_free_line (line); + link_free_line (super, line); return; } if ((size_t) mem >= (size_t) line diff --git a/libs/util/test/test-cmem.c b/libs/util/test/test-cmem.c index 6acd76c33..107c20ad4 100644 --- a/libs/util/test/test-cmem.c +++ b/libs/util/test/test-cmem.c @@ -1,9 +1,10 @@ #include -#include +#include #include #include #include "QF/cmem.h" +#include "QF/set.h" static int test_block (memsuper_t *super) @@ -46,6 +47,133 @@ test_block (memsuper_t *super) return 1; } +static int +check_block (memblock_t *block, int line_count, int allocated) +{ + set_t *visited = set_new (); + size_t free_bytes = 0; + int ret = 1; + int count = 0; + + for (memline_t **l = &block->free_lines; *l; l = &(*l)->block_next) { + memline_t *line = *l; + ptrdiff_t ind = (memline_t *) block - line; + if (ind < 1 || (size_t ) ind > block->pre_size / MEM_LINE_SIZE) { + fprintf (stderr, "line outside of block\n"); + return 0; + } + if (set_is_member (visited, ind)) { + fprintf (stderr, "loop in block free_lines\n"); + return 0; + } + count++; + set_add (visited, ind); + if (!line->size) { + fprintf (stderr, "line with size 0\n"); + ret = 0; + } + if (line->block_next && line->block_next < line) { + fprintf (stderr, "line link in wrong direction\n"); + ret = 0; + } + if ((size_t) line + line->size == (size_t) line->block_next) { + fprintf (stderr, "adjacant free line blocks\n"); + ret = 0; + } + if (line->block_prev != l) { + fprintf (stderr, "line block_prev link incorrect\n"); + ret = 0; + } + if (line->size > block->pre_size) { + fprintf (stderr, "line size too large: %zd / %zd\n", + line->size, block->pre_size); + ret = 0; + } + if (line->size % MEM_LINE_SIZE) { + fprintf (stderr, "bad line size: %zd / %zd\n", + line->size, line->size % MEM_LINE_SIZE); + ret = 0; + } + if (ret) { + free_bytes += line->size; + } + } + if (ret) { + if (free_bytes + block->pre_allocated != block->pre_size) { + fprintf (stderr, "block space mismatch: s: %zd a: %zd f: %zd\n", + block->pre_size, block->pre_allocated, free_bytes); + ret = 0; + } + if (line_count >= 0 && line_count != count) { + fprintf (stderr, "incorrect number of lines: e: %d g: %d\n", + line_count, count); + ret = 0; + } + if (allocated >= 0 && (size_t) allocated != block->pre_allocated) { + fprintf (stderr, "pre_allocated wrong size: %zd != %d\n", + block->pre_allocated, allocated); + } + } + set_delete (visited); + return ret; +} + +static int +check_for_loop (memline_t *line, memline_t **stop) +{ + memline_t *next = line->free_next; + + for (memline_t **l = line->free_prev; l != stop; + l = line->free_prev) { + line = (memline_t *) l; + if (line == next) { + return 1; + } + } + return 0; +} + +static int +check_bins (memsuper_t *super, int mask) +{ + int ret = 1; + for (int i = MAX_CACHE_LINES; i-- > 0; ) { + if (mask >= 0) { + if (mask & (1 << i)) { + if (!super->free_lines[i]) { + fprintf (stderr, "super free_lines[%d] is empty\n", i); + ret = 0; + } + } else { + if (super->free_lines[i]) { + fprintf (stderr, "super free_lines[%d] is occupied\n", i); + ret = 0; + } + } + } + for (memline_t **l = &super->free_lines[i]; *l; l = &(*l)->free_next) { + memline_t *line = *l; + if (line->free_prev != l) { + fprintf (stderr, "super free_lines[%d] has bad prev\n", i); + ret = 0; + break; + } + if (check_for_loop (line, &super->free_lines[i])) { + fprintf (stderr, "super free_lines[%d] loop detected\n", i); + ret = 0; + break; + } + if ((MEM_LINE_SIZE << i) > (int) line->size + || (MEM_LINE_SIZE << (i + 1)) <= (int) line->size) { + fprintf (stderr, "line in wrong i: %d %d %zd\n", + i, MEM_LINE_SIZE << i, line->size); + ret = 0; + } + } + } + return ret; +} + static int test_line (memsuper_t *super) { @@ -90,68 +218,153 @@ test_line (memsuper_t *super) fprintf (stderr, "line3 not contiguous with free lines\n"); return 0; } - if (block->free_lines->block_next) { - fprintf (stderr, "multiple free line blocks\n"); + + if (!check_block (block, 1, 3 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 1 failed\n"); return 0; } - if (block->pre_allocated != 3 * MEM_LINE_SIZE) { - fprintf (stderr, "pre_allocated wrong size: %zd != %d\n", - block->pre_allocated, 3 * MEM_LINE_SIZE); + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 1 failed\n"); return 0; } - if (block->free_lines->size != block->pre_size - block->pre_allocated) { - fprintf (stderr, "free lines wrong size: %zd != %zd\n", - block->free_lines->size, - block->pre_size - block->pre_allocated); - return 0; - } - size_t old_size = block->free_lines->size; - memline_t *old_line = block->free_lines; + cmemfree (super, line2); - if (block->pre_allocated != 2 * MEM_LINE_SIZE) { - fprintf (stderr, "pre_allocated wrong size: %zd != %d\n", - block->pre_allocated, 2 * MEM_LINE_SIZE); + + if (!check_block (block, 2, 2 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 2 failed\n"); return 0; } + if (!check_bins (super, 0x21)) { + fprintf (stderr, "bin check 2 failed\n"); + return 0; + } + if (block->free_lines != line2) { - fprintf (stderr, "free lines not pointing to line2\n"); + fprintf (stderr, "block free_lines not pointing to line2\n"); return 0; } - if (!block->free_lines->block_next - || block->free_lines->block_next->block_next) { - fprintf (stderr, "incorrect number of free blocks\n"); - return 0; - } - if (line2->block_next != old_line || old_line->size != old_size) { - fprintf (stderr, "free line blocks corrupted\n"); - return 0; - } - if (block->free_lines->size != MEM_LINE_SIZE) { - fprintf (stderr, "free line block wrong size: %zd != %d\n", - block->free_lines->size, MEM_LINE_SIZE); + if (super->free_lines[0] != line2) { + fprintf (stderr, "super free_lines[0] not pointing to line2\n"); return 0; } + cmemfree (super, line3); + if (!check_block (block, 1, 1 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 3 failed\n"); + return 0; + } + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 3 failed\n"); + return 0; + } + if (block->free_lines != line2) { fprintf (stderr, "free lines not pointing to line2 2\n"); return 0; } - if (block->pre_allocated != MEM_LINE_SIZE) { - fprintf (stderr, "pre_allocated wrong size: %zd != %d\n", - block->pre_allocated, MEM_LINE_SIZE); - return 0; - } - if (block->free_lines->size != block->pre_size - block->pre_allocated) { - fprintf (stderr, "free lines wrong size: %zd != %zd\n", - block->free_lines->size, - block->pre_size - block->pre_allocated); - return 0; - } + cmemfree (super, line1); if (super->memblocks) { fprintf (stderr, "line pool not freed\n"); return 0; } + if (!check_bins (super, 0x00)) { + fprintf (stderr, "bins not cleared\n"); + return 0; + } + + line1 = cmemalloc (super, MEM_LINE_SIZE); + line2 = cmemalloc (super, MEM_LINE_SIZE); + line3 = cmemalloc (super, MEM_LINE_SIZE); + block = super->memblocks; + + if (!check_block (block, 1, 3 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 4 failed\n"); + return 0; + } + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 4 failed\n"); + return 0; + } + + cmemfree (super, line1); + + if (!check_block (block, 2, 2 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 5 failed\n"); + return 0; + } + if (!check_bins (super, 0x21)) { + fprintf (stderr, "bin check 5 failed\n"); + return 0; + } + + cmemfree (super, line2); + + if (!check_block (block, 2, 1 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 6 failed\n"); + return 0; + } + if (!check_bins (super, 0x22)) { + fprintf (stderr, "bin check 6 failed\n"); + return 0; + } + + cmemfree (super, line3); + if (super->memblocks) { + fprintf (stderr, "line pool not freed 2\n"); + return 0; + } + if (!check_bins (super, 0x00)) { + fprintf (stderr, "bins not cleared 2\n"); + return 0; + } + + line1 = cmemalloc (super, MEM_LINE_SIZE); + line2 = cmemalloc (super, MEM_LINE_SIZE); + line3 = cmemalloc (super, MEM_LINE_SIZE); + block = super->memblocks; + + if (!check_block (block, 1, 3 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 7 failed\n"); + return 0; + } + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 7 failed\n"); + return 0; + } + + cmemfree (super, line3); + + if (!check_block (block, 1, 2 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 8 failed\n"); + return 0; + } + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 8 failed\n"); + return 0; + } + + cmemfree (super, line2); + + if (!check_block (block, 1, 1 * MEM_LINE_SIZE)) { + fprintf (stderr, "line block check 9 failed\n"); + return 0; + } + if (!check_bins (super, 0x20)) { + fprintf (stderr, "bin check 9 failed\n"); + return 0; + } + + cmemfree (super, line1); + if (super->memblocks) { + fprintf (stderr, "line pool not freed 3\n"); + return 0; + } + if (!check_bins (super, 0x00)) { + fprintf (stderr, "bins not cleared 3\n"); + return 0; + } + return 1; } @@ -252,9 +465,10 @@ int main (void) { memsuper_t *super = new_memsuper (); + int i; - if (sizeof (memsuper_t) != MEM_LINE_SIZE) { - fprintf (stderr, "memsuper_t not cache size: %zd\n", + if (sizeof (memsuper_t) != 2 * MEM_LINE_SIZE) { + fprintf (stderr, "memsuper_t not 2 * cache size: %zd\n", sizeof (memsuper_t)); return 1; } @@ -301,13 +515,50 @@ main (void) fprintf (stderr, "super block list not null\n"); return 1; } + for (i = 4; i-- > 0; ) { + if (super->last_freed[i]) { + break; + } + } + if (i >= 0) { + fprintf (stderr, "super last_freed not all null\n"); + return 1; + } + for (i = MAX_CACHE_LINES; i-- > 0; ) { + if (super->free_lines[i]) { + break; + } + } + if (i >= 0) { + fprintf (stderr, "super free_lines not all null\n"); + return 1; + } if (!test_block (super)) { fprintf (stderr, "block tests failed\n"); + return 1; } if (super->memblocks) { fprintf (stderr, "super block list not null 2\n"); return 1; } + for (i = 4; i-- > 0; ) { + if (super->last_freed[i]) { + break; + } + } + if (i >= 0) { + fprintf (stderr, "super last_freed not all null 2\n"); + return 1; + } + for (i = MAX_CACHE_LINES; i-- > 0; ) { + if (super->free_lines[i]) { + break; + } + } + if (i >= 0) { + fprintf (stderr, "super free_lines not all null 2\n"); + return 1; + } if (!test_line (super)) { fprintf (stderr, "line tests failed\n"); return 1; From 9090c535192c7318f681e39787e9c10b79f8b8c7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 30 Dec 2020 11:07:12 +0900 Subject: [PATCH 162/435] [util] Add failing sub-line allocator tests I think the sub-line allocator falling over is the final source of qfvis's leaks. It certainly causes a mess of the sub-lines. But having some tests to get working sure beats scratching my head over qfvis :) --- libs/util/test/test-cmem.c | 109 +++++++++++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 22 deletions(-) diff --git a/libs/util/test/test-cmem.c b/libs/util/test/test-cmem.c index 107c20ad4..3d995ba42 100644 --- a/libs/util/test/test-cmem.c +++ b/libs/util/test/test-cmem.c @@ -368,40 +368,105 @@ test_line (memsuper_t *super) return 1; } +typedef struct { + size_t size; + int group_id; +} sline_block_t; + +static sline_block_t group_tests[] = { + { 2, 4}, + { 4, 4}, + { 5, 8}, + { 3, 4}, + { 1, 4}, + { 6, 8}, + { 9, 16}, + { 4, 4}, + { 4, 4}, + { 7, 8}, + { 2, 4}, + { 4, 4}, + { 8, 8}, + {13, 16}, + { 3, 4}, + { 1, 4}, + { 8, 8}, + { 8, 8}, + { 4, 4}, + { 4, 4}, + {16, 16}, + {32, 32}, + {32, 33}, +}; +#define num_group_tests (sizeof (group_tests) / sizeof (group_tests[0])) +#define mask(x) (((size_t) (x)) & ~(MEM_LINE_SIZE - 1)) +#define pagemask(x,o,s) (((size_t) (x)) & (o (s)->page_mask)) + static int test_sline (memsuper_t *super) { - void *mem[] = { - //cmemalloc (super, 2), // smaller than min size - cmemalloc (super, 4), - cmemalloc (super, 4), - cmemalloc (super, 8), - cmemalloc (super, 8), - cmemalloc (super, 16), - cmemalloc (super, 16), - cmemalloc (super, 32), - cmemalloc (super, 32), - }; -#define mem_size (sizeof (mem) / sizeof (mem[0])) - int fail = 0; - for (size_t i = 0; i < mem_size; i++) { - printf("%p\n", mem[i]); + void *mem[num_group_tests]; + int ret = 1; + + for (size_t i = 0; i < num_group_tests; i++) { + mem[i] = cmemalloc (super, group_tests[i].size); if (!mem[i]) { fprintf (stderr, "mem[%zd] is null\n", i); - fail = 1; + return 0; } - for (size_t j = i + 1; j < mem_size; j++) { + if (!((size_t) mem[i] % MEM_LINE_SIZE)) { + fprintf (stderr, "mem[%zd] is aligned with chache line\n", i); + ret = 0; + } + } + for (size_t i = 0; i < num_group_tests; i++) { + for (size_t j = i + 1; j < num_group_tests; j++) { if (mem[i] == mem[j]) { fprintf (stderr, "mem[%zd] is dupped with %zd\n", i, j); - fail = 1; + ret = 0; + } + if (mask (mem[i]) == mask (mem[j])) { + if (group_tests[i].group_id != group_tests[j].group_id) { + fprintf (stderr, "mem[%zd](%d) is grouped with %zd(%d)\n", + i, group_tests[i].group_id, + j, group_tests[j].group_id); + ret = 0; + } + } else { + if (group_tests[i].group_id == group_tests[j].group_id) { + fprintf (stderr, + "mem[%zd](%d) is not grouped with %zd(%d)\n", + i, group_tests[i].group_id, + j, group_tests[j].group_id); + ret = 0; + } + } + if (pagemask (mem[i], ~, super) != pagemask (mem[j], ~, super)) { + fprintf (stderr, + "mem[%zd](%d) is not block grouped with %zd(%d)\n", + i, group_tests[i].group_id, + j, group_tests[j].group_id); } } } - if (fail) { - return 0; + for (size_t i = 0; i < num_group_tests; i++) { + cmemfree (super, mem[i]); + void *newmem = cmemalloc (super, group_tests[i].size); + if (newmem != mem[i]) { + fprintf (stderr, + "%2zd bytes not recycled (%2zd,%2d) (%06zx %06zx)\n", + group_tests[i].size, i, group_tests[i].group_id, + pagemask (mem[i], ~~, super), + pagemask (newmem, ~~, super)); + ret = 0; + } + if (!((size_t) newmem % MEM_LINE_SIZE)) { + fprintf (stderr, "newmem is aligned with chache line %p\n", + newmem); + ret = 0; + } } -#undef mem_size - return 1; + return ret; } static int From efdbd59909202933706e3b7a139a1fdde84c2fed Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 30 Dec 2020 18:12:28 +0900 Subject: [PATCH 163/435] [util] Fix handling of sline's list 'pointer' I forgot to right-shift the value so offsets were becoming 0 or 8 instead of 0-15. This fixes the management of small objects. It turns out that after this fix, qfvis's problems were caused by fragmentation in the windings. Need to revisit line allocation and use POT-specialized pools. --- libs/util/cmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/util/cmem.c b/libs/util/cmem.c index cc55ef01a..77060f8f8 100644 --- a/libs/util/cmem.c +++ b/libs/util/cmem.c @@ -377,7 +377,7 @@ cmemfree (memsuper_t *super, void *mem) // sub line block sline = (memsline_t *) ((size_t) mem & ~(MEM_LINE_SIZE - 1)); *(uint16_t *) mem = sline->list << 2; - sline->list = (size_t) mem & (MEM_LINE_SIZE - 1); + sline->list = ((size_t) mem & (MEM_LINE_SIZE - 1)) >> 2; super_sline = &super->last_freed[sline->size]; if (*super_sline != sline) { if (sline->next) { From 1fd02322f45d0e0bc5f57ff70e2f23c3732554bb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 1 Jan 2021 19:53:39 +0900 Subject: [PATCH 164/435] [util] Clean up some minor issues in cmem I forgot to remove the noinline attribute and do a check with optimization (to catch the "pure" recommendation). --- libs/util/cmem.c | 12 ++++++------ libs/util/test/test-cmem.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libs/util/cmem.c b/libs/util/cmem.c index 77060f8f8..9dc461b87 100644 --- a/libs/util/cmem.c +++ b/libs/util/cmem.c @@ -92,7 +92,7 @@ unlink_line (memline_t *line) unlink_free_line (line); } -static memblock_t * __attribute__((noinline)) +static memblock_t * init_block (memsuper_t *super, void *mem, size_t alloc_size) { size_t size = super->page_size; @@ -133,7 +133,7 @@ init_block (memsuper_t *super, void *mem, size_t alloc_size) return block; } -static memblock_t * __attribute__((noinline)) +static memblock_t * block_alloc (memsuper_t *super, size_t size) { memblock_t *block; @@ -159,7 +159,7 @@ block_alloc (memsuper_t *super, size_t size) return block; } -static void * __attribute__((noinline)) +static void * alloc_line (memline_t *line, size_t size) { void *mem = line; @@ -190,7 +190,7 @@ alloc_line (memline_t *line, size_t size) return mem; } -static void __attribute__((noinline)) +static void line_free (memsuper_t *super, memblock_t *block, void *mem) { //FIXME right now, can free only single lines (need allocated lines to @@ -252,7 +252,7 @@ line_free (memsuper_t *super, memblock_t *block, void *mem) link_free_line (super, memline); } -static memsline_t * __attribute__((noinline)) +static memsline_t * sline_new (memsuper_t *super, size_t size_ind) { size_t size = 4 << size_ind; @@ -351,7 +351,7 @@ cmemalloc (memsuper_t *super, size_t size) return 0; } -static void __attribute__((noinline)) +static void unlink_block (memblock_t *block) { if (block->pre_size) { diff --git a/libs/util/test/test-cmem.c b/libs/util/test/test-cmem.c index 3d995ba42..4f146ccc7 100644 --- a/libs/util/test/test-cmem.c +++ b/libs/util/test/test-cmem.c @@ -118,7 +118,7 @@ check_block (memblock_t *block, int line_count, int allocated) return ret; } -static int +static int __attribute__ ((pure)) check_for_loop (memline_t *line, memline_t **stop) { memline_t *next = line->free_next; From 7bf90e5f4a8659da87af15c50b2580988ad36405 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 1 Jan 2021 19:49:20 +0900 Subject: [PATCH 165/435] [util] Sort out implementation issues for simd --- include/QF/simd/vec4d.h | 192 ++++++++++++++++++++++++++----------- include/QF/simd/vec4f.h | 192 +++++++++++++++++++++++++------------ libs/util/Makemodule.am | 1 + libs/util/simd.c | 37 +++++++ libs/util/test/test-simd.c | 4 + 5 files changed, 308 insertions(+), 118 deletions(-) create mode 100644 libs/util/simd.c diff --git a/include/QF/simd/vec4d.h b/include/QF/simd/vec4d.h index 11e173eff..6bd984357 100644 --- a/include/QF/simd/vec4d.h +++ b/include/QF/simd/vec4d.h @@ -32,13 +32,107 @@ #include "QF/simd/types.h" +GNU89INLINE inline vec4d_t vsqrtd (vec4d_t v) __attribute__((const)); +GNU89INLINE inline vec4d_t vceild (vec4d_t v) __attribute__((const)); +GNU89INLINE inline vec4d_t vfloord (vec4d_t v) __attribute__((const)); +GNU89INLINE inline vec4d_t vtruncd (vec4d_t v) __attribute__((const)); /** 3D vector cross product. * * The w (4th) component can be any value on input, and is guaranteed to be 0 * in the result. The result is not affected in any way by either vector's w * componemnt */ -vec4d_t crossd (vec4d_t a, vec4d_t b) __attribute__((const)); +GNU89INLINE inline vec4d_t crossd (vec4d_t a, vec4d_t b) __attribute__((const)); +/** 4D vector dot product. + * + * The w component *IS* significant, but if it is 0 in either vector, then + * the result will be as for a 3D dot product. + * + * Note that the dot product is in all 4 of the return value's elements. This + * helps optimize vector math as the scalar is already pre-spread. If just the + * scalar is required, use result[0]. + */ +GNU89INLINE inline vec4d_t dotd (vec4d_t a, vec4d_t b) __attribute__((const)); +/** Quaternion product. + * + * The vector is interpreted as a quaternion instead of a regular 4D vector. + * The quaternion may be of any magnitude, so this is more generally useful. + * than if the quaternion was required to be unit length. + */ +GNU89INLINE inline vec4d_t qmuld (vec4d_t a, vec4d_t b) __attribute__((const)); +/** Optimized quaterion-vector multiplication for vector rotation. + * + * If the vector's w component is not zero, then the result's w component + * is the cosine of the full rotation angle scaled by the vector's w component. + * The quaternion is assumed to be unit. If the quaternion is not unit, the + * vector will be scaled by the square of the quaternion's magnitude. + */ +GNU89INLINE inline vec4d_t qvmuld (vec4d_t q, vec4d_t v) __attribute__((const)); +/** Create the quaternion representing the shortest rotation from a to b. + * + * Both a and b are assumed to be 3D vectors (w components 0), but a resonable + * (but incorrect) result will still be produced if either a or b is a 4D + * vector. The rotation axis will be the same as if both vectors were 3D, but + * the magnitude of the rotation will be different. + */ +GNU89INLINE inline vec4d_t qrotd (vec4d_t a, vec4d_t b) __attribute__((const)); +/** Return the conjugate of the quaternion. + * + * That is, [-x, -y, -z, w]. + */ +GNU89INLINE inline vec4d_t qconjd (vec4d_t q) __attribute__((const)); +GNU89INLINE inline vec4d_t loadvec3d (const double v3[]) __attribute__((pure, access(read_only, 1))); +GNU89INLINE inline void storevec3d (double v3[3], vec4d_t v4) __attribute__((access (write_only, 1))); + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +vsqrtd (vec4d_t v) +{ + return _mm256_sqrt_pd (v); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +vceild (vec4d_t v) +{ + return _mm256_ceil_pd (v); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +vfloord (vec4d_t v) +{ + return _mm256_floor_pd (v); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +vtruncd (vec4d_t v) +{ + return _mm256_round_pd (v, _MM_FROUND_TRUNC); +} + +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4d_t crossd (vec4d_t a, vec4d_t b) { @@ -49,16 +143,11 @@ crossd (vec4d_t a, vec4d_t b) return __builtin_shuffle(c, A); } -/** 4D vector dot product. - * - * The w component *IS* significant, but if it is 0 in either vector, then - * the result will be as for a 3D dot product. - * - * Note that the dot product is in all 4 of the return value's elements. This - * helps optimize vector math as the scalar is already pre-spread. If just the - * scalar is required, use result[0]. - */ -vec4d_t dotd (vec4d_t a, vec4d_t b) __attribute__((const)); +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4d_t dotd (vec4d_t a, vec4d_t b) { @@ -69,13 +158,11 @@ dotd (vec4d_t a, vec4d_t b) return c; } -/** Quaternion product. - * - * The vector is interpreted as a quaternion instead of a regular 4D vector. - * The quaternion may be of any magnitude, so this is more generally useful. - * than if the quaternion was required to be unit length. - */ -vec4d_t qmuld (vec4d_t a, vec4d_t b) __attribute__((const)); +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4d_t qmuld (vec4d_t a, vec4d_t b) { @@ -89,14 +176,11 @@ qmuld (vec4d_t a, vec4d_t b) return c - d; } -/** Optimized quaterion-vector multiplication for vector rotation. - * - * If the vector's w component is not zero, then the result's w component - * is the cosine of the full rotation angle scaled by the vector's w component. - * The quaternion is assumed to be unit. If the quaternion is not unit, the - * vector will be scaled by the square of the quaternion's magnitude. - */ -vec4d_t qvmuld (vec4d_t q, vec4d_t v) __attribute__((const)); +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4d_t qvmuld (vec4d_t q, vec4d_t v) { @@ -112,19 +196,16 @@ qvmuld (vec4d_t q, vec4d_t v) return (s * s - qq) * v + 2 * (qv * q + s * c); } -/** Create the quaternion representing the shortest rotation from a to b. - * - * Both a and b are assumed to be 3D vectors (w components 0), but a resonable - * (but incorrect) result will still be produced if either a or b is a 4D - * vector. The rotation axis will be the same as if both vectors were 3D, but - * the magnitude of the rotation will be different. - */ -vec4d_t qrotd (vec4d_t a, vec4d_t b) __attribute__((const)); +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4d_t qrotd (vec4d_t a, vec4d_t b) { - vec4d_t ma = _mm256_sqrt_pd (dotd (a, a)); - vec4d_t mb = _mm256_sqrt_pd (dotd (b, b)); + vec4d_t ma = vsqrtd (dotd (a, a)); + vec4d_t mb = vsqrtd (dotd (b, b)); vec4d_t den = 2 * ma * mb; vec4d_t t = mb * a + ma * b; vec4d_t mba_mab = _mm256_sqrt_pd (dotd (t, t)); @@ -133,7 +214,11 @@ qrotd (vec4d_t a, vec4d_t b) return q; } -vec4d_t qconjd (vec4d_t q) __attribute__((const)); +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4d_t qconjd (vec4d_t q) { @@ -141,7 +226,11 @@ qconjd (vec4d_t q) return _mm256_xor_pd (q, (__m256d) neg); } -vec4d_t loadvec3d (const double v3[]) __attribute__((pure, access(read_only, 1))); +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4d_t loadvec3d (const double v3[]) { @@ -153,30 +242,17 @@ loadvec3d (const double v3[]) return v4; } -void storevec3d (double v3[3], vec4d_t v4) __attribute__((access (write_only, 1))); -void storevec3d (double v3[3], vec4d_t v4) +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +storevec3d (double v3[3], vec4d_t v4) { v3[0] = v4[0]; v3[1] = v4[1]; v3[2] = v4[2]; } -vec4d_t vceild (vec4d_t v) __attribute__((const)); -vec4d_t vceild (vec4d_t v) -{ - return _mm256_ceil_pd (v); -} - -vec4d_t vfloord (vec4d_t v) __attribute__((const)); -vec4d_t vfloord (vec4d_t v) -{ - return _mm256_floor_pd (v); -} - -vec4d_t vtruncd (vec4d_t v) __attribute__((const)); -vec4d_t vtruncd (vec4d_t v) -{ - return _mm256_round_pd (v, _MM_FROUND_TRUNC); -} - #endif//__QF_simd_vec4d_h diff --git a/include/QF/simd/vec4f.h b/include/QF/simd/vec4f.h index 997127a94..5c0b4cc3d 100644 --- a/include/QF/simd/vec4f.h +++ b/include/QF/simd/vec4f.h @@ -32,21 +32,17 @@ #include "QF/simd/types.h" +GNU89INLINE inline vec4f_t vsqrtf (vec4f_t v) __attribute__((const)); +GNU89INLINE inline vec4f_t vceilf (vec4f_t v) __attribute__((const)); +GNU89INLINE inline vec4f_t vfloorf (vec4f_t v) __attribute__((const)); +GNU89INLINE inline vec4f_t vtruncf (vec4f_t v) __attribute__((const)); /** 3D vector cross product. * * The w (4th) component can be any value on input, and is guaranteed to be 0 * in the result. The result is not affected in any way by either vector's w * componemnt */ -vec4f_t crossf (vec4f_t a, vec4f_t b) __attribute__((const)); -vec4f_t -crossf (vec4f_t a, vec4f_t b) -{ - static const vec4i_t A = {1, 2, 0, 3}; - vec4f_t c = a * __builtin_shuffle (b, A) - __builtin_shuffle (a, A) * b; - return __builtin_shuffle(c, A); -} - +GNU89INLINE inline vec4f_t crossf (vec4f_t a, vec4f_t b) __attribute__((const)); /** 4D vector dot product. * * The w component *IS* significant, but if it is 0 in either vector, then @@ -56,7 +52,99 @@ crossf (vec4f_t a, vec4f_t b) * helps optimize vector math as the scalar is already pre-spread. If just the * scalar is required, use result[0]. */ -vec4f_t dotf (vec4f_t a, vec4f_t b) __attribute__((const)); +GNU89INLINE inline vec4f_t dotf (vec4f_t a, vec4f_t b) __attribute__((const)); +/** Quaternion product. + * + * The vector is interpreted as a quaternion instead of a regular 4D vector. + * The quaternion may be of any magnitude, so this is more generally useful. + * than if the quaternion was required to be unit length. + */ +GNU89INLINE inline vec4f_t qmulf (vec4f_t a, vec4f_t b) __attribute__((const)); +/** Optimized quaterion-vector multiplication for vector rotation. + * + * If the vector's w component is not zero, then the result's w component + * is the cosine of the full rotation angle scaled by the vector's w component. + * The quaternion is assumed to be unit. + */ +GNU89INLINE inline vec4f_t qvmulf (vec4f_t q, vec4f_t v) __attribute__((const)); +/** Create the quaternion representing the shortest rotation from a to b. + * + * Both a and b are assumed to be 3D vectors (w components 0), but a resonable + * (but incorrect) result will still be produced if either a or b is a 4D + * vector. The rotation axis will be the same as if both vectors were 3D, but + * the magnitude of the rotation will be different. + */ +GNU89INLINE inline vec4f_t qrotf (vec4f_t a, vec4f_t b) __attribute__((const)); +/** Return the conjugate of the quaternion. + * + * That is, [-x, -y, -z, w]. + */ +GNU89INLINE inline vec4f_t qconjf (vec4f_t q) __attribute__((const)); +GNU89INLINE inline vec4f_t loadvec3f (const float v3[3]) __attribute__((pure, access(read_only, 1))); +GNU89INLINE inline void storevec3f (float v3[3], vec4f_t v4) __attribute__((access (write_only, 1))); + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +vsqrtf (vec4f_t v) +{ + return _mm_sqrt_ps (v); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +vceilf (vec4f_t v) +{ + return _mm_ceil_ps (v); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +vfloorf (vec4f_t v) +{ + return _mm_floor_ps (v); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +vtruncf (vec4f_t v) +{ + return _mm_round_ps (v, _MM_FROUND_TRUNC); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +crossf (vec4f_t a, vec4f_t b) +{ + static const vec4i_t A = {1, 2, 0, 3}; + vec4f_t c = a * __builtin_shuffle (b, A) - __builtin_shuffle (a, A) * b; + return __builtin_shuffle(c, A); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4f_t dotf (vec4f_t a, vec4f_t b) { @@ -66,13 +154,11 @@ dotf (vec4f_t a, vec4f_t b) return c; } -/** Quaternion product. - * - * The vector is interpreted as a quaternion instead of a regular 4D vector. - * The quaternion may be of any magnitude, so this is more generally useful. - * than if the quaternion was required to be unit length. - */ -vec4f_t qmulf (vec4f_t a, vec4f_t b) __attribute__((const)); +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4f_t qmulf (vec4f_t a, vec4f_t b) { @@ -85,13 +171,11 @@ qmulf (vec4f_t a, vec4f_t b) return c - d; } -/** Optimized quaterion-vector multiplication for vector rotation. - * - * If the vector's w component is not zero, then the result's w component - * is the cosine of the full rotation angle scaled by the vector's w component. - * The quaternion is assumed to be unit. - */ -vec4f_t qvmulf (vec4f_t q, vec4f_t v) __attribute__((const)); +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4f_t qvmulf (vec4f_t q, vec4f_t v) { @@ -106,19 +190,16 @@ qvmulf (vec4f_t q, vec4f_t v) return (s * s - qq) * v + 2 * (qv * q + s * c); } -/** Create the quaternion representing the shortest rotation from a to b. - * - * Both a and b are assumed to be 3D vectors (w components 0), but a resonable - * (but incorrect) result will still be produced if either a or b is a 4D - * vector. The rotation axis will be the same as if both vectors were 3D, but - * the magnitude of the rotation will be different. - */ -vec4f_t qrotf (vec4f_t a, vec4f_t b) __attribute__((const)); +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4f_t qrotf (vec4f_t a, vec4f_t b) { - vec4f_t ma = _mm_sqrt_ps (dotf (a, a)); - vec4f_t mb = _mm_sqrt_ps (dotf (b, b)); + vec4f_t ma = vsqrtf (dotf (a, a)); + vec4f_t mb = vsqrtf (dotf (b, b)); vec4f_t den = 2 * ma * mb; vec4f_t t = mb * a + ma * b; vec4f_t mba_mab = _mm_sqrt_ps (dotf (t, t)); @@ -127,11 +208,11 @@ qrotf (vec4f_t a, vec4f_t b) return q; } -/** Return the conjugate of the quaternion. - * - * That is, [-x, -y, -z, w]. - */ -vec4f_t qconjf (vec4f_t q) __attribute__((const)); +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4f_t qconjf (vec4f_t q) { @@ -139,7 +220,11 @@ qconjf (vec4f_t q) return _mm_xor_ps (q, (__m128) neg); } -vec4f_t loadvec3f (const float v3[3]) __attribute__((pure, access(read_only, 1))); +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif vec4f_t loadvec3f (const float v3[3]) { @@ -160,30 +245,17 @@ loadvec3f (const float v3[3]) return v4; } -void storevec3f (float v3[3], vec4f_t v4) __attribute__((access (write_only, 1))); -void storevec3f (float v3[3], vec4f_t v4) +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +storevec3f (float v3[3], vec4f_t v4) { v3[0] = v4[0]; v3[1] = v4[1]; v3[2] = v4[2]; } -vec4f_t vceilf (vec4f_t v) __attribute__((const)); -vec4f_t vceilf (vec4f_t v) -{ - return _mm_ceil_ps (v); -} - -vec4f_t vfloorf (vec4f_t v) __attribute__((const)); -vec4f_t vfloorf (vec4f_t v) -{ - return _mm_floor_ps (v); -} - -vec4f_t vtruncf (vec4f_t v) __attribute__((const)); -vec4f_t vtruncf (vec4f_t v) -{ - return _mm_round_ps (v, _MM_FROUND_TRUNC); -} - #endif//__QF_simd_vec4f_h diff --git a/libs/util/Makemodule.am b/libs/util/Makemodule.am index f554289be..d2ad47b0c 100644 --- a/libs/util/Makemodule.am +++ b/libs/util/Makemodule.am @@ -74,6 +74,7 @@ libs_util_libQFutil_la_SOURCES= \ libs/util/script.c \ libs/util/segtext.c \ libs/util/set.c \ + libs/util/simd.c \ libs/util/sizebuf.c \ libs/util/string.c \ libs/util/sys.c \ diff --git a/libs/util/simd.c b/libs/util/simd.c new file mode 100644 index 000000000..f5a0fcd35 --- /dev/null +++ b/libs/util/simd.c @@ -0,0 +1,37 @@ +/* + simd.c + + SIMD math support + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#define IMPLEMENT_VEC4F_Funcs +#define IMPLEMENT_VEC4D_Funcs + +#include "QF/simd/vec4d.h" +#include "QF/simd/vec4f.h" diff --git a/libs/util/test/test-simd.c b/libs/util/test/test-simd.c index 8fcc6935c..006e57526 100644 --- a/libs/util/test/test-simd.c +++ b/libs/util/test/test-simd.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include #include From 015cee7b6f37c95451b0ad3b26405c6bad14d9b7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 2 Jan 2021 10:44:45 +0900 Subject: [PATCH 166/435] [util] Add vector-quaternion shortcut functions Care needs to be taken to ensure the right function is used with the right arguments, but with these, the need to use qconj(d|f) for a one-off inverse rotation is removed. --- include/QF/simd/vec4d.h | 36 ++++++++++++++++++++++++++++++++++++ include/QF/simd/vec4f.h | 30 ++++++++++++++++++++++++++++++ libs/util/test/test-simd.c | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/include/QF/simd/vec4d.h b/include/QF/simd/vec4d.h index 6bd984357..1b8adbdfc 100644 --- a/include/QF/simd/vec4d.h +++ b/include/QF/simd/vec4d.h @@ -61,6 +61,8 @@ GNU89INLINE inline vec4d_t dotd (vec4d_t a, vec4d_t b) __attribute__((const)); */ GNU89INLINE inline vec4d_t qmuld (vec4d_t a, vec4d_t b) __attribute__((const)); /** Optimized quaterion-vector multiplication for vector rotation. + * + * \note This is the inverse of vqmulf * * If the vector's w component is not zero, then the result's w component * is the cosine of the full rotation angle scaled by the vector's w component. @@ -68,6 +70,16 @@ GNU89INLINE inline vec4d_t qmuld (vec4d_t a, vec4d_t b) __attribute__((const)); * vector will be scaled by the square of the quaternion's magnitude. */ GNU89INLINE inline vec4d_t qvmuld (vec4d_t q, vec4d_t v) __attribute__((const)); +/** Optimized vector-quaterion multiplication for vector rotation. + * + * \note This is the inverse of qvmulf + * + * If the vector's w component is not zero, then the result's w component + * is the cosine of the full rotation angle scaled by the vector's w component. + * The quaternion is assumed to be unit. If the quaternion is not unit, the + * vector will be scaled by the square of the quaternion's magnitude. + */ +GNU89INLINE inline vec4d_t vqmuld (vec4d_t v, vec4d_t q) __attribute__((const)); /** Create the quaternion representing the shortest rotation from a to b. * * Both a and b are assumed to be 3D vectors (w components 0), but a resonable @@ -183,6 +195,7 @@ VISIBLE #endif vec4d_t qvmuld (vec4d_t q, vec4d_t v) +// ^^^ ^^^ { double s = q[3]; // zero the scalar of the quaternion. Results in an extra operation, but @@ -193,9 +206,32 @@ qvmuld (vec4d_t q, vec4d_t v) vec4d_t qv = dotd (q, v); // q.w is 0 so v.w is irrelevant vec4d_t qq = dotd (q, q); + // vvv return (s * s - qq) * v + 2 * (qv * q + s * c); } +#ifndef IMPLEMENT_VEC4D_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4d_t +vqmuld (vec4d_t v, vec4d_t q) +// ^^^ ^^^ +{ + double s = q[3]; + // zero the scalar of the quaternion. Results in an extra operation, but + // avoids adding precision issues. + vec4d_t z = {}; + q = _mm256_blend_pd (q, z, 0x08); + vec4d_t c = crossd (q, v); + vec4d_t qv = dotd (q, v); // q.w is 0 so v.w is irrelevant + vec4d_t qq = dotd (q, q); + + // vvv + return (s * s - qq) * v + 2 * (qv * q - s * c); +} + #ifndef IMPLEMENT_VEC4D_Funcs GNU89INLINE inline #else diff --git a/include/QF/simd/vec4f.h b/include/QF/simd/vec4f.h index 5c0b4cc3d..f3ea3b22f 100644 --- a/include/QF/simd/vec4f.h +++ b/include/QF/simd/vec4f.h @@ -61,12 +61,23 @@ GNU89INLINE inline vec4f_t dotf (vec4f_t a, vec4f_t b) __attribute__((const)); */ GNU89INLINE inline vec4f_t qmulf (vec4f_t a, vec4f_t b) __attribute__((const)); /** Optimized quaterion-vector multiplication for vector rotation. + * + * \note This is the inverse of vqmulf * * If the vector's w component is not zero, then the result's w component * is the cosine of the full rotation angle scaled by the vector's w component. * The quaternion is assumed to be unit. */ GNU89INLINE inline vec4f_t qvmulf (vec4f_t q, vec4f_t v) __attribute__((const)); +/** Optimized vector-quaterion multiplication for vector rotation. + * + * \note This is the inverse of qvmulf + * + * If the vector's w component is not zero, then the result's w component + * is the cosine of the full rotation angle scaled by the vector's w component. + * The quaternion is assumed to be unit. + */ +GNU89INLINE inline vec4f_t vqmulf (vec4f_t v, vec4f_t q) __attribute__((const)); /** Create the quaternion representing the shortest rotation from a to b. * * Both a and b are assumed to be 3D vectors (w components 0), but a resonable @@ -190,6 +201,25 @@ qvmulf (vec4f_t q, vec4f_t v) return (s * s - qq) * v + 2 * (qv * q + s * c); } +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +vqmulf (vec4f_t v, vec4f_t q) +{ + float s = q[3]; + // zero the scalar of the quaternion. Results in an extra operation, but + // avoids adding precision issues. + q = _mm_insert_ps (q, q, 0xf8); + vec4f_t c = crossf (q, v); + vec4f_t qv = dotf (q, v); // q.w is 0 so v.w is irrelevant + vec4f_t qq = dotf (q, q); + + return (s * s - qq) * v + 2 * (qv * q - s * c); +} + #ifndef IMPLEMENT_VEC4F_Funcs GNU89INLINE inline #else diff --git a/libs/util/test/test-simd.c b/libs/util/test/test-simd.c index 006e57526..40a7276de 100644 --- a/libs/util/test/test-simd.c +++ b/libs/util/test/test-simd.c @@ -153,11 +153,22 @@ static vec4d_test_t vec4d_tests[] = { { qvmuld, one, up, { 4, 0, 0, 0 } }, { qvmuld, one, {1,1,1,0}, { 4, 4, 4, 0 } }, { qvmuld, one, one, { 4, 4, 4, -2 } }, + // inverse rotation, so x->z->y->x + { vqmuld, right, one, { 0, 0, 4, 0 } }, + { vqmuld, forward, one, { 4, 0, 0, 0 } }, + { vqmuld, up, one, { 0, 4, 0, 0 } }, + { vqmuld, {1,1,1,0}, one, { 4, 4, 4, 0 } }, + { vqmuld, one, one, { 4, 4, 4, -2 } }, // The half vector is unit. { qvmuld, half, right, forward }, { qvmuld, half, forward, up }, { qvmuld, half, up, right }, { qvmuld, half, {1,1,1,0}, { 1, 1, 1, 0 } }, + // inverse + { vqmuld, right, half, up }, + { vqmuld, forward, half, right }, + { vqmuld, up, half, forward }, + { vqmuld, {1,1,1,0}, half, { 1, 1, 1, 0 } }, // one is a 4D vector and qvmuld is meant for 3D vectors. However, it // seems that the vector's w has no effect on the 3d portion of the // result, but the result's w is cosine of the full rotation angle @@ -168,6 +179,13 @@ static vec4d_test_t vec4d_tests[] = { { qvmuld, qtest, forward, {0.6144, 0.1808, 0.768, 0}, {0, -2.7e-17, 0, 0} }, { qvmuld, qtest, up, {0.576, -0.768, -0.28, 0} }, + // inverse + { vqmuld, one, half, { 1, 1, 1, -0.5 } }, + { vqmuld, {2,2,2,2}, half, { 2, 2, 2, -1 } }, + { vqmuld, right, qtest, {0.5392, 0.6144, 0.576, 0} }, + { vqmuld, forward, qtest, {0.6144, 0.1808, -0.768, 0}, + {0, -2.7e-17, 0, 0} }, + { vqmuld, up, qtest, {-0.576, 0.768, -0.28, 0} }, { qrotd, right, right, qident }, { qrotd, right, forward, { 0, 0, s05, s05 }, @@ -259,12 +277,25 @@ static vec4f_test_t vec4f_tests[] = { { qvmulf, one, up, { 4, 0, 0, 0 } }, { qvmulf, one, {1,1,1,0}, { 4, 4, 4, 0 } }, { qvmulf, one, one, { 4, 4, 4, -2 } }, + // inverse rotation, so x->z->y->x + { vqmulf, right, one, { 0, 0, 4, 0 } }, + { vqmulf, forward, one, { 4, 0, 0, 0 } }, + { vqmulf, up, one, { 0, 4, 0, 0 } }, + { vqmulf, {1,1,1,0}, one, { 4, 4, 4, 0 } }, + { vqmulf, one, one, { 4, 4, 4, -2 } }, + // { qvmulf, qtest, right, {0.5392, 0.6144, -0.576, 0}, - {0, -5.9e-08, -6e-8, 0} }, + {0, -5.9e-8, -6e-8, 0} }, { qvmulf, qtest, forward, {0.6144, 0.1808, 0.768, 0}, - {-5.9e-08, 1.5e-08, 0, 0} }, + {-5.9e-8, 1.5e-8, 0, 0} }, { qvmulf, qtest, up, {0.576, -0.768, -0.28, 0}, {6e-8, 0, 3e-8, 0} }, + { vqmulf, right, qtest, {0.5392, 0.6144, 0.576, 0}, + {0, -5.9e-8, 5.9e-8, 0} }, + { vqmulf, forward, qtest, {0.6144, 0.1808, -0.768, 0}, + {-5.9e-8, 1.5e-8, 0, 0} }, + { vqmulf, up, qtest, {-0.576, 0.768, -0.28, 0}, + {-5.9e-8, 0, 3e-8, 0} }, { qrotf, right, right, qident }, { qrotf, right, forward, { 0, 0, s05, s05 } }, From eb52d366c8f12d8b07a16834c9c96c995a4259a5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 2 Jan 2021 12:10:58 +0900 Subject: [PATCH 167/435] [util] Add q-v and v-q multiplication to cexpr --- libs/util/cexpr-type.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index 81fc212cd..04eef6d70 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -356,6 +356,16 @@ BINOP(vector, sub, vec4f_t, -) BINOP(vector, mul, vec4f_t, *) BINOP(vector, div, vec4f_t, /) +static void +vector_quaternion_mul (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + vec4f_t a = *(vec4f_t *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = vqmulf (a, b); +} + static void vector_rem (const exprval_t *val1, const exprval_t *val2, exprval_t *result, exprctx_t *ctx) @@ -396,6 +406,7 @@ binop_t vector_binops[] = { { '+', &cexpr_vector, &cexpr_vector, vector_add }, { '-', &cexpr_vector, &cexpr_vector, vector_sub }, { '*', &cexpr_vector, &cexpr_vector, vector_mul }, + { '*', &cexpr_quaternion, &cexpr_vector, vector_quaternion_mul }, { '/', &cexpr_vector, &cexpr_vector, vector_div }, { '%', &cexpr_vector, &cexpr_vector, vector_rem }, { MOD, &cexpr_vector, &cexpr_vector, vector_mod }, @@ -426,10 +437,21 @@ quaternion_mul (const exprval_t *val1, const exprval_t *val2, *c = qmulf (a, b); } +static void +quaternion_vector_mul (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ + vec4f_t a = *(vec4f_t *) val1->value; + vec4f_t b = *(vec4f_t *) val2->value; + __auto_type c = (vec4f_t *) result->value; + *c = qvmulf (a, b); +} + binop_t quaternion_binops[] = { { '+', &cexpr_quaternion, &cexpr_quaternion, vector_add }, { '-', &cexpr_quaternion, &cexpr_quaternion, vector_sub }, { '*', &cexpr_quaternion, &cexpr_quaternion, quaternion_mul }, + { '*', &cexpr_vector, &cexpr_vector, quaternion_vector_mul }, {} }; From 81300f89f8ca473a90840a0dfce5998fe037852d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 2 Jan 2021 14:02:33 +0900 Subject: [PATCH 168/435] [util] Allow multiple types for pl fields I want to be able to use name references, but that requires string items, so anything that would normally be dictionary or array (or binary, even) would also need to accept string. This seemed to be the cleanest solution. Any custom parser would then need to check the type and act appropriately, but any inappropriate types have already been pre-filtered by the standard parsers. --- include/QF/qfplist.h | 5 +++- libs/util/qfplist.c | 66 ++++++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 972f69dc3..20c7671bb 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -44,7 +44,10 @@ typedef enum { QFArray, ///< The property list item represents an array. QFBinary, ///< The property list item represents arbitrary binary ///< data. - QFString ///< The property list item represents a C string. + QFString, ///< The property list item represents a C string. + + QFMultiType = (1 << 31) ///< if bit 31 is set, the type indicates a mask + ///< of allowed types for plfield_t } pltype_t; /** Generic property list item. diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 3e64e3c3e..c3fc5a756 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -227,6 +227,8 @@ PL_Free (plitem_t *item) case QFString: free (item->data); break; + case QFMultiType: + break; } free (item); } @@ -1138,11 +1140,48 @@ pl_default_parser (const plfield_t *field, const plitem_t *item, void *data, case QFString: *(char **)data = (char *)item->data; return 1; + case QFMultiType: + break; } PL_Message (messages, 0, "invalid item type: %d", field->type); return 0; } +static int +types_match (pltype_t field_type, pltype_t item_type) +{ + if (field_type & QFMultiType) { + // field_type is a mask of allowed types + return field_type & (1 << item_type); + } else { + // exact match + return field_type == item_type; + } +} + +static void +type_mismatch (plitem_t *messages, const plitem_t *item, const char *name, + pltype_t field_type, pltype_t item_type) +{ + const int num_types = sizeof (pl_types) / sizeof (pl_types[0]); + if (field_type & QFMultiType) { + PL_Message (messages, item, + "error: %s is the wrong type. Got %s, expected on of:", + name, pl_types[item_type]); + field_type &= ~QFMultiType; + for (int type = 0; field_type && type < num_types; + type++, field_type >>= 1) { + if (field_type & 1) { + PL_Message (messages, item, " %s", pl_types[type]); + } + } + } else { + PL_Message (messages, item, + "error: %s is the wrong type. Got %s, expected %s", name, + pl_types[item_type], pl_types[field_type]); + } +} + VISIBLE int PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data, plitem_t *messages, void *context) @@ -1174,11 +1213,9 @@ PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data, } else { parser = pl_default_parser; } - if (item->type != f->type) { - PL_Message (messages, item, "error: %s is the wrong type" - " Got %s, expected %s",current->key, - pl_types[f->type], - pl_types[item->type]); + if (!types_match (f->type, item->type)) { + type_mismatch (messages, item, current->key, + f->type, item->type); result = 0; } else { if (!parser (f, item, flddata, messages, context)) { @@ -1231,12 +1268,11 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, plitem_t *item = plarray->values[i]; void *eledata = &arr->a[i * element->stride]; - if (item->type != element->type) { - PL_Message (messages, item, - "error: element %d is the wrong type" - " Got %s, expected %s", i, - pl_types[element->type], - pl_types[item->type]); + if (!types_match (element->type, item->type)) { + char index[16]; + snprintf (index, sizeof(index) - 1, "%d", i); + index[15] = 0; + type_mismatch (messages, item, index, element->type, item->type); result = 0; } else { if (!parser (&f, item, eledata, messages, context)) { @@ -1284,12 +1320,8 @@ PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, const char *key = current->key; plitem_t *item = current->value; - if (item->type != element->type) { - PL_Message (messages, item, - "error: element %s is the wrong type" - " Got %s, expected %s", key, - pl_types[element->type], - pl_types[item->type]); + if (!types_match (element->type, item->type)) { + type_mismatch (messages, item, key, element->type, item->type); result = 0; continue; } From 4562e0b8760447438b543d2a098838a74d81b3c9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 00:11:52 +0900 Subject: [PATCH 169/435] [util] Implement more of cexpr This adds unary, vector and function expressions. --- include/QF/cexpr.h | 14 +++ libs/util/cexpr-parse.y | 193 +++++++++++++++++++++++++++++++++++----- libs/util/cexpr-type.c | 7 ++ 3 files changed, 194 insertions(+), 20 deletions(-) diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index e257412d6..77e5b0463 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -62,6 +62,11 @@ typedef struct exprval_s { void *value; } exprval_t; +typedef struct exprlist_s { + struct exprlist_s *next; + exprval_t *value; +} exprlist_t; + typedef struct exprsym_s { const char *name; exprtype_t *type; @@ -69,6 +74,14 @@ typedef struct exprsym_s { struct exprsym_s *next; } exprsym_t; +typedef struct exprfunc_s { + exprtype_t *result; + int num_params; + exprtype_t **param_types; + void (*func) (const exprval_t **params, exprval_t *result, + struct exprctx_s *context); +} exprfunc_t; + typedef struct exprtab_s { exprsym_t *symbols; struct hashtab_s *tab; @@ -116,6 +129,7 @@ extern exprtype_t cexpr_vector; extern exprtype_t cexpr_quaternion; extern exprtype_t cexpr_exprval; extern exprtype_t cexpr_field; +extern exprtype_t cexpr_function; extern binop_t cexpr_struct_binops[]; diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y index eb56ed588..f208f4680 100644 --- a/libs/util/cexpr-parse.y +++ b/libs/util/cexpr-parse.y @@ -43,6 +43,7 @@ #include #include "QF/cmem.h" +#include "QF/dstring.h" #include "QF/hash.h" #include "QF/qfplist.h" #include "QF/sys.h" @@ -55,11 +56,17 @@ static exprval_t *binary_expr (int op, const exprval_t *a, const exprval_t *b, exprctx_t *context); static exprval_t *field_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context); +static exprval_t *unary_expr (int op, const exprval_t *val, + exprctx_t *context); +static exprval_t *vector_expr (exprlist_t *list, exprctx_t *context); +static exprval_t *function_expr (exprsym_t *fsym, exprlist_t *list, + exprctx_t *context); +static exprlist_t *expr_item (exprval_t *val, exprctx_t *context); static void yyerror (void *scanner, exprctx_t *context, const char *s) { - cexpr_error (context, "%s before %s\n", s, cexpr_yyget_text (scanner)); + cexpr_error (context, "%s before %s", s, cexpr_yyget_text (scanner)); } %} @@ -78,19 +85,21 @@ yyerror (void *scanner, exprctx_t *context, const char *s) %left SHL SHR %left '+' '-' %left '*' '/' '%' MOD -%right SIZEOF UNARY INCOP +%right SIZEOF UNARY INCOP %left HYPERUNARY %left '.' '(' '[' %token NAME %token VALUE -%type expr field +%type expr field uexpr +%type opt_arg_list arg_list arg_expr %union { int op; exprsym_t *symbol; exprval_t *value; + exprlist_t *list; const char *string; } @@ -100,20 +109,8 @@ start : expr { assign_expr (context->result, $1, context); } ; -expr - : expr SHL expr { $$ = binary_expr (SHL, $1, $3, context); } - | expr SHR expr { $$ = binary_expr (SHR, $1, $3, context); } - | expr '+' expr { $$ = binary_expr ('+', $1, $3, context); } - | expr '-' expr { $$ = binary_expr ('-', $1, $3, context); } - | expr '*' expr { $$ = binary_expr ('*', $1, $3, context); } - | expr '/' expr { $$ = binary_expr ('/', $1, $3, context); } - | expr '&' expr { $$ = binary_expr ('&', $1, $3, context); } - | expr '|' expr { $$ = binary_expr ('|', $1, $3, context); } - | expr '^' expr { $$ = binary_expr ('^', $1, $3, context); } - | expr '%' expr { $$ = binary_expr ('%', $1, $3, context); } - | expr '.' field { $$ = field_expr ($1, $3, context); } - | expr MOD expr { $$ = binary_expr (MOD, $1, $3, context); } - | NAME +uexpr + : NAME { if ($1) { $$ = (exprval_t *) cmemalloc (context->memsuper, sizeof (*$$)); @@ -125,6 +122,29 @@ expr } } | VALUE + | '[' arg_list ']' { $$ = vector_expr ($2, context); } + | '(' expr ')' { $$ = $2; } + | NAME '(' opt_arg_list ')' { $$ = function_expr ($1, $3, context); } + | uexpr '.' field { $$ = field_expr ($1, $3, context); } + | '+' uexpr %prec UNARY { $$ = $2; } + | '-' uexpr %prec UNARY { $$ = unary_expr ('-', $2, context); } + | '!' uexpr %prec UNARY { $$ = unary_expr ('!', $2, context); } + | '~' uexpr %prec UNARY { $$ = unary_expr ('~', $2, context); } + ; + +expr + : uexpr + | expr SHL expr { $$ = binary_expr (SHL, $1, $3, context); } + | expr SHR expr { $$ = binary_expr (SHR, $1, $3, context); } + | expr '+' expr { $$ = binary_expr ('+', $1, $3, context); } + | expr '-' expr { $$ = binary_expr ('-', $1, $3, context); } + | expr '*' expr { $$ = binary_expr ('*', $1, $3, context); } + | expr '/' expr { $$ = binary_expr ('/', $1, $3, context); } + | expr '&' expr { $$ = binary_expr ('&', $1, $3, context); } + | expr '|' expr { $$ = binary_expr ('|', $1, $3, context); } + | expr '^' expr { $$ = binary_expr ('^', $1, $3, context); } + | expr '%' expr { $$ = binary_expr ('%', $1, $3, context); } + | expr MOD expr { $$ = binary_expr (MOD, $1, $3, context); } ; field @@ -141,6 +161,23 @@ field } ; +opt_arg_list + : { $$ = 0; } + | arg_list { $$ = $1; } + ; + +arg_list + : arg_expr + | arg_list ',' arg_expr + { + $3-> next = $1; + $$ = $3; + } + +arg_expr + : expr { $$ = expr_item ($1, context); } + ; + %% static void @@ -156,7 +193,7 @@ assign_expr (exprval_t *dst, const exprval_t *src, exprctx_t *context) } else { if (dst->type != src->type) { cexpr_error (context, - "type mismatch in expression result: %s = %s\n", + "type mismatch in expression result: %s = %s", dst->type->name, src->type->name); return; } @@ -185,8 +222,9 @@ binary_expr (int op, const exprval_t *a, const exprval_t *b, } exprval_t *result = cexpr_value (rtype, context); if (!binop->op) { - cexpr_error (context, "invalid binary expression: %s %c %s\n", + cexpr_error (context, "invalid binary expression: %s %c %s", a->type->name, op, b->type->name); + memset (result->value, 0, rtype->size); } else { binop->func (a, b, result, context); } @@ -205,11 +243,126 @@ field_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context) } } if (!binop->op) { - cexpr_error (context, "invalid binary expression: %s.%s\n", + cexpr_error (context, "invalid binary expression: %s.%s", a->type->name, b->type->name); + result = cexpr_value (&cexpr_int, context); + *(int *) result->value = 0; } else { exprval_t c = { 0, &result }; binop->func (a, b, &c, context); } return result; } + +static exprval_t * +unary_expr (int op, const exprval_t *val, exprctx_t *context) +{ + unop_t *unop; + + for (unop = val->type->unops; unop->op; unop++) { + if (unop->op == op) { + break; + } + } + exprtype_t *rtype = unop->result; + if (!rtype) { + rtype = val->type; + } + exprval_t *result = cexpr_value (rtype, context); + if (!unop->op) { + cexpr_error (context, "invalid unary expression: %c %s", + op, val->type->name); + } else { + unop->func (val, result, context); + } + return result; +} + +exprval_t * +vector_expr (exprlist_t *list, exprctx_t *context) +{ + exprlist_t *l; + exprval_t *val = cexpr_value (&cexpr_vector, context); + int i; + for (i = 0; i < 4 && list; i++, list = l) { + exprval_t dst = { &cexpr_float, ((float *) val->value) + i }; + exprval_t *src = list->value; + binop_t *cast = cexpr_find_cast (&cexpr_float, src->type); + if (cast) { + cast->func (&dst, src, &dst, context); + } else { + cexpr_error (context, "invalid vector expression type: [%d] %s", + i, val->type->name); + } + l = list->next; + cmemfree (context->memsuper, list); + } + for ( ; i < 4; i++) { + ((float *) val->value)[i] = 0; + } + if (i == 4 && list) { + cexpr_error (context, "excess elements in vector expression"); + } + return val; +} + +static exprval_t *function_expr (exprsym_t *fsym, exprlist_t *list, + exprctx_t *context) +{ + exprlist_t *l; + int num_args = 0; + exprfunc_t *func = 0; + exprval_t *result; + + for (l = list; l; l = l->next) { + num_args++; + } + __auto_type args = (const exprval_t **) alloca (num_args * sizeof (exprval_t *)); + __auto_type types = (exprtype_t **) alloca (num_args * sizeof (exprtype_t *)); + for (num_args = 0; list; list = l, num_args++) { + args[num_args] = list->value; + types[num_args] = list->value->type; + l = list->next; + cmemfree (context->memsuper, list); + } + if (fsym->type != &cexpr_function) { + cexpr_error (context, "invalid function %s", fsym->name); + result = cexpr_value (&cexpr_int, context); + *(int *) result->value = 0; + return result; + } + for (exprfunc_t *f = fsym->value; f->result; f++) { + if (f->num_params == num_args + && memcmp (f->param_types, types, + num_args * sizeof (exprtype_t *)) == 0) { + func = f; + break; + } + } + if (!func) { + dstring_t *argstr = dstring_newstr(); + for (int i = 0; i < num_args; i++) { + dasprintf (argstr, "%s%s", types[i]->name, + i + 1 < num_args ? ", ": ""); + } + cexpr_error (context, "no overload for %s(%s)", fsym->name, + argstr->str); + dstring_delete (argstr); + result = cexpr_value (&cexpr_int, context); + *(int *) result->value = 0; + return result; + } + result = cexpr_value (func->result, context); + func->func (args, result, context); + return result; +} + +static exprlist_t * +expr_item (exprval_t *val, exprctx_t *context) +{ + __auto_type item = (exprlist_t *) cmemalloc (context->memsuper, + sizeof (exprlist_t)); + item->next = 0; + item->value = val; + return item; +} diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index 04eef6d70..1a68728de 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -483,6 +483,13 @@ exprtype_t cexpr_field = { 0, }; +exprtype_t cexpr_function = { + "function", + 0, // has no size of its own + 0, // can't actually do anything with a function other than call + 0, +}; + VISIBLE binop_t * cexpr_find_cast (exprtype_t *dst_type, exprtype_t *src_type) { From 619fe1536784727fc99ff8bb58824e08f73f4093 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 00:15:22 +0900 Subject: [PATCH 170/435] [util] Add vector swizzles to cexpr That turned out to be a lot easier than expected: needed only 4 ifs per vector "type" (xyzw vs rgba) instead of 340. --- libs/util/cexpr-type.c | 73 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index 1a68728de..6b02be01d 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -391,6 +391,78 @@ vector_mod (const exprval_t *val1, const exprval_t *val2, exprval_t *result, *c = a - b * vfloorf (a / b); } +static void +vector_swizzle (const exprval_t *val1, const exprval_t *val2, + exprval_t *result, exprctx_t *ctx) +{ +#define m(x) (1 << ((x) - 'a')) +#define v(x, mask) (((x) & 0x60) == 0x60 && (m(x) & (mask))) +#define vind(x) ((x) & 3) +#define cind(x) (-(((x) >> 3) ^ (x)) & 3) + const int color = m('r') | m('g') | m('b') | m('a'); + const int vector = m('x') | m('y') | m('z') | m('w'); + float *vec = val1->value; + const char *name = val2->value; + exprval_t *val = 0; + + if (v (name[0], vector) && v (name[1], vector) + && v (name[2], vector) && v (name[3], vector) && !name[4]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[vind (name[0])]; + res[1] = vec[vind (name[1])]; + res[2] = vec[vind (name[2])]; + res[3] = vec[vind (name[3])]; + } else if (v (name[0], color) && v (name[1], color) + && v (name[2], color) && v (name[3], color) && !name[4]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[cind (name[0])]; + res[1] = vec[cind (name[1])]; + res[2] = vec[cind (name[2])]; + res[3] = vec[cind (name[3])]; + } else if (v (name[0], vector) && v (name[1], vector) + && v (name[2], vector) && !name[3]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[vind (name[0])]; + res[1] = vec[vind (name[1])]; + res[2] = vec[vind (name[2])]; + res[3] = 0; + } else if (v (name[0], color) && v (name[1], color) + && v (name[2], color) && !name[3]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[cind (name[0])]; + res[1] = vec[cind (name[1])]; + res[2] = vec[cind (name[2])]; + res[3] = 0; + } else if (v (name[0], vector) && v (name[1], vector) && !name[2]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[vind (name[0])]; + res[1] = vec[vind (name[1])]; + res[2] = 0; + res[3] = 0; + } else if (v (name[0], color) && v (name[1], color) && !name[2]) { + val = cexpr_value (&cexpr_vector, ctx); + float *res = val->value; + res[0] = vec[cind (name[0])]; + res[1] = vec[cind (name[1])]; + res[2] = 0; + res[3] = 0; + } else if (v (name[0], vector) && !name[1]) { + val = cexpr_value (&cexpr_float, ctx); + float *res = val->value; + res[0] = vec[vind (name[0])]; + } else if (v (name[0], color) && !name[1]) { + val = cexpr_value (&cexpr_float, ctx); + float *res = val->value; + res[0] = vec[cind (name[0])]; + } + *(exprval_t **) result->value = val; +} + UNOP(vector, pos, vec4f_t, +) UNOP(vector, neg, vec4f_t, -) @@ -410,6 +482,7 @@ binop_t vector_binops[] = { { '/', &cexpr_vector, &cexpr_vector, vector_div }, { '%', &cexpr_vector, &cexpr_vector, vector_rem }, { MOD, &cexpr_vector, &cexpr_vector, vector_mod }, + { '.', &cexpr_field, &cexpr_exprval, vector_swizzle }, {} }; From 55445a25f2438ddccf9aa4864086d3201b634e44 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 00:18:35 +0900 Subject: [PATCH 171/435] [util] Add some tests for the new cexpr work --- libs/util/test/test-cexpr.c | 141 +++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-) diff --git a/libs/util/test/test-cexpr.c b/libs/util/test/test-cexpr.c index 095316222..338e71bbc 100644 --- a/libs/util/test/test-cexpr.c +++ b/libs/util/test/test-cexpr.c @@ -24,27 +24,125 @@ Boston, MA 02111-1307, USA */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include "QF/cexpr.h" #include "QF/cmem.h" #include "QF/hash.h" +#include "QF/mathlib.h" +#include "QF/simd/vec4f.h" int a = 5; int b = 6; int c; +float point[4] = { 2, 3, 4, 1 }; // a point, so w = 1 +float normal[4] = { 1, 2, 3, 0 }; // a vector, so w = 0 +float direction[4] = { 4, 5, 6, 0 }; // a vector, so w = 0 +float plane[4]; +float intercept[4]; + +exprtype_t *vector_params[] = { + &cexpr_vector, + &cexpr_vector, +}; + +exprtype_t *int_params[] = { + &cexpr_int, + &cexpr_int, +}; + +exprtype_t *float_params[] = { + &cexpr_float, + &cexpr_float, +}; + +exprtype_t *double_params[] = { + &cexpr_double, + &cexpr_double, +}; + +static void +float_dot (const exprval_t **params, exprval_t *result, exprctx_t *context) +{ + // parameters are reversed! + vec4f_t *a = params[1]->value; + vec4f_t *b = params[0]->value; + vec4f_t *d = result->value; + *d = dotf (*a, *b); +} + +exprfunc_t dot_func[] = { + { &cexpr_vector, 2, vector_params, float_dot}, + {} +}; + +exprfunc_t sin_func[] = { + { &cexpr_float, 1, float_params }, + { &cexpr_double, 1, double_params }, + {} +}; + +exprfunc_t cos_func[] = { + { &cexpr_float, 1, float_params }, + { &cexpr_double, 1, double_params }, + {} +}; + +exprfunc_t atan2_func[] = { + { &cexpr_float, 2, float_params }, + { &cexpr_double, 2, double_params }, + {} +}; + +exprfunc_t int_func[] = { + { &cexpr_int, 1, float_params }, + { &cexpr_int, 1, double_params }, + {} +}; + +exprfunc_t float_func[] = { + { &cexpr_float, 1, int_params }, + { &cexpr_float, 1, double_params }, + {} +}; + +exprfunc_t double_func[] = { + { &cexpr_double, 1, float_params }, + { &cexpr_double, 1, double_params }, + {} +}; exprsym_t symbols[] = { { "a", &cexpr_int, &a }, { "b", &cexpr_int, &b }, + { "point", &cexpr_vector, &point }, + { "normal", &cexpr_vector, &normal }, + { "plane", &cexpr_vector, &plane }, + { "direction", &cexpr_vector, &direction }, + { "intercept", &cexpr_vector, &intercept }, + { "dot", &cexpr_function, dot_func }, + { "sin", &cexpr_function, sin_func }, + { "cos", &cexpr_function, cos_func }, + { "atan2", &cexpr_function, atan2_func }, + { "float", &cexpr_function, float_func }, + { "double", &cexpr_function, double_func }, + { "int", &cexpr_function, int_func }, {} }; -exprval_t result = { &cexpr_int, &c }; +exprval_t test_result = { &cexpr_int, &c }; +exprval_t plane_result = { &cexpr_vector, &plane }; +// a bit hacky, but no l-values +exprval_t dist_result = { &cexpr_float, &plane[3] }; +exprval_t intercept_result = { &cexpr_vector, &intercept }; exprtab_t symtab = { symbols, 0 }; -exprctx_t context = { &result, &symtab }; +exprctx_t context = { &test_result, &symtab }; #define TEST_BINOP(op) \ do { \ @@ -75,6 +173,45 @@ main(int argc, const char **argv) TEST_BINOP (^); TEST_BINOP (%); + context.result = &plane_result; + cexpr_eval_string ("point.wzyx", &context); + if (plane[0] != point[3] || plane[1] != point[2] + || plane[2] != point[1] || plane[3] != point[0]) { + printf ("point.wzyx [%.9g, %.9g, %.9g] %.9g\n", + VectorExpand (plane), plane[3]); + ret |= 1; + } + cexpr_eval_string ("point.zyx", &context); + if (plane[0] != point[2] || plane[1] != point[1] + || plane[2] != point[0] || plane[3] != 0) { + printf ("point.zyx [%.9g, %.9g, %.9g] %.9g\n", + VectorExpand (plane), plane[3]); + ret |= 1; + } + cexpr_eval_string ("point.yx", &context); + if (plane[0] != point[1] || plane[1] != point[0] + || plane[2] != 0 || plane[3] != 0) { + printf ("point.yx [%.9g, %.9g, %.9g] %.9g\n", + VectorExpand (plane), plane[3]); + ret |= 1; + } + cexpr_eval_string ("normal", &context); + context.result = &dist_result; + cexpr_eval_string ("-dot(point, normal).x / 2f", &context); + if (!VectorCompare (normal, plane) + || plane[3] != -DotProduct (normal, point) / 2) { + printf ("plane [%.9g, %.9g, %.9g] %.9g\n", + VectorExpand (plane), plane[3]); + ret |= 1; + } + context.result = &intercept_result; + cexpr_eval_string ("point - direction * dot(point, plane)/dot(direction,plane)", &context); + if (intercept[0] != 0.75 || intercept[1] != 1.4375 + || intercept[2] != 2.125 || intercept[3] != 1) { + printf ("[%.9g, %.9g, %.9g] %.9g\n", VectorExpand (intercept), intercept[3]); + ret |= 1; + } + Hash_DelTable (symtab.tab); delete_memsuper (context.memsuper); return ret; From 5b842da394beaca4e8f2b45261bc10e88454c322 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 00:21:48 +0900 Subject: [PATCH 172/435] [util] Fix types for double and float constants --- libs/util/cexpr-lex.l | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/util/cexpr-lex.l b/libs/util/cexpr-lex.l index cdae1ee04..2cbbdaa79 100644 --- a/libs/util/cexpr-lex.l +++ b/libs/util/cexpr-lex.l @@ -241,14 +241,14 @@ static exprval_t *parse_uint (const char *str, exprctx_t *context) static exprval_t *parse_float (const char *str, exprctx_t *context) { - exprval_t *val = cexpr_value (&cexpr_int, context); + exprval_t *val = cexpr_value (&cexpr_float, context); *(float *) val->value = strtof (str, 0); return val; } static exprval_t *parse_double (const char *str, exprctx_t *context) { - exprval_t *val = cexpr_value (&cexpr_int, context); + exprval_t *val = cexpr_value (&cexpr_double, context); *(double *) val->value = strtod (str, 0); return val; } From 0426879bf60119f3b7cc6dbe4ca701fc32268bcf Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 14:54:04 +0900 Subject: [PATCH 173/435] [qfcc] Check returned type instead of expr type Block expressions hide ex_error, but get_type() always returns null when it finds one (which it does by recursing into block expression), so just check the type itself. --- tools/qfcc/source/expr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 9ecf0ad15..a8684a83b 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2075,7 +2075,7 @@ return_expr (function_t *f, expr_t *e) t = get_type (e); - if (e->type == ex_error) { + if (!t) { return e; } if (is_void(ret_type)) { From a6a3d4c6b52ceb0cd735ed019f749497c9b3de86 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 15:30:27 +0900 Subject: [PATCH 174/435] [vulkan] Make array and single parsing smarter Array and single type overrides now allow the parsing of the items themselves to be customized. This makes it easy to handle arrays and pointers to single items while also using custom specifications, rather than relying entirely on the custom override. --- .../video/renderer/vulkan/vkgen/Makemodule.am | 1 + .../renderer/vulkan/vkgen/vkfieldarray.h | 4 +- .../renderer/vulkan/vkgen/vkfieldarray.r | 9 +-- .../renderer/vulkan/vkgen/vkfieldsingle.h | 4 +- .../renderer/vulkan/vkgen/vkfieldsingle.r | 11 ++- .../video/renderer/vulkan/vkgen/vkfieldtype.h | 20 ++++++ .../video/renderer/vulkan/vkgen/vkfieldtype.r | 69 +++++++++++++++++++ 7 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldtype.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkfieldtype.r diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am index 4847bf6fd..b60e97f1d 100644 --- a/libs/video/renderer/vulkan/vkgen/Makemodule.am +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -11,6 +11,7 @@ vkgen_dat_src= \ libs/video/renderer/vulkan/vkgen/vkfielddef.r \ libs/video/renderer/vulkan/vkgen/vkfieldsingle.r \ libs/video/renderer/vulkan/vkgen/vkfieldstring.r \ + libs/video/renderer/vulkan/vkgen/vkfieldtype.r \ libs/video/renderer/vulkan/vkgen/vkgen.r \ libs/video/renderer/vulkan/vkgen/vkstruct.r \ libs/video/renderer/vulkan/vkgen/vktype.r \ diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldarray.h b/libs/video/renderer/vulkan/vkgen/vkfieldarray.h index 5cf31880b..6f97f0aa7 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfieldarray.h +++ b/libs/video/renderer/vulkan/vkgen/vkfieldarray.h @@ -3,9 +3,11 @@ #include "vkfielddef.h" +@class FieldType; + @interface ArrayField: FieldDef { - string type; + FieldType *type; } @end diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldarray.r b/libs/video/renderer/vulkan/vkgen/vkfieldarray.r index dd81dd9f4..159a41ba3 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfieldarray.r +++ b/libs/video/renderer/vulkan/vkgen/vkfieldarray.r @@ -1,6 +1,7 @@ #include #include "vkfieldarray.h" +#include "vkfieldtype.h" #include "vkgen.h" #include "vktype.h" @@ -14,7 +15,7 @@ } PLItem *desc = [item getObjectForKey:"type"]; - type = [[desc getObjectAtIndex:1] string]; + type = [[FieldType fieldType:[desc getObjectAtIndex:1]] retain]; value_field = [[item getObjectForKey:"values"] string]; size_field = [[item getObjectForKey:"size"] string]; @@ -23,13 +24,9 @@ -writeParseData { - Type *field_type = [[Type lookup: type] dereference]; - fprintf (output_file, "static parse_array_t parse_%s_%s_data = {\n", struct_name, field_name); - fprintf (output_file, "\t%s,\n", [field_type parseType]); - fprintf (output_file, "\tsizeof (%s),\n", type); - fprintf (output_file, "\tparse_%s,\n", type); + [type writeParseData]; fprintf (output_file, "\tfield_offset (%s, %s),\n", struct_name, value_field); if (size_field) { diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldsingle.h b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.h index 2fcd312c4..83a3dad77 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfieldsingle.h +++ b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.h @@ -3,9 +3,11 @@ #include "vkfielddef.h" +@class FieldType; + @interface SingleField: FieldDef { - string type; + FieldType *type; } @end diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldsingle.r b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.r index e30ced3dd..f1c4b4977 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfieldsingle.r +++ b/libs/video/renderer/vulkan/vkgen/vkfieldsingle.r @@ -1,6 +1,7 @@ #include #include "vkfieldsingle.h" +#include "vkfieldtype.h" #include "vkgen.h" #include "vktype.h" @@ -14,7 +15,7 @@ } PLItem *desc = [item getObjectForKey:"type"]; - type = [[desc getObjectAtIndex:1] string]; + type = [[FieldType fieldType:[desc getObjectAtIndex:1]] retain]; value_field = [[item getObjectForKey:"value"] string]; return self; @@ -22,13 +23,9 @@ -writeParseData { - Type *field_type = [[Type lookup: type] dereference]; - fprintf (output_file, "static parse_single_t parse_%s_%s_data = {\n", struct_name, field_name); - fprintf (output_file, "\t%s,\n", [field_type parseType]); - fprintf (output_file, "\tsizeof (%s),\n", type); - fprintf (output_file, "\tparse_%s,\n", type); + [type writeParseData]; fprintf (output_file, "\tfield_offset (%s, %s),\n", struct_name, value_field); fprintf (output_file, "};\n"); @@ -37,7 +34,7 @@ -writeField { - string parse_type = [[[Type lookup: type] dereference] parseType]; + string parse_type = [type parseType]; fprintf (output_file, "\t{\"%s\", 0, %s, parse_%s, &parse_%s_%s_data},\n", field_name, parse_type, "single", struct_name, field_name); return self; diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldtype.h b/libs/video/renderer/vulkan/vkgen/vkfieldtype.h new file mode 100644 index 000000000..fa27c7d8e --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldtype.h @@ -0,0 +1,20 @@ +#ifndef __renderer_vulkan_vkgen_vkfieldtype_h +#define __renderer_vulkan_vkgen_vkfieldtype_h + +#include + +@class PLItem; + +@interface FieldType: Object +{ + string parse_type; + string type; + string parser; +} ++fieldType:(PLItem *)item; +-initWithItem:(PLItem *)item; +-writeParseData; +-(string)parseType; +@end + +#endif//__renderer_vulkan_vkgen_vkfieldtype_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldtype.r b/libs/video/renderer/vulkan/vkgen/vkfieldtype.r new file mode 100644 index 000000000..e3d7cf59d --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkfieldtype.r @@ -0,0 +1,69 @@ +#include +#include + +#include "vkfieldtype.h" +#include "vkgen.h" +#include "vktype.h" + +@implementation FieldType + ++fieldType:(PLItem *)item +{ + return [[[self alloc] initWithItem:item] autorelease]; +} + +-(void)dealloc +{ + str_free (parser); + str_free (parse_type); +} + +static string +parseItemType (PLItem *item) +{ + string str = [item string]; + if (str) { + return str; + } + string mask = "QFMultiType"; + for (int i = [item count]; i-- > 0; ) { + str = [[item getObjectAtIndex:i] string]; + mask = mask + " | (1 << " + str + ")"; + } + return str_hold (mask); +} + +-initWithItem:(PLItem *)item +{ + if (!(self = [super init])) { + return nil; + } + + type = [item string]; + if (type) { + Type *field_type = [[Type lookup:type] dereference]; + parse_type = [field_type parseType]; + parser = str_hold ("parse_" + type); + } else { + parse_type = parseItemType([item getObjectForKey:"parse_type"]); + type = [[item getObjectForKey:"type"] string]; + parser = [[item getObjectForKey:"parser"] string]; + } + + return self; +} + +-writeParseData +{ + fprintf (output_file, "\t%s,\n", parse_type); + fprintf (output_file, "\tsizeof (%s),\n", type); + fprintf (output_file, "\t%s,\n", parser); + return self; +} + +-(string) parseType +{ + return parse_type; +} + +@end From e4f75791ce273bc74a03828e2207fed1891736f2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 17:26:39 +0900 Subject: [PATCH 175/435] [vulkan] Clean up some tangled dependencies Dependencies on vkparse.hinc were spreading through the code which I didn't want as that removes a lot of the automation from the automake files. This keeps all parser code internal to vkparse.c's scope, and any accesses required for enum and struct (not yet) definitions can be fetched by name. --- include/QF/Vulkan/shader.h | 3 -- libs/video/renderer/vulkan/descriptor.c | 1 - libs/video/renderer/vulkan/shader.c | 16 ------ libs/video/renderer/vulkan/vkgen/vkenum.h | 1 + libs/video/renderer/vulkan/vkgen/vkenum.r | 6 +++ libs/video/renderer/vulkan/vkgen/vkgen.r | 1 + libs/video/renderer/vulkan/vkgen/vkstruct.h | 1 + libs/video/renderer/vulkan/vkgen/vkstruct.r | 4 ++ libs/video/renderer/vulkan/vkparse.c | 52 +++++++++++++++---- libs/video/renderer/vulkan/vkparse.h | 3 ++ .../video/renderer/vulkan/vulkan_vid_common.c | 5 +- 11 files changed, 62 insertions(+), 31 deletions(-) diff --git a/include/QF/Vulkan/shader.h b/include/QF/Vulkan/shader.h index b13f6a618..41b38a862 100644 --- a/include/QF/Vulkan/shader.h +++ b/include/QF/Vulkan/shader.h @@ -15,8 +15,5 @@ VkShaderModule QFV_FindShaderModule (struct vulkan_ctx_s *ctx, void QFV_RegisterShaderModule (struct vulkan_ctx_s *ctx, const char *name, VkShaderModule module); void QFV_DeregisterShaderModule (struct vulkan_ctx_s *ctx, const char *name); -int parse_VkShaderModule (const struct plitem_s *item, void **data, - struct plitem_s *messages, - struct parsectx_s *context); #endif//__QF_Vulkan_shader_h diff --git a/libs/video/renderer/vulkan/descriptor.c b/libs/video/renderer/vulkan/descriptor.c index 23c1a0d50..dc7cc6fa4 100644 --- a/libs/video/renderer/vulkan/descriptor.c +++ b/libs/video/renderer/vulkan/descriptor.c @@ -44,7 +44,6 @@ #include "QF/hash.h" #include "QF/input.h" #include "QF/mathlib.h" -#include "QF/qargs.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/va.h" diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index 5ee89ca25..e55833782 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -53,7 +53,6 @@ #include "QF/Vulkan/shader.h" #include "vid_vulkan.h" -#include "vkparse.h" static #include "libs/video/renderer/vulkan/passthrough.vert.spvc" @@ -212,18 +211,3 @@ QFV_DeregisterShaderModule (vulkan_ctx_t *ctx, const char *name) } Hash_Free (ctx->shadermodules, Hash_Del (ctx->shadermodules, name)); } - -int -parse_VkShaderModule (const plitem_t *item, void **data, - plitem_t *messages, parsectx_t *context) -{ - vulkan_ctx_t *ctx = context->vctx; - const char *name = PL_String (item); - __auto_type mptr = (VkShaderModule *)data[0]; - VkShaderModule module = QFV_FindShaderModule (ctx, name); - if (module) { - *mptr = module; - return 1; - } - return 0; -} diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.h b/libs/video/renderer/vulkan/vkgen/vkenum.h index 4df770b92..5577b8a23 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.h +++ b/libs/video/renderer/vulkan/vkgen/vkenum.h @@ -11,6 +11,7 @@ } -(void) writeTable; -(void) writeSymtabInit; +-(void) writeSymtabEntry; @end #endif//__renderer_vulkan_vkgen_vkenum_h diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.r b/libs/video/renderer/vulkan/vkgen/vkenum.r index 9f12c013e..22342cb1c 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.r +++ b/libs/video/renderer/vulkan/vkgen/vkenum.r @@ -147,6 +147,12 @@ skip_value(string name) [self name]); } +-(void) writeSymtabEntry +{ + fprintf (output_file, "\tHash_Add (enum_symtab, &%s_enum);\n", + [self name]); +} + -(string) cexprType { return [self name] + "_type"; diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r index 7a1edab8a..d47873ad2 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.r +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -251,6 +251,7 @@ main(int argc, string *argv) } arp_start (); [obj writeSymtabInit]; + [obj writeSymtabEntry]; arp_end (); } fprintf (output_file, "}\n"); diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.h b/libs/video/renderer/vulkan/vkgen/vkstruct.h index 048b3332f..08b489592 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.h +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.h @@ -16,6 +16,7 @@ -(qfot_var_t *)findField:(string) fieldName; -(void) writeTable; -(void) writeSymtabInit; +-(void) writeSymtabEntry; -(string) outname; @end diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index ac03d8f41..6d5c2cfc2 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -165,6 +165,10 @@ [self outname]); } +-(void) writeSymtabEntry +{ +} + -(string) outname { if (outname) { diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index d2ae12949..21e7bdf72 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -42,6 +42,7 @@ #include "QF/cmem.h" #include "QF/cvar.h" #include "QF/dstring.h" +#include "QF/hash.h" #include "QF/input.h" #include "QF/mathlib.h" #include "QF/qargs.h" @@ -50,6 +51,7 @@ #include "QF/sys.h" #include "QF/va.h" #include "QF/vid.h" +#include "QF/simd/vec4f.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/command.h" @@ -65,7 +67,10 @@ #include "vid_vulkan.h" #include "util.h" + +#define vkparse_internal #include "vkparse.h" +#undef vkparse_internal static void flag_or (const exprval_t *val1, const exprval_t *val2, exprval_t *result, exprctx_t *ctx) @@ -145,19 +150,16 @@ parse_basic (const plfield_t *field, const plitem_t *item, ectx.symtab = 0; ectx.result = &result; const char *valstr = PL_String (item); - //Sys_Printf ("parse_uint32_t: %s %zd %d %p %p: %s\n", + //Sys_Printf ("parse_basic: %s %zd %d %p %p: %s\n", // field->name, field->offset, field->type, field->parser, // field->data, valstr); if (strcmp (valstr, "VK_SUBPASS_EXTERNAL") == 0) { //FIXME handle subpass in a separate parser? *(uint32_t *) data = VK_SUBPASS_EXTERNAL; } else { - Sys_Printf ("parse_uint32_t: %s %zd %d %p %p %s\n", - field->name, field->offset, field->type, field->parser, - field->data, valstr); ret = !cexpr_eval_string (valstr, &ectx); - Sys_Printf (" %x\n", *(uint32_t *)data); } + //Sys_Printf (" %x\n", *(uint32_t *)data); return ret; } @@ -179,11 +181,11 @@ parse_uint32_t (const plfield_t *field, const plitem_t *item, //FIXME handle subpass in a separate parser? *(uint32_t *) data = VK_SUBPASS_EXTERNAL; } else { - Sys_Printf ("parse_uint32_t: %s %zd %d %p %p %s\n", - field->name, field->offset, field->type, field->parser, - field->data, valstr); + //Sys_Printf ("parse_uint32_t: %s %zd %d %p %p %s\n", + // field->name, field->offset, field->type, field->parser, + // field->data, valstr); ret = !cexpr_eval_string (valstr, &ectx); - Sys_Printf (" %d\n", *(uint32_t *)data); + //Sys_Printf (" %d\n", *(uint32_t *)data); } return ret; @@ -327,6 +329,23 @@ parse_custom (const plfield_t *field, const plitem_t *item, return custom->parse (item, offsets, messages, context); } + +static int +parse_VkShaderModule (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) +{ + vulkan_ctx_t *ctx = context->vctx; + const char *name = PL_String (item); + __auto_type mptr = (VkShaderModule *)data[0]; + VkShaderModule module = QFV_FindShaderModule (ctx, name); + if (module) { + *mptr = module; + return 1; + } + return 0; +} +static hashtab_t *enum_symtab; + #include "libs/video/renderer/vulkan/vkparse.cinc" typedef struct qfv_renderpass_s { @@ -421,9 +440,24 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) return renderpass; } +static const char * +enum_symtab_getkey (const void *e, void *unused) +{ + __auto_type enm = (const exprenum_t *) e; + return enm->type->name; +} + void QFV_InitParse (void) { exprctx_t context = {}; + enum_symtab = Hash_NewTable (61, enum_symtab_getkey, 0, 0, + &context.hashlinks); vkgen_init_symtabs (&context); } + +exprenum_t * +QFV_GetEnum (const char *name) +{ + return Hash_Find (enum_symtab, name); +} diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index b95475bda..e34624dab 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -3,7 +3,9 @@ #include "QF/cexpr.h" #include "QF/Vulkan/renderpass.h" +#ifdef vkparse_internal #include "libs/video/renderer/vulkan/vkparse.hinc" +#endif typedef struct parsectx_s { struct exprctx_s *ectx; @@ -12,5 +14,6 @@ typedef struct parsectx_s { VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); void QFV_InitParse (void); +exprenum_t *QFV_GetEnum (const char *name); #endif//__vkparse_h diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 78c4e9add..7647db9ff 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -98,11 +98,12 @@ msaaSamples_f (cvar_t *var) exprctx_t context = {}; context.memsuper = new_memsuper(); - if (cexpr_parse_enum (&VkSampleCountFlagBits_enum, var->string, &context, - &var->int_val)) { + if (cexpr_parse_enum (QFV_GetEnum ("VkSampleCountFlagBits"), var->string, + &context, &var->int_val)) { Sys_Printf ("Invalid MSAA samples, using 1\n"); var->int_val = VK_SAMPLE_COUNT_1_BIT; } + delete_memsuper (context.memsuper); } static void From d919a85c8e63cd7757f6b9be49cb0fc59d5124d3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 17:36:11 +0900 Subject: [PATCH 176/435] [vulkan] Implement pipeline layout creation It seems to work when parsing the layouts. They can be created in-line (in theory) or in a "setLayouts" node and then referenced by name. --- include/vid_vulkan.h | 1 + libs/video/renderer/vulkan/qfpipeline.plist | 31 ++++ libs/video/renderer/vulkan/vkparse.c | 116 +++++++++++++++ libs/video/renderer/vulkan/vkparse.h | 2 + libs/video/renderer/vulkan/vkparse.plist | 132 ++++++++++++++++++ .../video/renderer/vulkan/vulkan_vid_common.c | 21 ++- 6 files changed, 302 insertions(+), 1 deletion(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 5eb2dd157..29cbc8ff1 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -45,6 +45,7 @@ typedef struct vulkan_ctx_s { struct hashlink_s *hashlinks; //FIXME want per thread VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain struct hashtab_s *shadermodules; + struct hashtab_s *setLayouts; struct shadermodule_s *shadermodule_freelist; VkCommandPool cmdpool; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 7af624b99..d619b8406 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -14,6 +14,37 @@ file = $builtin/pushcolor.frag; }, ); + setLayouts = { + something = { + flags = 0; + bindings = ( + { + binding = 0; + descriptorType = sampled_image; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 1; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = vertex; + }, + ); + }; + }; + pipelineLayouts = { + something = { + setLayouts = (something); + pushConstantRanges = ( + { + stageFlags = fragment; + offset = 0; + size = "4 * 4"; + }, + ); + }; + }; renderpass = { attachments = ( { diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 21e7bdf72..0931ee755 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -53,6 +53,7 @@ #include "QF/vid.h" #include "QF/simd/vec4f.h" #include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/instance.h" @@ -329,6 +330,21 @@ parse_custom (const plfield_t *field, const plitem_t *item, return custom->parse (item, offsets, messages, context); } +static int +parse_RGBA (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) +{ + int ret = 1; + exprctx_t ectx = *context->ectx; + exprval_t result = { &cexpr_vector, data[0] }; + ectx.symtab = 0; + ectx.result = &result; + const char *valstr = PL_String (item); + Sys_Printf ("parse_RGBA: %s\n", valstr); + ret = !cexpr_eval_string (valstr, &ectx); + Sys_Printf (" "VEC4F_FMT"\n", VEC4_EXP (*(vec4f_t *)data[0])); + return ret; +} static int parse_VkShaderModule (const plitem_t *item, void **data, @@ -344,6 +360,79 @@ parse_VkShaderModule (const plitem_t *item, void **data, } return 0; } + +typedef struct setlayout_s { + char *name; + VkDescriptorSetLayout layout; +} setlayout_t; + +static const char * +setLayout_getkey (const void *sl, void *unused) +{ + return ((setlayout_t *)sl)->name; +} + +static void +setLayout_free (void *sl, void *_ctx) +{ + __auto_type setLayout = (setlayout_t *) sl; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyDescriptorSetLayout (device->dev, setLayout->layout, 0); + free (setLayout->name); + free (setLayout); +} + +static int +parse_VkDescriptorSetLayout (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type layout = (setlayout_t *) data; + vulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (PL_Type (item) == QFString) { + // accessing a named set layout + const char *name = PL_String (item); + setlayout_t *l = Hash_Find (ctx->setLayouts, name); + if (!l) { + PL_Message (messages, item, "undefined set layout %s", name); + return 0; + } + *layout = *l; + return 1; + } + + VkDescriptorSetLayoutCreateInfo createInfo = {}; + + if (!parse_VkDescriptorSetLayoutCreateInfo (0, item, &createInfo, + messages, context)) { + return 0; + } + layout->name = strdup (field->name); + VkResult res; + res = dfunc->vkCreateDescriptorSetLayout (device->dev, &createInfo, 0, + &layout->layout); + if (res != VK_SUCCESS) { + PL_Message (messages, item, "could not create set layout"); + return 0; + } + return 1; +} + +static plelement_t setLayout_data = { + QFDictionary, + sizeof (setlayout_t), + malloc, + parse_VkDescriptorSetLayout, + 0, +}; + +static plfield_t setLayout_field = { 0, 0, QFDictionary, 0, &setLayout_data }; + static hashtab_t *enum_symtab; #include "libs/video/renderer/vulkan/vkparse.cinc" @@ -440,6 +529,33 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) return renderpass; } +void +QFV_ParseDescriptorSetLayouts (vulkan_ctx_t *ctx, plitem_t *sets) +{ + plitem_t *messages = PL_NewArray (); + exprctx_t exprctx = {}; + parsectx_t parsectx = { &exprctx, ctx }; + + exprctx.memsuper = new_memsuper (); + exprctx.messages = messages; + exprctx.hashlinks = ctx->hashlinks; + + if (!ctx->setLayouts) { + ctx->setLayouts = Hash_NewTable (23, setLayout_getkey, setLayout_free, + ctx, &exprctx.hashlinks); + } + int res = PL_ParseSymtab (&setLayout_field, sets, ctx->setLayouts, + messages, &parsectx); + if (!res || developer->int_val & SYS_VULKAN) { + for (int i = 0; i < PL_A_NumObjects (messages); i++) { + Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); + } + } + PL_Free (messages); + delete_memsuper (exprctx.memsuper); + ctx->hashlinks = exprctx.hashlinks; +} + static const char * enum_symtab_getkey (const void *e, void *unused) { diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index e34624dab..0f47ac16a 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -12,6 +12,8 @@ typedef struct parsectx_s { struct vulkan_ctx_s *vctx; } parsectx_t; + +void QFV_ParseDescriptorSetLayouts (vulkan_ctx_t *ctx, plitem_t *sets); VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); void QFV_InitParse (void); exprenum_t *QFV_GetEnum (const char *name); diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index 1ba7e8bb4..95ad4368e 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -5,6 +5,18 @@ VkSubpassDependency, VkSpecializationInfo, VkPipelineShaderStageCreateInfo, + VkPipelineVertexInputStateCreateInfo, + VkPipelineInputAssemblyStateCreateInfo, + VkPipelineViewportStateCreateInfo, + VkPipelineRasterizationStateCreateInfo, + VkPipelineMultisampleStateCreateInfo, + VkPipelineDepthStencilStateCreateInfo, + VkPipelineColorBlendStateCreateInfo, + VkPipelineDynamicStateCreateInfo, + VkDescriptorSetLayoutBinding, + VkDescriptorSetLayoutCreateInfo, + VkPushConstantRange, + VkPipelineLayoutCreateInfo, qfv_swapchain_t, ); parse = { @@ -69,5 +81,125 @@ }; }; VkShaderModuleCreateInfo = skip; + VkDescriptorSetLayoutBinding = { + binding = auto; + descriptorType = auto; + descriptorCount = auto; + stageFlags = auto; + // skip pImmutableSamplers (default to 0) until I know how it works + }; + VkDescriptorSetLayoutCreateInfo = { + flags = auto; + bindings = { + type = (array, VkDescriptorSetLayoutBinding); + size = bindingCount; + values = pBindings; + }; + }; + VkPipelineVertexInputStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + bindings = { + type = (array, VkVertexInputBindingDescription); + size = vertexBindingDescriptionCount; + values = pVertexBindingDescriptions; + }; + attributes = { + type = (array, VkVertexInputAttributeDescription); + size = vertexAttributeDescriptionCount; + values = pVertexAttributeDescriptions; + }; + }; + VkPipelineInputAssemblyStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + topology = auto; + primitiveRestartEnable = auto; + }; + VkPipelineViewportStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + //FIXME redo as one array + viewports = { + type = (array, VkViewport); + size = viewportCount; + values = pViewports; + }; + scissors = { + type = (array, VkRect2D); + size = scissorCount; + values = pScissors; + }; + }; + VkPipelineRasterizationStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + depthClampEnable = auto; + rasterizerDiscardEnable = auto; + polygonMode = auto; + cullMode = auto; + frontFace = auto; + depthBiasEnable = auto; + depthBiasConstantFactor = auto; + depthBiasClamp = auto; + depthBiasSlopeFactor = auto; + lineWidth = auto; + }; + VkPipelineMultisampleStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + rasterizationSamples = auto; + sampleShadingEnable = auto; + minSampleShading = auto; + //pSampleMask = auto; FIXME disabled until correct size is known + alphaToCoverageEnable = auto; + alphaToOneEnable = auto; + }; + VkPipelineDepthStencilStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + depthTestEnable = auto; + depthWriteEnable = auto; + depthCompareOp = auto; + depthBoundsTestEnable = auto; + stencilTestEnable = auto; + front = auto; + back = auto; + minDepthBounds = auto; + maxDepthBounds = auto; + }; + VkPipelineColorBlendStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + logicOpEnable = auto; + logicOp = auto; + attachments = { + type = (array, VkPipelineColorBlendAttachmentState); + size = attachmentCount; + values = pAttachments; + }; + blendConstants = { + type = (custom, QFString, parse_RGBA); + fields = (blendConstants); + }; + }; + VkPipelineDynamicStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + dynamicState = { + type = (array, VkDynamicState); + size = dynamicStateCount; + values = pDynamicStates; + }; + }; + VkPipelineLayoutCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + setLayouts = { + type = (array, { + parse_type = (QFDictionary, QFString); + type = VkDescriptorSetLayout; + parser = parse_VkDescriptorSetLayout; + }); + size = setLayoutCount; + values = pSetLayouts; + }; + pushConstantRanges = { + type = (array, VkPushConstantRange); + size = pushConstantRangeCount; + values = pPushConstantRanges; + }; + } } } diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 7647db9ff..f515abd83 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -52,6 +52,7 @@ #include "QF/va.h" #include "QF/vid.h" #include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/instance.h" @@ -401,8 +402,10 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) void Vulkan_CreatePipelines (vulkan_ctx_t *ctx) { - plitem_t *item = qfv_load_pipeline (); + plitem_t *pipeline_def = qfv_load_pipeline (); + plitem_t *item; + item = pipeline_def; if (!item || !(item = PL_ObjectForKey (item, "modules"))) { Sys_Printf ("error loading modules\n"); } else { @@ -424,6 +427,22 @@ Vulkan_CreatePipelines (vulkan_ctx_t *ctx) QFV_RegisterShaderModule (ctx, name, module); } } + + item = pipeline_def; + if (!item || !(item = PL_ObjectForKey (item, "setLayouts"))) { + Sys_Printf ("error loading setLayouts\n"); + } else { + Sys_Printf ("Found setLayouts\n"); + QFV_ParseDescriptorSetLayouts (ctx, item); + } + + /*item = pipeline_def; + if (!item || !(item = PL_ObjectForKey (item, "pipelineLayouts"))) { + Sys_Printf ("error loading pipelineLayouts\n"); + } else { + Sys_Printf ("Found pipelineLayouts\n"); + QFV_ParsePipelineLayouts (ctx, item); + }*/ } void From 7e726545b86e81eb329fe3d853bd0ade0bacef63 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 19:28:27 +0900 Subject: [PATCH 177/435] [vulkan] Fix some string retention issues I really need to come up with a better solution for managing strings in quakec. --- libs/video/renderer/vulkan/vkgen/vkfieldcustom.r | 11 +++++++++-- libs/video/renderer/vulkan/vkgen/vkfieldtype.r | 6 ++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r index 3e9e56c74..7c7843414 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r +++ b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r @@ -1,4 +1,5 @@ #include +#include #include "vkfieldcustom.h" #include "vkgen.h" @@ -14,13 +15,19 @@ } PLItem *desc = [item getObjectForKey:"type"]; - pltype = [[desc getObjectAtIndex:1] string]; - parser = [[desc getObjectAtIndex:2] string]; + pltype = str_hold ([[desc getObjectAtIndex:1] string]); + parser = str_hold ([[desc getObjectAtIndex:2] string]); fields = [item getObjectForKey:"fields"]; return self; } +-(void)dealloc +{ + str_free (pltype); + str_free (parser); +} + -writeParseData { fprintf (output_file, "static size_t parse_%s_%s_offsets[] = {\n", diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldtype.r b/libs/video/renderer/vulkan/vkgen/vkfieldtype.r index e3d7cf59d..cb1a04508 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfieldtype.r +++ b/libs/video/renderer/vulkan/vkgen/vkfieldtype.r @@ -14,6 +14,7 @@ -(void)dealloc { + str_free (type); str_free (parser); str_free (parse_type); } @@ -42,12 +43,13 @@ parseItemType (PLItem *item) type = [item string]; if (type) { Type *field_type = [[Type lookup:type] dereference]; + type = str_hold (type); parse_type = [field_type parseType]; parser = str_hold ("parse_" + type); } else { parse_type = parseItemType([item getObjectForKey:"parse_type"]); - type = [[item getObjectForKey:"type"] string]; - parser = [[item getObjectForKey:"parser"] string]; + type = str_hold ([[item getObjectForKey:"type"] string]); + parser = str_hold ([[item getObjectForKey:"parser"] string]); } return self; From 1b8b7c04cbe1259af47106a87c22c3e1daf56acd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 23:42:10 +0900 Subject: [PATCH 178/435] [gamecode] Disconnect held strings from return slot Fixes an internal string error when a return string has been freed. --- libs/gamecode/pr_strings.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index e8e1dff85..7efd2265c 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -344,7 +344,7 @@ get_string (progs_t *pr, string_t num) case str_free: break; } - PR_Error (pr, "internal string error: %d", __LINE__); + PR_Error (pr, "internal string error: line:%d", __LINE__); } else { if (num >= pr->pr_stringsize) return 0; @@ -469,17 +469,17 @@ PR_SetReturnString (progs_t *pr, const char *s) requeue_strref (res, sr); } else if ((sr->type == str_return && !sr->rs_slot) || (sr->type != str_return && sr->rs_slot)) { - PR_Error (pr, "internal string error: %d %d %p", __LINE__, + PR_Error (pr, "internal string error: line:%d %d %p", __LINE__, sr->type, sr->rs_slot); } return string_index (res, sr); } // grab the string ref from the oldest slot, or make a new one if the - // slot is empty or the string has been held - if ((sr = res->rs_slot->strref) && sr->type != str_dynamic) { + // slot is empty + if ((sr = res->rs_slot->strref)) { if (sr->type != str_return || sr->rs_slot != res->rs_slot) { - PR_Error (pr, "internal string error: %d", __LINE__); + PR_Error (pr, "internal string error: line:%d", __LINE__); } pr_strfree (pr, sr->s.string); } else { @@ -629,7 +629,10 @@ PR_HoldString (progs_t *pr, string_t str) if (sr) { switch (sr->type) { case str_temp: + break; case str_return: + sr->rs_slot->strref = 0; + sr->rs_slot = 0; break; case str_static: case str_mutable: @@ -637,7 +640,7 @@ PR_HoldString (progs_t *pr, string_t str) // non-ephemeral string, no-op return; default: - PR_Error (pr, "internal string error: %d", __LINE__); + PR_Error (pr, "internal string error: line:%d", __LINE__); } sr->type = str_dynamic; return; @@ -666,7 +669,7 @@ PR_FreeString (progs_t *pr, string_t str) pr_strfree (pr, sr->s.string); break; default: - PR_Error (pr, "internal string error: %d", __LINE__); + PR_Error (pr, "internal string error: line:%d", __LINE__); } free_string_ref (res, sr); return; @@ -690,7 +693,7 @@ PR_FreeTempStrings (progs_t *pr) continue; } if (sr->type != str_temp) - PR_Error (pr, "internal string error: %d", __LINE__); + PR_Error (pr, "internal string error: line:%d", __LINE__); if (R_STRING (pr) < 0 && string_index (res, sr) == R_STRING (pr) && pr->pr_depth) { // It looks like the temp string is being returned. While this From ec7d974dc104668bb02e4380f9ddafe095614f9f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 00:07:58 +0900 Subject: [PATCH 179/435] [gamecode] Move % handling to the flags state % is effectively a format flag that cancels the format and outputs a % single %. Fixes % not getting output for %%. --- libs/gamecode/pr_strings.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index 7efd2265c..7cb295284 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -868,6 +868,7 @@ fmt_append_item (fmt_state_t *state) * \dot * digraph PR_Sprintf_fmt_state_machine { * format -> flags [label="{%}"]; + * flogs -> format [label="{%}"]; * flags -> flags [label="{#+0 -}"]; * flags -> var_field_width [label="{*}"]; * flags -> precision [label="{.}"]; @@ -906,6 +907,17 @@ fmt_state_flags (fmt_state_t *state) state->c++; // skip over % while (1) { switch (*state->c) { + case '%': + state->c++; + (*state->fi)->flags = 0; + (*state->fi)->precision = 1; + (*state->fi)->minFieldWidth = 0; + (*state->fi)->type = 's'; + (*state->fi)->data.string_var = "%"; + + fmt_append_item (state); + state->state = fmt_state_format; + return; case '0': (*state->fi)->flags |= FMT_ZEROPAD; break; @@ -1111,15 +1123,6 @@ fmt_state_conversion (fmt_state_t *state) (*state->fi)->data.string_var = "'"; state->fmt_count++; - fmt_append_item (state); - break; - case '%': - (*state->fi)->flags = 0; - (*state->fi)->precision = 0; - (*state->fi)->minFieldWidth = 0; - (*state->fi)->type = 's'; - (*state->fi)->data.string_var = "%"; - fmt_append_item (state); break; case 'x': From 9039c6975a461d44f6f1719aa1646eaae6fe4f29 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 08:35:53 +0900 Subject: [PATCH 180/435] [util] Clean up some missed vsqrt changes --- include/QF/simd/vec4d.h | 2 +- include/QF/simd/vec4f.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/QF/simd/vec4d.h b/include/QF/simd/vec4d.h index 1b8adbdfc..e73873bc0 100644 --- a/include/QF/simd/vec4d.h +++ b/include/QF/simd/vec4d.h @@ -244,7 +244,7 @@ qrotd (vec4d_t a, vec4d_t b) vec4d_t mb = vsqrtd (dotd (b, b)); vec4d_t den = 2 * ma * mb; vec4d_t t = mb * a + ma * b; - vec4d_t mba_mab = _mm256_sqrt_pd (dotd (t, t)); + vec4d_t mba_mab = vsqrtd (dotd (t, t)); vec4d_t q = crossd (a, b) / mba_mab; q[3] = (mba_mab / den)[0]; return q; diff --git a/include/QF/simd/vec4f.h b/include/QF/simd/vec4f.h index f3ea3b22f..85eb252eb 100644 --- a/include/QF/simd/vec4f.h +++ b/include/QF/simd/vec4f.h @@ -232,7 +232,7 @@ qrotf (vec4f_t a, vec4f_t b) vec4f_t mb = vsqrtf (dotf (b, b)); vec4f_t den = 2 * ma * mb; vec4f_t t = mb * a + ma * b; - vec4f_t mba_mab = _mm_sqrt_ps (dotf (t, t)); + vec4f_t mba_mab = vsqrtf (dotf (t, t)); vec4f_t q = crossf (a, b) / mba_mab; q[3] = (mba_mab / den)[0]; return q; From d8261ade9e1350fc713800e311892e6a01240b73 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 08:38:35 +0900 Subject: [PATCH 181/435] [vulkan] Generate code for vulkan handles The handles can be created in place or in resource blocks and referred to by name (resource block code gen next). --- include/vid_vulkan.h | 2 + .../video/renderer/vulkan/vkgen/Makemodule.am | 1 + libs/video/renderer/vulkan/vkgen/vkenum.r | 3 +- libs/video/renderer/vulkan/vkgen/vkgen.r | 18 +++ libs/video/renderer/vulkan/vkgen/vkhandle.h | 8 ++ libs/video/renderer/vulkan/vkgen/vkhandle.r | 56 ++++++++++ libs/video/renderer/vulkan/vkparse.c | 81 +++++--------- libs/video/renderer/vulkan/vkparse.plist | 105 ++++++++++++++++++ 8 files changed, 221 insertions(+), 53 deletions(-) create mode 100644 libs/video/renderer/vulkan/vkgen/vkhandle.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkhandle.r diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 29cbc8ff1..d35c0139d 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -46,6 +46,8 @@ typedef struct vulkan_ctx_s { VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain struct hashtab_s *shadermodules; struct hashtab_s *setLayouts; + struct hashtab_s *pipelineLayouts; + struct hashtab_s *renderPasses; struct shadermodule_s *shadermodule_freelist; VkCommandPool cmdpool; diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am index b60e97f1d..21c2ae97e 100644 --- a/libs/video/renderer/vulkan/vkgen/Makemodule.am +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -13,6 +13,7 @@ vkgen_dat_src= \ libs/video/renderer/vulkan/vkgen/vkfieldstring.r \ libs/video/renderer/vulkan/vkgen/vkfieldtype.r \ libs/video/renderer/vulkan/vkgen/vkgen.r \ + libs/video/renderer/vulkan/vkgen/vkhandle.r \ libs/video/renderer/vulkan/vkgen/vkstruct.r \ libs/video/renderer/vulkan/vkgen/vktype.r \ libs/video/renderer/vulkan/vkgen/vulkan.r diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.r b/libs/video/renderer/vulkan/vkgen/vkenum.r index 22342cb1c..537916800 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.r +++ b/libs/video/renderer/vulkan/vkgen/vkenum.r @@ -115,7 +115,7 @@ skip_value(string name) fprintf (output_file, "static exprtab_t %s_symtab = {\n", [self name]); fprintf (output_file, "\t%s_symbols,\n", [self name]); fprintf (output_file, "};\n"); - fprintf (output_file, "exprenum_t %s_enum = {\n", [self name]); + fprintf (output_file, "static exprenum_t %s_enum = {\n", [self name]); fprintf (output_file, "\t&%s_type,\n", [self name]); fprintf (output_file, "\t&%s_symtab,\n", [self name]); fprintf (output_file, "};\n"); @@ -138,7 +138,6 @@ skip_value(string name) " const plitem_t *item, void *data, plitem_t *messages," " void *context);\n", [self name]); - fprintf (header_file, "extern exprenum_t %s_enum;\n", [self name]); } -(void) writeSymtabInit diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r index d47873ad2..3d4837744 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.r +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -10,6 +10,7 @@ #include "vkgen.h" #include "vkstruct.h" #include "vkenum.h" +#include "vkhandle.h" static AutoreleasePool *autorelease_pool; static void @@ -148,6 +149,7 @@ main(int argc, string *argv) QFile plist_file; PLItem *plist; PLItem *search; + PLItem *handles; arp_start (); @@ -171,6 +173,7 @@ main(int argc, string *argv) printf ("%s not a dictionary\n", plist_filename); } search = [[plist getObjectForKey: "search"] retain]; + handles = [[plist getObjectForKey: "handles"] retain]; parse = [[plist getObjectForKey: "parse"] retain]; encodings = PR_FindGlobal (".type_encodings"); @@ -195,6 +198,17 @@ main(int argc, string *argv) } } + PLItem *handle_keys = [handles allKeys]; + for (int i = [handle_keys count]; i-- > 0; ) { + string search_name = [[handle_keys getObjectAtIndex:i] string]; + id obj = (id) Hash_Find (available_types, search_name); + obj = [obj resolveType]; + printf("handle: %d %s\n", obj, class_get_class_name([obj class])); + if (obj && [obj class] == [Struct class]) { + [obj addToQueue]; + } + } + while ([queue count]) { id obj = [queue objectAtIndex:0]; [queue removeObjectAtIndex:0]; @@ -241,6 +255,10 @@ main(int argc, string *argv) [obj writeTable]; arp_end (); } + for (int i = [handle_keys count]; i-- > 0; ) { + string key = [[handle_keys getObjectAtIndex:i] string]; + output_handle (key, [handles getObjectForKey: key]); + } fprintf (output_file, "static void\n"); fprintf (output_file, "vkgen_init_symtabs (exprctx_t *context)\n"); fprintf (output_file, "{\n"); diff --git a/libs/video/renderer/vulkan/vkgen/vkhandle.h b/libs/video/renderer/vulkan/vkgen/vkhandle.h new file mode 100644 index 000000000..47a68798b --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkhandle.h @@ -0,0 +1,8 @@ +#ifndef __renderer_vulkan_vkgen_vkhandle_h +#define __renderer_vulkan_vkgen_vkhandle_h + +@class PLItem; + +void output_handle (string name, PLItem *handle); + +#endif//__renderer_vulkan_vkgen_vkhandle_h diff --git a/libs/video/renderer/vulkan/vkgen/vkhandle.r b/libs/video/renderer/vulkan/vkgen/vkhandle.r new file mode 100644 index 000000000..d6e9a7f52 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkhandle.r @@ -0,0 +1,56 @@ +#include +#include + +#include "vkgen.h" +#include "vkhandle.h" + +void +output_handle (string name, PLItem *handle) +{ + string symtab = str_hold ([[handle getObjectForKey:"symtab"] string]); + string class = str_hold ([[handle getObjectForKey:"class"] string]); + string create = str_hold ([[handle getObjectForKey:"create"] string]); + fprintf (output_file, "static int parse_%s (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context)\n", name); + fprintf (output_file, "{\n"); + fprintf (output_file, "\t__auto_type handle = (%s *) data;\n", name); + fprintf (output_file, "\tvulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx;\n"); + fprintf (output_file, "\tqfv_device_t *device = ctx->device;\n"); + fprintf (output_file, "\tqfv_devfuncs_t *dfunc = device->funcs;\n"); + fprintf (output_file, "\tif (PL_Type (item) == QFString) {\n"); + fprintf (output_file, "\t\tconst char *name = PL_String (item);\n"); + fprintf (output_file, "\t\thandleref_t *hr = Hash_Find (ctx->%s, name);\n", symtab); + fprintf (output_file, "\t\tif (!hr) {\n"); + fprintf (output_file, "\t\t\tPL_Message (messages, item, \"undefined %s %%s\", name);\n", class); + fprintf (output_file, "\t\t\treturn 0;\n"); + fprintf (output_file, "\t\t}\n"); + fprintf (output_file, "\t\t*handle = (%s) hr->handle;\n", name); + fprintf (output_file, "\t\treturn 1;\n"); + fprintf (output_file, "\t}\n"); + + fprintf (output_file, "\t%sCreateInfo createInfo = {};\n", name); + + fprintf (output_file, "\tif (!parse_%sCreateInfo (0, item, &createInfo, messages, context)) {\n", name); + fprintf (output_file, "\t\treturn 0;\n"); + fprintf (output_file, "\t}\n"); + fprintf (output_file, "\tVkResult res;\n"); + fprintf (output_file, "\tres = dfunc->%s (device->dev, &createInfo, 0, handle);\n", create); + fprintf (output_file, "\tif (res != VK_SUCCESS) {\n"); + fprintf (output_file, "\t\tPL_Message (messages, item, \"could not create %s\");\n", class); + fprintf (output_file, "\t\treturn 0;\n"); + fprintf (output_file, "\t}\n"); + fprintf (output_file, "\treturn 1;\n"); + fprintf (output_file, "}\n"); + + fprintf (output_file, "int parse_%s_handleref (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context)\n", name); + fprintf (output_file, "{\n"); + fprintf (output_file, "\thandleref_t *handleref = data;\n"); + fprintf (output_file, "\thandleref->name = strdup (field->name);\n"); + fprintf (output_file, "\treturn parse_%s (field, item, &handleref->handle, messages, context);\n", name); + fprintf (output_file, "}\n"); + + fprintf (header_file, "static int parse_%s (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context);\n", name); + fprintf (header_file, "int parse_%s_handleref (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context);\n", name); + str_free (symtab); + str_free (class); + str_free (create); +} diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 0931ee755..af22a1dc0 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -361,82 +361,61 @@ parse_VkShaderModule (const plitem_t *item, void **data, return 0; } -typedef struct setlayout_s { +typedef struct handleref_s { char *name; - VkDescriptorSetLayout layout; -} setlayout_t; + uint64_t handle; +} handleref_t; static const char * -setLayout_getkey (const void *sl, void *unused) +handleref_getkey (const void *hr, void *unused) { - return ((setlayout_t *)sl)->name; + return ((handleref_t *)hr)->name; } static void -setLayout_free (void *sl, void *_ctx) +handleref_free (void *hr, void *_ctx) { - __auto_type setLayout = (setlayout_t *) sl; + __auto_type handleref = (handleref_t *) hr; + free (handleref->name); + free (handleref); +} + +static void +setLayout_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type layout = (VkDescriptorSetLayout) handleref->handle; __auto_type ctx = (vulkan_ctx_t *) _ctx; qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkDestroyDescriptorSetLayout (device->dev, setLayout->layout, 0); - free (setLayout->name); - free (setLayout); + dfunc->vkDestroyDescriptorSetLayout (device->dev, layout, 0); + handleref_free (handleref, ctx); } +static hashtab_t *enum_symtab; + static int -parse_VkDescriptorSetLayout (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +parse_BasePipeline (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) { - __auto_type layout = (setlayout_t *) data; - vulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx; - qfv_device_t *device = ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; - - if (PL_Type (item) == QFString) { - // accessing a named set layout - const char *name = PL_String (item); - setlayout_t *l = Hash_Find (ctx->setLayouts, name); - if (!l) { - PL_Message (messages, item, "undefined set layout %s", name); - return 0; - } - *layout = *l; - return 1; - } - - VkDescriptorSetLayoutCreateInfo createInfo = {}; - - if (!parse_VkDescriptorSetLayoutCreateInfo (0, item, &createInfo, - messages, context)) { - return 0; - } - layout->name = strdup (field->name); - VkResult res; - res = dfunc->vkCreateDescriptorSetLayout (device->dev, &createInfo, 0, - &layout->layout); - if (res != VK_SUCCESS) { - PL_Message (messages, item, "could not create set layout"); - return 0; - } - return 1; + *(VkPipeline *) data = 0; + PL_Message (messages, item, "not implemented"); + return 0; } +#include "libs/video/renderer/vulkan/vkparse.cinc" + static plelement_t setLayout_data = { QFDictionary, - sizeof (setlayout_t), + sizeof (handleref_t), malloc, - parse_VkDescriptorSetLayout, + parse_VkDescriptorSetLayout_handleref, 0, }; static plfield_t setLayout_field = { 0, 0, QFDictionary, 0, &setLayout_data }; -static hashtab_t *enum_symtab; - -#include "libs/video/renderer/vulkan/vkparse.cinc" - typedef struct qfv_renderpass_s { qfv_attachmentdescription_t *attachments; qfv_subpassparametersset_t *subpasses; @@ -541,7 +520,7 @@ QFV_ParseDescriptorSetLayouts (vulkan_ctx_t *ctx, plitem_t *sets) exprctx.hashlinks = ctx->hashlinks; if (!ctx->setLayouts) { - ctx->setLayouts = Hash_NewTable (23, setLayout_getkey, setLayout_free, + ctx->setLayouts = Hash_NewTable (23, handleref_getkey, setLayout_free, ctx, &exprctx.hashlinks); } int res = PL_ParseSymtab (&setLayout_field, sets, ctx->setLayouts, diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index 95ad4368e..c816b32c4 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -17,8 +17,26 @@ VkDescriptorSetLayoutCreateInfo, VkPushConstantRange, VkPipelineLayoutCreateInfo, + VkGraphicsPipelineCreateInfo, qfv_swapchain_t, ); + handles = { + VkDescriptorSetLayout = { + symtab = setLayouts; + class = "set layout"; + create = vkCreateDescriptorSetLayout; + }; + VkRenderPass = { + symtab = renderPasses; + class = "render pass"; + create = vkCreateRenderPass; + }; + VkPipelineLayout = { + symtab = pipelineLayouts; + class = "pipeline layout"; + create = vkCreatePipelineLayout; + }; + }; parse = { qfv_swapchain_s = { .name = qfv_swapchain_t; @@ -52,6 +70,24 @@ values = pPreserveAttachments; }; }; + VkRenderPassCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + attachments = { + type = (array, VkAttachmentDescription); + size = attachmentCount; + values = pAttachments; + }; + subpasses = { + type = (array, VkSubpassDescription); + size = subpassCount; + values = pSubpasses; + }; + dependencies = { + type = (array, VkSubpassDependency); + size = dependencyCount; + values = pDependencies; + }; + }; VkSpecializationInfo = { mapEntries = { type = (array, VkSpecializationMapEntry); @@ -200,6 +236,75 @@ size = pushConstantRangeCount; values = pPushConstantRanges; }; + }; + VkPipelineTessellationStateCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + patchControlPoints = auto; + }; + VkGraphicsPipelineCreateInfo = { + flags = auto; + stages = { + type = (array, VkPipelineShaderStageCreateInfo); + size = stageCount; + values = pStages; + }; + vertexInput = { + type = (single, VkPipelineVertexInputStateCreateInfo); + value = pVertexInputState; + }; + inputAssembly = { + type = (single, VkPipelineInputAssemblyStateCreateInfo); + value = pInputAssemblyState; + }; + tessellation = { + type = (single, VkPipelineTessellationStateCreateInfo); + value = pTessellationState; + }; + viewport = { + type = (single, VkPipelineViewportStateCreateInfo); + value = pViewportState; + }; + rasterization = { + type = (single, VkPipelineRasterizationStateCreateInfo); + value = pRasterizationState; + }; + multisample = { + type = (single, VkPipelineMultisampleStateCreateInfo); + value = pMultisampleState; + }; + depthStencil = { + type = (single, VkPipelineDepthStencilStateCreateInfo); + value = pDepthStencilState; + }; + colorBlend = { + type = (single, VkPipelineColorBlendStateCreateInfo); + value = pColorBlendState; + }; + dynamic = { + type = (single, VkPipelineDynamicStateCreateInfo); + value = pDynamicState; + }; + layout = { + type = (single, { + parse_type = (QFDictionary, QFString); + type = VkPipelineLayout; + parser = parse_VkPipelineLayout; + }); + value = layout; + }; + renderPass = { + type = (single, { + parse_type = (QFDictionary, QFString); + type = VkRenderPass; + parser = parse_VkRenderPass; + }); + value = renderPass; + }; + basePipelineHandle = { + type = (custom, QFString, parse_BasePipeline); + fields = (basePipelineHandle); + }; + basePipelineIndex = auto; } } } From e5708100bbf8b65a9578c472a2be68d36c1b4e99 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 14:15:35 +0900 Subject: [PATCH 182/435] [vulkan] Generate code for resource nodes This makes it easy to add resource nodes defining contextually named resources. It is already used for shaders, set layouts, and pipeline layouts. --- include/QF/Vulkan/shader.h | 5 - include/vid_vulkan.h | 3 +- libs/video/renderer/vulkan/qfpipeline.plist | 22 ++-- libs/video/renderer/vulkan/shader.c | 71 +---------- .../video/renderer/vulkan/vkgen/Makemodule.am | 1 + libs/video/renderer/vulkan/vkgen/vkgen.r | 16 +++ libs/video/renderer/vulkan/vkgen/vkhandle.r | 66 +++++----- libs/video/renderer/vulkan/vkgen/vkresource.h | 9 ++ libs/video/renderer/vulkan/vkgen/vkresource.r | 44 +++++++ libs/video/renderer/vulkan/vkparse.c | 118 ++++++++++++++---- libs/video/renderer/vulkan/vkparse.h | 12 +- libs/video/renderer/vulkan/vkparse.plist | 36 +++++- .../video/renderer/vulkan/vulkan_vid_common.c | 40 +----- 13 files changed, 257 insertions(+), 186 deletions(-) create mode 100644 libs/video/renderer/vulkan/vkgen/vkresource.h create mode 100644 libs/video/renderer/vulkan/vkgen/vkresource.r diff --git a/include/QF/Vulkan/shader.h b/include/QF/Vulkan/shader.h index 41b38a862..f44189978 100644 --- a/include/QF/Vulkan/shader.h +++ b/include/QF/Vulkan/shader.h @@ -10,10 +10,5 @@ VkShaderModule QFV_CreateShaderModule (struct qfv_device_s *device, const char *path); void QFV_DestroyShaderModule (struct qfv_device_s *device, VkShaderModule module); -VkShaderModule QFV_FindShaderModule (struct vulkan_ctx_s *ctx, - const char *name); -void QFV_RegisterShaderModule (struct vulkan_ctx_s *ctx, const char *name, - VkShaderModule module); -void QFV_DeregisterShaderModule (struct vulkan_ctx_s *ctx, const char *name); #endif//__QF_Vulkan_shader_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index d35c0139d..1741165ee 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -44,11 +44,10 @@ typedef struct vulkan_ctx_s { VkSampleCountFlagBits msaaSamples; // FIXME not here? struct hashlink_s *hashlinks; //FIXME want per thread VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain - struct hashtab_s *shadermodules; + struct hashtab_s *shaderModules; struct hashtab_s *setLayouts; struct hashtab_s *pipelineLayouts; struct hashtab_s *renderPasses; - struct shadermodule_s *shadermodule_freelist; VkCommandPool cmdpool; VkCommandBuffer cmdbuffer; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index d619b8406..ed74f689a 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -1,19 +1,13 @@ { - modules = ( + shaderModules = { // specify shader modules to load into memory - { - // the name of the module for referecy by the pipeline - name = passthrough; - // the path to the spv file to load - // $shader refers to the shader install path - // $builtin refers to compiled-in shaders - file = $builtin/passthrough.vert; - }, - { - name = pushcolor; - file = $builtin/pushcolor.frag; - }, - ); + // key is the name of the module for referecy by the pipeline + // value the path to the spv file to load + // $shader refers to the shader install path + // $builtin refers to compiled-in shaders + passthrough = $builtin/passthrough.vert; + pushcolor = $builtin/pushcolor.frag; + }; setLayouts = { something = { flags = 0; diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index e55833782..f0064bb35 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -65,14 +65,6 @@ typedef struct shaderdata_s { size_t size; } shaderdata_t; -typedef struct shadermodule_s { - char *name; - union { - VkShaderModule module; - struct shadermodule_s *next; - }; -} shadermodule_t; - static shaderdata_t builtin_shaders[] = { { "passthrough.vert", passthrough_vert, sizeof (passthrough_vert) }, { "pushcolor.frag", pushcolor_frag, sizeof (pushcolor_frag) }, @@ -122,6 +114,9 @@ QFV_CreateShaderModule (qfv_device_t *device, const char *shader_path) } if (data) { + Sys_MaskPrintf (SYS_VULKAN, + "QFV_CreateShaderModule: creating shader module %s\n", + shader_path); VkShaderModuleCreateInfo createInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0, 0, data->size, data->data @@ -151,63 +146,3 @@ QFV_DestroyShaderModule (qfv_device_t *device, VkShaderModule module) dfunc->vkDestroyShaderModule (dev, module, 0); } - -static shadermodule_t * -new_module (vulkan_ctx_t *ctx) -{ - shadermodule_t *shadermodule; - ALLOC (128, shadermodule_t, ctx->shadermodule, shadermodule); - return shadermodule; -} - -static void -del_module (shadermodule_t *shadermodule, vulkan_ctx_t *ctx) -{ - free (shadermodule->name); - FREE (ctx->shadermodule, shadermodule); -} - -static const char * -sm_getkey (const void *sm, void *unused) -{ - return ((shadermodule_t *) sm)->name; -} - -static void -sm_free (void *sm, void *ctx) -{ - del_module (sm, ctx); -} - -VkShaderModule -QFV_FindShaderModule (vulkan_ctx_t *ctx, const char *name) -{ - //FIXME - if (!ctx->shadermodules) { - ctx->shadermodules = Hash_NewTable (127, sm_getkey, sm_free, ctx, 0); - } - return Hash_Find (ctx->shadermodules, name); -} - -void -QFV_RegisterShaderModule (vulkan_ctx_t *ctx, const char *name, - VkShaderModule module) -{ - //FIXME - if (!ctx->shadermodules) { - ctx->shadermodules = Hash_NewTable (127, sm_getkey, sm_free, ctx, 0); - } - shadermodule_t *shadermodule = new_module (ctx); - shadermodule->name = strdup (name); - shadermodule->module = module; - Hash_Add (ctx->shadermodules, shadermodule); -} - -void -QFV_DeregisterShaderModule (vulkan_ctx_t *ctx, const char *name) -{ - if (!ctx->shadermodules) { - return; - } - Hash_Free (ctx->shadermodules, Hash_Del (ctx->shadermodules, name)); -} diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am index 21c2ae97e..2fba61b0b 100644 --- a/libs/video/renderer/vulkan/vkgen/Makemodule.am +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -14,6 +14,7 @@ vkgen_dat_src= \ libs/video/renderer/vulkan/vkgen/vkfieldtype.r \ libs/video/renderer/vulkan/vkgen/vkgen.r \ libs/video/renderer/vulkan/vkgen/vkhandle.r \ + libs/video/renderer/vulkan/vkgen/vkresource.r \ libs/video/renderer/vulkan/vkgen/vkstruct.r \ libs/video/renderer/vulkan/vkgen/vktype.r \ libs/video/renderer/vulkan/vkgen/vulkan.r diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r index 3d4837744..4636df52f 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.r +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -11,6 +11,7 @@ #include "vkstruct.h" #include "vkenum.h" #include "vkhandle.h" +#include "vkresource.h" static AutoreleasePool *autorelease_pool; static void @@ -150,6 +151,7 @@ main(int argc, string *argv) PLItem *plist; PLItem *search; PLItem *handles; + PLItem *resources; arp_start (); @@ -174,6 +176,7 @@ main(int argc, string *argv) } search = [[plist getObjectForKey: "search"] retain]; handles = [[plist getObjectForKey: "handles"] retain]; + resources = [[plist getObjectForKey: "resources"] retain]; parse = [[plist getObjectForKey: "parse"] retain]; encodings = PR_FindGlobal (".type_encodings"); @@ -259,6 +262,19 @@ main(int argc, string *argv) string key = [[handle_keys getObjectAtIndex:i] string]; output_handle (key, [handles getObjectForKey: key]); } + for (int i = [resources count]; i-- > 0; ) { + PLItem *res = [resources getObjectAtIndex:i]; + output_resource_data (res); + } + // keep the order intuitive (since it matters) + fprintf (output_file, "static parseres_t parse_resources[] = {\n"); + for (int i = 0; i < [resources count]; i++) { + PLItem *res = [resources getObjectAtIndex:i]; + output_resource_entry (res); + } + fprintf (output_file, "\t{}\n"); + fprintf (output_file, "};\n"); + fprintf (output_file, "static void\n"); fprintf (output_file, "vkgen_init_symtabs (exprctx_t *context)\n"); fprintf (output_file, "{\n"); diff --git a/libs/video/renderer/vulkan/vkgen/vkhandle.r b/libs/video/renderer/vulkan/vkgen/vkhandle.r index d6e9a7f52..da4a4fbcc 100644 --- a/libs/video/renderer/vulkan/vkgen/vkhandle.r +++ b/libs/video/renderer/vulkan/vkgen/vkhandle.r @@ -10,46 +10,54 @@ output_handle (string name, PLItem *handle) string symtab = str_hold ([[handle getObjectForKey:"symtab"] string]); string class = str_hold ([[handle getObjectForKey:"class"] string]); string create = str_hold ([[handle getObjectForKey:"create"] string]); - fprintf (output_file, "static int parse_%s (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context)\n", name); - fprintf (output_file, "{\n"); - fprintf (output_file, "\t__auto_type handle = (%s *) data;\n", name); - fprintf (output_file, "\tvulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx;\n"); - fprintf (output_file, "\tqfv_device_t *device = ctx->device;\n"); - fprintf (output_file, "\tqfv_devfuncs_t *dfunc = device->funcs;\n"); - fprintf (output_file, "\tif (PL_Type (item) == QFString) {\n"); - fprintf (output_file, "\t\tconst char *name = PL_String (item);\n"); - fprintf (output_file, "\t\thandleref_t *hr = Hash_Find (ctx->%s, name);\n", symtab); - fprintf (output_file, "\t\tif (!hr) {\n"); - fprintf (output_file, "\t\t\tPL_Message (messages, item, \"undefined %s %%s\", name);\n", class); - fprintf (output_file, "\t\t\treturn 0;\n"); - fprintf (output_file, "\t\t}\n"); - fprintf (output_file, "\t\t*handle = (%s) hr->handle;\n", name); - fprintf (output_file, "\t\treturn 1;\n"); - fprintf (output_file, "\t}\n"); + string custom = str_hold ([[handle getObjectForKey:"custom"] string]); + if (!custom) { + fprintf (output_file, "static int parse_%s (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context)\n", name); + fprintf (output_file, "{\n"); + fprintf (output_file, "\t__auto_type handle = (%s *) data;\n", name); + fprintf (output_file, "\tvulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx;\n"); + fprintf (output_file, "\tqfv_device_t *device = ctx->device;\n"); + fprintf (output_file, "\tqfv_devfuncs_t *dfunc = device->funcs;\n"); + fprintf (output_file, "\tif (PL_Type (item) == QFString) {\n"); + fprintf (output_file, "\t\tconst char *name = PL_String (item);\n"); + fprintf (output_file, "\t\thandleref_t *hr = Hash_Find (ctx->%s, name);\n", symtab); + fprintf (output_file, "\t\tif (!hr) {\n"); + fprintf (output_file, "\t\t\tPL_Message (messages, item, \"undefined %s %%s\", name);\n", class); + fprintf (output_file, "\t\t\treturn 0;\n"); + fprintf (output_file, "\t\t}\n"); + fprintf (output_file, "\t\t*handle = (%s) hr->handle;\n", name); + fprintf (output_file, "\t\treturn 1;\n"); + fprintf (output_file, "\t}\n"); - fprintf (output_file, "\t%sCreateInfo createInfo = {};\n", name); + fprintf (output_file, "\t%sCreateInfo createInfo = {};\n", name); - fprintf (output_file, "\tif (!parse_%sCreateInfo (0, item, &createInfo, messages, context)) {\n", name); - fprintf (output_file, "\t\treturn 0;\n"); - fprintf (output_file, "\t}\n"); - fprintf (output_file, "\tVkResult res;\n"); - fprintf (output_file, "\tres = dfunc->%s (device->dev, &createInfo, 0, handle);\n", create); - fprintf (output_file, "\tif (res != VK_SUCCESS) {\n"); - fprintf (output_file, "\t\tPL_Message (messages, item, \"could not create %s\");\n", class); - fprintf (output_file, "\t\treturn 0;\n"); - fprintf (output_file, "\t}\n"); - fprintf (output_file, "\treturn 1;\n"); - fprintf (output_file, "}\n"); + fprintf (output_file, "\tif (!parse_%sCreateInfo (0, item, &createInfo, messages, context)) {\n", name); + fprintf (output_file, "\t\treturn 0;\n"); + fprintf (output_file, "\t}\n"); + fprintf (output_file, "\tVkResult res;\n"); + fprintf (output_file, "\tres = dfunc->%s (device->dev, &createInfo, 0, handle);\n", create); + fprintf (output_file, "\tif (res != VK_SUCCESS) {\n"); + fprintf (output_file, "\t\tPL_Message (messages, item, \"could not create %s\");\n", class); + fprintf (output_file, "\t\treturn 0;\n"); + fprintf (output_file, "\t}\n"); + fprintf (output_file, "\treturn 1;\n"); + fprintf (output_file, "}\n"); + } fprintf (output_file, "int parse_%s_handleref (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context)\n", name); fprintf (output_file, "{\n"); fprintf (output_file, "\thandleref_t *handleref = data;\n"); fprintf (output_file, "\thandleref->name = strdup (field->name);\n"); - fprintf (output_file, "\treturn parse_%s (field, item, &handleref->handle, messages, context);\n", name); + if (custom) { + fprintf (output_file, "\treturn %s (field, item, &handleref->handle, messages, context);\n", custom); + } else { + fprintf (output_file, "\treturn parse_%s (field, item, &handleref->handle, messages, context);\n", name); + } fprintf (output_file, "}\n"); fprintf (header_file, "static int parse_%s (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context);\n", name); fprintf (header_file, "int parse_%s_handleref (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context);\n", name); + str_free (custom); str_free (symtab); str_free (class); str_free (create); diff --git a/libs/video/renderer/vulkan/vkgen/vkresource.h b/libs/video/renderer/vulkan/vkgen/vkresource.h new file mode 100644 index 000000000..e72042c3e --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkresource.h @@ -0,0 +1,9 @@ +#ifndef __renderer_vulkan_vkgen_vkresource_h +#define __renderer_vulkan_vkgen_vkresource_h + +@class PLItem; + +void output_resource_data (PLItem *resource); +void output_resource_entry (PLItem *resource); + +#endif//__renderer_vulkan_vkgen_vkresource_h diff --git a/libs/video/renderer/vulkan/vkgen/vkresource.r b/libs/video/renderer/vulkan/vkgen/vkresource.r new file mode 100644 index 000000000..47478d9f8 --- /dev/null +++ b/libs/video/renderer/vulkan/vkgen/vkresource.r @@ -0,0 +1,44 @@ +#include +#include + +#include "vkgen.h" +#include "vkresource.h" + +void +output_resource_data (PLItem *resource) +{ + string name = str_hold ([[resource getObjectForKey:"name"] string]); + string parse_type = str_hold ([[resource getObjectForKey:"parse_type"] string]); + string parser = str_hold ([[resource getObjectForKey:"parser"] string]); + string type = str_hold ([[resource getObjectForKey:"type"] string]); + + fprintf (output_file, "static plelement_t resource_%s_data = {\n", name); + fprintf (output_file, "\t%s,\n", parse_type); + fprintf (output_file, "\tsizeof (%s),\n", type); + fprintf (output_file, "\tmalloc,\n"); + fprintf (output_file, "\t%s,\n", parser); + fprintf (output_file, "\t0,\n"); + fprintf (output_file, "};\n"); + + fprintf (output_file, "static plfield_t resource_%s_field = {\n", name); + fprintf (output_file, "\t0, 0, %s, 0, &resource_%s_data\n", + parse_type, name); + fprintf (output_file, "};\n"); + + str_free (name); + str_free (parse_type); + str_free (parser); + str_free (type); +} + +void +output_resource_entry (PLItem *resource) +{ + string name = str_hold ([[resource getObjectForKey:"name"] string]); + string table = str_hold ([[resource getObjectForKey:"table"] string]); + fprintf (output_file, + "\t{\"%s\", &resource_%s_field, field_offset (vulkan_ctx_t, %s) },\n", + name, name, table); + str_free (name); + str_free (table); +} diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index af22a1dc0..418ef707d 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -207,6 +207,9 @@ parse_enum (const plfield_t *field, const plitem_t *item, // field->name, field->offset, field->type, field->parser, // field->data, valstr); ret = !cexpr_parse_enum (enm, valstr, &ectx, data); + if (!ret) { + PL_Message (messages, item, "error parsing enum: %s", valstr); + } //Sys_Printf (" %d\n", *(int *)data); return ret; } @@ -347,24 +350,37 @@ parse_RGBA (const plitem_t *item, void **data, } static int -parse_VkShaderModule (const plitem_t *item, void **data, - plitem_t *messages, parsectx_t *context) +parse_VkShaderModule (const plfield_t *field, const plitem_t *item, void *data, + plitem_t *messages, void *context) { - vulkan_ctx_t *ctx = context->vctx; + __auto_type handle = (VkShaderModule *) data; + vulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx; + const char *name = PL_String (item); - __auto_type mptr = (VkShaderModule *)data[0]; - VkShaderModule module = QFV_FindShaderModule (ctx, name); - if (module) { - *mptr = module; - return 1; + handleref_t *hr = Hash_Find (ctx->shaderModules, name); + if (!hr) { + PL_Message (messages, item, "undefined shader module %s", name); + return 0; } - return 0; + *handle = (VkShaderModule) hr->handle; + return 1; } -typedef struct handleref_s { - char *name; - uint64_t handle; -} handleref_t; +static int +parse_VkShaderModule_resource (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + __auto_type handle = (VkShaderModule *) data; + vulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx; + qfv_device_t *device = ctx->device; + + const char *shader_path = PL_String (item); + if (!(*handle = QFV_CreateShaderModule (device, shader_path))) { + PL_Message (messages, item, "could not find shader %s", shader_path); + return 0; + } + return 1; +} static const char * handleref_getkey (const void *hr, void *unused) @@ -393,6 +409,45 @@ setLayout_free (void *hr, void *_ctx) handleref_free (handleref, ctx); } +static void +shaderModule_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type module = (VkShaderModule) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyShaderModule (device->dev, module, 0); + handleref_free (handleref, ctx); +} + +static void +pipelineLayout_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type layout = (VkPipelineLayout) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyPipelineLayout (device->dev, layout, 0); + handleref_free (handleref, ctx); +} + +static void +renderPass_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type renderPass = (VkRenderPass) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyRenderPass (device->dev, renderPass, 0); + handleref_free (handleref, ctx); +} + static hashtab_t *enum_symtab; static int @@ -406,16 +461,6 @@ parse_BasePipeline (const plitem_t *item, void **data, #include "libs/video/renderer/vulkan/vkparse.cinc" -static plelement_t setLayout_data = { - QFDictionary, - sizeof (handleref_t), - malloc, - parse_VkDescriptorSetLayout_handleref, - 0, -}; - -static plfield_t setLayout_field = { 0, 0, QFDictionary, 0, &setLayout_data }; - typedef struct qfv_renderpass_s { qfv_attachmentdescription_t *attachments; qfv_subpassparametersset_t *subpasses; @@ -509,27 +554,46 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) } void -QFV_ParseDescriptorSetLayouts (vulkan_ctx_t *ctx, plitem_t *sets) +QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *pipelinedef) { plitem_t *messages = PL_NewArray (); exprctx_t exprctx = {}; parsectx_t parsectx = { &exprctx, ctx }; + int ret = 1; exprctx.memsuper = new_memsuper (); exprctx.messages = messages; exprctx.hashlinks = ctx->hashlinks; if (!ctx->setLayouts) { + ctx->shaderModules = Hash_NewTable (23, handleref_getkey, + shaderModule_free, + ctx, &exprctx.hashlinks); ctx->setLayouts = Hash_NewTable (23, handleref_getkey, setLayout_free, ctx, &exprctx.hashlinks); + ctx->pipelineLayouts = Hash_NewTable (23, handleref_getkey, + pipelineLayout_free, + ctx, &exprctx.hashlinks); + ctx->renderPasses = Hash_NewTable (23, handleref_getkey, + renderPass_free, + ctx, &exprctx.hashlinks); } - int res = PL_ParseSymtab (&setLayout_field, sets, ctx->setLayouts, - messages, &parsectx); - if (!res || developer->int_val & SYS_VULKAN) { + + for (parseres_t *res = parse_resources; res->name; res++) { + plitem_t *item = PL_ObjectForKey (pipelinedef, res->name); + if (item) { + __auto_type table = *(hashtab_t **) ((size_t) ctx + res->offset); + Sys_Printf ("found %s\n", res->name); + ret &= PL_ParseSymtab (res->field, item, table, messages, + &parsectx); + } + } + if (!ret || developer->int_val & SYS_VULKAN) { for (int i = 0; i < PL_A_NumObjects (messages); i++) { Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); } } + PL_Free (messages); delete_memsuper (exprctx.memsuper); ctx->hashlinks = exprctx.hashlinks; diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index 0f47ac16a..e63bb44e2 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -12,9 +12,19 @@ typedef struct parsectx_s { struct vulkan_ctx_s *vctx; } parsectx_t; +typedef struct parseres_s { + const char *name; + plfield_t *field; + size_t offset; +} parseres_t; + +typedef struct handleref_s { + char *name; + uint64_t handle; +} handleref_t; -void QFV_ParseDescriptorSetLayouts (vulkan_ctx_t *ctx, plitem_t *sets); VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); +void QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *plist); void QFV_InitParse (void); exprenum_t *QFV_GetEnum (const char *name); diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index c816b32c4..844b471f9 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -21,6 +21,11 @@ qfv_swapchain_t, ); handles = { + VkShaderModule = { + symtab = shaderModules; + class = "shader module"; + custom = parse_VkShaderModule_resource; + }; VkDescriptorSetLayout = { symtab = setLayouts; class = "set layout"; @@ -37,6 +42,29 @@ create = vkCreatePipelineLayout; }; }; + resources = ( + { + name = shaderModules; + parse_type = QFString; + parser = parse_VkShaderModule_handleref; + type = handleref_t; + table = shaderModules; + }, + { + name = setLayouts; + parse_type = QFDictionary; + parser = parse_VkDescriptorSetLayout_handleref; + type = handleref_t; + table = setLayouts; + }, + { + name = pipelineLayouts; + parse_type = QFDictionary; + parser = parse_VkPipelineLayout_handleref; + type = handleref_t; + table = pipelineLayouts; + }, + ); parse = { qfv_swapchain_s = { .name = qfv_swapchain_t; @@ -108,8 +136,12 @@ string = pName; }; module = { - type = (custom, QFString, parse_VkShaderModule); - fields = (module); + type = (single, { + parse_type = QFString; + type = VkShaderModule; + parser = parse_VkShaderModule; + }); + value = module; }; specializationInfo = { type = (single, VkSpecializationInfo); diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index f515abd83..12c9a463b 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -403,46 +403,10 @@ void Vulkan_CreatePipelines (vulkan_ctx_t *ctx) { plitem_t *pipeline_def = qfv_load_pipeline (); - plitem_t *item; - item = pipeline_def; - if (!item || !(item = PL_ObjectForKey (item, "modules"))) { - Sys_Printf ("error loading modules\n"); - } else { - Sys_Printf ("Found modules def\n"); + if (pipeline_def) { + QFV_ParseResources (ctx, pipeline_def); } - for (int i = PL_A_NumObjects (item); i-- > 0; ) { - plitem_t *mod = PL_ObjectAtIndex (item, i); - const char *name = PL_String (PL_ObjectForKey (mod, "name")); - const char *file = PL_String (PL_ObjectForKey (mod, "file")); - if (!name || !file) { - continue; - } - if (QFV_FindShaderModule (ctx, name)) { - continue; - } - VkShaderModule module = QFV_CreateShaderModule (ctx->device, file); - if (module) { - Sys_Printf ("registering shader %s %p\n", name, module); - QFV_RegisterShaderModule (ctx, name, module); - } - } - - item = pipeline_def; - if (!item || !(item = PL_ObjectForKey (item, "setLayouts"))) { - Sys_Printf ("error loading setLayouts\n"); - } else { - Sys_Printf ("Found setLayouts\n"); - QFV_ParseDescriptorSetLayouts (ctx, item); - } - - /*item = pipeline_def; - if (!item || !(item = PL_ObjectForKey (item, "pipelineLayouts"))) { - Sys_Printf ("error loading pipelineLayouts\n"); - } else { - Sys_Printf ("Found pipelineLayouts\n"); - QFV_ParsePipelineLayouts (ctx, item); - }*/ } void From 518befdaed3a8aad617baeca7b633cc3c493aa6b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 17:40:07 +0900 Subject: [PATCH 183/435] [util] FIx an "only" in a comment --- include/QF/hash.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/hash.h b/include/QF/hash.h index fde2eed97..f96682fd9 100644 --- a/include/QF/hash.h +++ b/include/QF/hash.h @@ -46,7 +46,7 @@ typedef struct hashlink_s hashlink_t; inserting or finding the element. First parameter is a pointer to the element from which to extract the key, the second is the user data pointer. - \param f a function to free the element. Only ever called from + \param f a function to free the element. Called from only Hash_FlushTable and Hash_DelTable. The first parameter is the element to be freed and the second is the user data pointer. \param ud user data pointer. set to whatever you want, it will be passed From 7c661e7cc51d51839e7c6e7451c93800831c7485 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 17:43:26 +0900 Subject: [PATCH 184/435] [vulkan] Remove renderpass from generated code The creation of a render pass seems to need special handling. --- include/vid_vulkan.h | 2 +- libs/video/renderer/vulkan/qfpipeline.plist | 77 ++++++++++++++++++++- libs/video/renderer/vulkan/vkparse.c | 16 ----- libs/video/renderer/vulkan/vkparse.plist | 15 +--- 4 files changed, 78 insertions(+), 32 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 1741165ee..74a1ef51a 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -44,10 +44,10 @@ typedef struct vulkan_ctx_s { VkSampleCountFlagBits msaaSamples; // FIXME not here? struct hashlink_s *hashlinks; //FIXME want per thread VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain + struct plitem_s *pipelineDef; struct hashtab_s *shaderModules; struct hashtab_s *setLayouts; struct hashtab_s *pipelineLayouts; - struct hashtab_s *renderPasses; VkCommandPool cmdpool; VkCommandBuffer cmdbuffer; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index ed74f689a..198604466 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -39,6 +39,81 @@ ); }; }; + pipelines = { + something = { + stages = ( + { stage = vertex; name = main; module = passthrough; }, + { stage = fragment; name = main; module = pushcolor; }, + ); + vertexInput = { + bindings = ( + { + binding = 0; + stride = "4 * 4"; + inputRate = vertex; + }, + ); + attributes = ( + { + location = 0; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 0; + }, + ); + }; + inputAssembly = { + topology = triangle_list; + primitiveRestartEnable = 0; + }; + viewport = { + viewports = ( + { + x = 0; y = 0; + width = 640; height = 480; + minDepth = 0; maxDepth = 1000; + } + ); + scissors = ( + { + offset = { x = 0; y = 0 }; + extent = { width = 640; height = 480; }; + }, + ); + }; + rasterization = { + depthClampEnable = 1; + rasterizerDiscardEnable = 0; + polygonMode = fill; + cullMode = back; + frontFace = counter_clockwise; + depthBiasEnable = 0; + lineWidth = 1; + }; + multisample = { + rasterizationSamples = $msaaSamples; + sampleShadingEnable = 0; + minSampleShading = 0.5; + alphaToCoverageEnable = 0; + alphaToOneEnable = 0; + }; + depthStencil = { + depthTestEnable = 1; + depthWriteEnable = 1; + depthCompareOp = less; + depthBoundsTestEnable = 0; + stencilTestEnable = 0; + }; + colorBlend = { + logicOpEnable = 0; + }; + dymamic = { + dymamicState = ( viewport, scissor ); + }; + layout = something; + renderPass = renderpass; + }; + }; renderpass = { attachments = ( { @@ -108,5 +183,5 @@ dependencyFlags = 0; } ); - } + }; } diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 418ef707d..08ab9acfb 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -435,19 +435,6 @@ pipelineLayout_free (void *hr, void *_ctx) handleref_free (handleref, ctx); } -static void -renderPass_free (void *hr, void *_ctx) -{ - __auto_type handleref = (handleref_t *) hr; - __auto_type renderPass = (VkRenderPass) handleref->handle; - __auto_type ctx = (vulkan_ctx_t *) _ctx; - qfv_device_t *device = ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; - - dfunc->vkDestroyRenderPass (device->dev, renderPass, 0); - handleref_free (handleref, ctx); -} - static hashtab_t *enum_symtab; static int @@ -574,9 +561,6 @@ QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *pipelinedef) ctx->pipelineLayouts = Hash_NewTable (23, handleref_getkey, pipelineLayout_free, ctx, &exprctx.hashlinks); - ctx->renderPasses = Hash_NewTable (23, handleref_getkey, - renderPass_free, - ctx, &exprctx.hashlinks); } for (parseres_t *res = parse_resources; res->name; res++) { diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index 844b471f9..e270fb9be 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -31,11 +31,6 @@ class = "set layout"; create = vkCreateDescriptorSetLayout; }; - VkRenderPass = { - symtab = renderPasses; - class = "render pass"; - create = vkCreateRenderPass; - }; VkPipelineLayout = { symtab = pipelineLayouts; class = "pipeline layout"; @@ -129,7 +124,7 @@ }; }; VkPipelineShaderStageCreateInfo = { - flags = auto; + //flags = auto; reserved for future use (Bits enum does not exist) stage = auto; name = { type = string; @@ -324,14 +319,6 @@ }); value = layout; }; - renderPass = { - type = (single, { - parse_type = (QFDictionary, QFString); - type = VkRenderPass; - parser = parse_VkRenderPass; - }); - value = renderPass; - }; basePipelineHandle = { type = (custom, QFString, parse_BasePipeline); fields = (basePipelineHandle); From d22be09ae339ed7628283fccbed0f0c690b8a053 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 17:45:02 +0900 Subject: [PATCH 185/435] [vulkan] Clean up pipeline def loading --- .../video/renderer/vulkan/vulkan_vid_common.c | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 12c9a463b..486e078e4 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -260,22 +260,23 @@ static qfv_pipelinestagepair_t imageLayoutTransitionStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }, }; -static plitem_t * -qfv_load_pipeline (void) +static void +qfv_load_pipeline (vulkan_ctx_t *ctx) { - static plitem_t *pipeline; - - if (!pipeline) { - pipeline = PL_GetPropertyList (quakeforge_pipeline); + if (!ctx->pipelineDef) { + ctx->pipelineDef = PL_GetPropertyList (quakeforge_pipeline); + if (ctx->pipelineDef) { + QFV_ParseResources (ctx, ctx->pipelineDef); + } } - return pipeline; } void Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) { - plitem_t *item = qfv_load_pipeline (); + qfv_load_pipeline (ctx); + plitem_t *item = ctx->pipelineDef; if (!item || !(item = PL_ObjectForKey (item, "renderpass"))) { Sys_Printf ("error loading renderpass\n"); } else { @@ -402,11 +403,6 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) void Vulkan_CreatePipelines (vulkan_ctx_t *ctx) { - plitem_t *pipeline_def = qfv_load_pipeline (); - - if (pipeline_def) { - QFV_ParseResources (ctx, pipeline_def); - } } void From dc704a9384a23ecdc5f327eb161507dcf3825e52 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 17:46:03 +0900 Subject: [PATCH 186/435] [vulkan] Update the validation layer request It's now Kronos as LunarG has been deprecated (explains why I got no help with some of my debugging). --- libs/video/renderer/vulkan/instance.c | 2 +- libs/video/renderer/vulkan/vulkan_vid_common.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/video/renderer/vulkan/instance.c b/libs/video/renderer/vulkan/instance.c index b228df2fe..617d792e8 100644 --- a/libs/video/renderer/vulkan/instance.c +++ b/libs/video/renderer/vulkan/instance.c @@ -59,7 +59,7 @@ static VkExtensionProperties *instanceExtensionProperties; static strset_t *instanceExtensions; const char * const vulkanValidationLayers[] = { - "VK_LAYER_LUNARG_standard_validation", + "VK_LAYER_KHRONOS_validation", 0, }; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 486e078e4..23d5ca4cc 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -112,8 +112,8 @@ Vulkan_Init_Cvars (void) { vulkan_use_validation = Cvar_Get ("vulkan_use_validation", "1", CVAR_NONE, 0, - "enable LunarG Standard Validation " - "Layer if available (requires instance " + "enable KRONOS Validation Layer if " + "available (requires instance " "restart)."); // FIXME implement fallback choices (instead of just fifo) vulkan_presentation_mode = Cvar_Get ("vulkan_presentation_mode", "mailbox", From 3cf8a336a81f627c21573deaa2a232b1c1b7fe29 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 17:48:00 +0900 Subject: [PATCH 187/435] [vulkan] Clear out the resource tables on shutdown This would take care of undestroyed resources if there wasn't a problem with invalid memory use. Not sure what's going on just yet. --- libs/video/renderer/vulkan/vkparse.c | 12 +++++++++--- libs/video/renderer/vulkan/vulkan_vid_common.c | 13 +++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 08ab9acfb..55192ad36 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -405,7 +405,9 @@ setLayout_free (void *hr, void *_ctx) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkDestroyDescriptorSetLayout (device->dev, layout, 0); + if (layout) { + dfunc->vkDestroyDescriptorSetLayout (device->dev, layout, 0); + } handleref_free (handleref, ctx); } @@ -418,7 +420,9 @@ shaderModule_free (void *hr, void *_ctx) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkDestroyShaderModule (device->dev, module, 0); + if (module) { + dfunc->vkDestroyShaderModule (device->dev, module, 0); + } handleref_free (handleref, ctx); } @@ -431,7 +435,9 @@ pipelineLayout_free (void *hr, void *_ctx) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkDestroyPipelineLayout (device->dev, layout, 0); + if (layout) { + dfunc->vkDestroyPipelineLayout (device->dev, layout, 0); + }; handleref_free (handleref, ctx); } diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 23d5ca4cc..fc0a97edf 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -43,6 +43,7 @@ #include "QF/cmem.h" #include "QF/cvar.h" #include "QF/dstring.h" +#include "QF/hash.h" #include "QF/input.h" #include "QF/mathlib.h" #include "QF/qargs.h" @@ -144,6 +145,15 @@ Vulkan_Init_Common (vulkan_ctx_t *ctx) ctx->instance = QFV_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version } +static void +clear_table (hashtab_t **table) +{ + if (*table) { + Hash_DelTable (*table); + *table = 0; + } +} + void Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) { @@ -156,6 +166,9 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) if (ctx->swapchain) { QFV_DestroySwapchain (ctx->swapchain); } + clear_table (&ctx->pipelineLayouts); + clear_table (&ctx->setLayouts); + clear_table (&ctx->shaderModules); ctx->instance->funcs->vkDestroySurfaceKHR (ctx->instance->instance, ctx->surface, 0); if (ctx->device) { From 37b6d11c01d5a7aba766d28bd9185918c81be7dc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 18:24:18 +0900 Subject: [PATCH 188/435] [ruamoko] Add binding for str_upper I can't believe I didn't do that when I did str_lower. --- libs/ruamoko/rua_string.c | 17 +++++++++++++++++ ruamoko/include/string.h | 1 + ruamoko/lib/string.r | 1 + 3 files changed, 19 insertions(+) diff --git a/libs/ruamoko/rua_string.c b/libs/ruamoko/rua_string.c index 31b717273..754d1627e 100644 --- a/libs/ruamoko/rua_string.c +++ b/libs/ruamoko/rua_string.c @@ -265,6 +265,22 @@ bi_str_lower (progs_t *pr) RETURN_STRING (pr, lower); } +static void +bi_str_upper (progs_t *pr) +{ + const char *str = P_GSTRING (pr, 0); + char *upper = alloca (strlen (str) + 1); + char *l = upper; + byte c; + + while ((c = *str++)) { + *l++ = toupper (c); + } + *l++ = 0; + + RETURN_STRING (pr, upper); +} + static builtin_t builtins[] = { {"strlen", bi_strlen, -1}, {"sprintf", bi_sprintf, -1}, @@ -283,6 +299,7 @@ static builtin_t builtins[] = { {"str_char", bi_str_char, -1}, {"str_quote", bi_str_quote, -1}, {"str_lower", bi_str_lower, -1}, + {"str_upper", bi_str_upper, -1}, {0} }; diff --git a/ruamoko/include/string.h b/ruamoko/include/string.h index 8087ef67e..3d978cfd5 100644 --- a/ruamoko/include/string.h +++ b/ruamoko/include/string.h @@ -18,5 +18,6 @@ int str_str (string haystack, string needle); @extern int str_char (string str, int ind); string str_quote (string str); string str_lower (string str); +string str_upper (string str); #endif//__ruamoko_string_h diff --git a/ruamoko/lib/string.r b/ruamoko/lib/string.r index 3858ef7d6..5169296a0 100644 --- a/ruamoko/lib/string.r +++ b/ruamoko/lib/string.r @@ -17,3 +17,4 @@ int str_str (string haystack, string needle) = #0; int str_char (string str, int ind) = #0; string str_quote (string str) = #0; string str_lower (string str) = #0; +string str_upper (string str) = #0; From d8b389d2b61cc58870e0e94d9bf088d46080a049 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 18:26:01 +0900 Subject: [PATCH 189/435] [vulkan] Initialize sType in parsed structures This fixes a lot of validation issues, but still some fun with uninitialized memory and bad accesses. --- libs/video/renderer/vulkan/vkgen/vkstruct.r | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index 6d5c2cfc2..108af71ef 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -47,11 +47,31 @@ return nil; } +-(string)sTypeName +{ + string s = "VK_STRUCTURE_TYPE"; + string name = str_hold ([self outname]); + int length = strlen (name); + int start, end, c; + for (start = 2; start < length; start = end) { + for (end = start + 1; end < length; end++) { + c = str_char (name, end); + if (c >= 'A' && c <= 'Z') { + break; + } + } + s += "_" + str_mid (name, start, end); + } + str_free (name); + return str_upper (s); +} + -(void) writeTable { PLItem *field_dict = [parse getObjectForKey:[self name]]; PLItem *new_name = [field_dict getObjectForKey:".name"]; Array *field_defs = [Array array]; + int have_sType = 0; if ([parse string] == "skip") { return; @@ -60,6 +80,12 @@ outname = str_hold ([new_name string]); } + for (int i = 0; i < type.strct.num_fields; i++) { + qfot_var_t *field = &type.strct.fields[i]; + if (field.name == "sType") { + have_sType = 1; + } + } if (field_dict) { PLItem *field_keys = [field_dict allKeys]; @@ -108,6 +134,10 @@ " void *context)\n", [self outname]); fprintf (output_file, "{\n"); + if (have_sType) { + fprintf (output_file, "\t((%s *) data)->sType", [self outname]); + fprintf (output_file, " = %s;\n", [self sTypeName]); + } fprintf (output_file, "\treturn PL_ParseStruct (%s_fields, item, data, messages," " context);\n", From a45f8f98b6e001dd068c1c42c8d714c128437061 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 19:55:17 +0900 Subject: [PATCH 190/435] [util] Make exprctx hashlinks double pointer The way I wound up using the field meant that exprctx should not "own" the hashlinks chain, but rather just point to it. This fixes the nasty access errors I had. --- include/QF/cexpr.h | 2 +- libs/util/cexpr-vars.c | 2 +- libs/video/renderer/vulkan/vkparse.c | 17 ++++++++--------- libs/video/renderer/vulkan/vkparse.h | 2 +- libs/video/renderer/vulkan/vulkan_vid_common.c | 9 +++++---- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index 77e5b0463..ac6eef683 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -94,7 +94,7 @@ typedef struct exprctx_s { struct memsuper_s *memsuper; const struct plitem_s *item; struct plitem_s *messages; - struct hashlink_s *hashlinks; + struct hashlink_s **hashlinks; int errors; } exprctx_t; diff --git a/libs/util/cexpr-vars.c b/libs/util/cexpr-vars.c index 6ec8ce3d9..115f0ba64 100644 --- a/libs/util/cexpr-vars.c +++ b/libs/util/cexpr-vars.c @@ -128,7 +128,7 @@ void cexpr_init_symtab (exprtab_t *symtab, exprctx_t *ctx) { exprsym_t *sym; - symtab->tab = Hash_NewTable (61, expr_getkey, 0, 0, &ctx->hashlinks); + symtab->tab = Hash_NewTable (61, expr_getkey, 0, 0, ctx->hashlinks); for (sym = symtab->symbols; sym->name; sym++) { Hash_Add (symtab->tab, sym); } diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 55192ad36..394a402d9 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -513,7 +513,7 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) exprctx.external_variables = &vars_tab; exprctx.memsuper = new_memsuper (); exprctx.messages = messages; - exprctx.hashlinks = ctx->hashlinks; + exprctx.hashlinks = &ctx->hashlinks; cexpr_init_symtab (&vars_tab, &exprctx); @@ -526,7 +526,6 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) } PL_Free (messages); delete_memsuper (exprctx.memsuper); - ctx->hashlinks = exprctx.hashlinks; renderpass = QFV_CreateRenderPass (device, renderpass_data.attachments, @@ -556,17 +555,17 @@ QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *pipelinedef) exprctx.memsuper = new_memsuper (); exprctx.messages = messages; - exprctx.hashlinks = ctx->hashlinks; + exprctx.hashlinks = &ctx->hashlinks; if (!ctx->setLayouts) { ctx->shaderModules = Hash_NewTable (23, handleref_getkey, shaderModule_free, - ctx, &exprctx.hashlinks); + ctx, &ctx->hashlinks); ctx->setLayouts = Hash_NewTable (23, handleref_getkey, setLayout_free, - ctx, &exprctx.hashlinks); + ctx, &ctx->hashlinks); ctx->pipelineLayouts = Hash_NewTable (23, handleref_getkey, pipelineLayout_free, - ctx, &exprctx.hashlinks); + ctx, &ctx->hashlinks); } for (parseres_t *res = parse_resources; res->name; res++) { @@ -586,7 +585,6 @@ QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *pipelinedef) PL_Free (messages); delete_memsuper (exprctx.memsuper); - ctx->hashlinks = exprctx.hashlinks; } static const char * @@ -597,11 +595,12 @@ enum_symtab_getkey (const void *e, void *unused) } void -QFV_InitParse (void) +QFV_InitParse (vulkan_ctx_t *ctx) { exprctx_t context = {}; enum_symtab = Hash_NewTable (61, enum_symtab_getkey, 0, 0, - &context.hashlinks); + &ctx->hashlinks); + context.hashlinks = &ctx->hashlinks; vkgen_init_symtabs (&context); } diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index e63bb44e2..e4fe36774 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -25,7 +25,7 @@ typedef struct handleref_s { VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); void QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *plist); -void QFV_InitParse (void); +void QFV_InitParse (vulkan_ctx_t *ctx); exprenum_t *QFV_GetEnum (const char *name); #endif//__vkparse_h diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index fc0a97edf..af24c78eb 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -140,7 +140,7 @@ void Vulkan_Init_Common (vulkan_ctx_t *ctx) { Sys_Printf ("Vulkan_Init_Common\n"); - QFV_InitParse (); + QFV_InitParse (ctx); Vulkan_Init_Cvars (); ctx->instance = QFV_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version } @@ -149,8 +149,9 @@ static void clear_table (hashtab_t **table) { if (*table) { - Hash_DelTable (*table); + hashtab_t *tab = *table; *table = 0; + Hash_DelTable (tab); } } @@ -166,11 +167,11 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) if (ctx->swapchain) { QFV_DestroySwapchain (ctx->swapchain); } + ctx->instance->funcs->vkDestroySurfaceKHR (ctx->instance->instance, + ctx->surface, 0); clear_table (&ctx->pipelineLayouts); clear_table (&ctx->setLayouts); clear_table (&ctx->shaderModules); - ctx->instance->funcs->vkDestroySurfaceKHR (ctx->instance->instance, - ctx->surface, 0); if (ctx->device) { QFV_DestroyDevice (ctx->device); } From b493e6ac324c7414f2fc8a902565f7da88214d7a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 23:39:52 +0900 Subject: [PATCH 191/435] [util] Expose plist type check support functions --- include/QF/qfplist.h | 5 +++++ libs/util/qfplist.c | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 20c7671bb..3f22a9e16 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -310,6 +310,11 @@ plitem_t *PL_NewString (const char *str); */ void PL_Free (plitem_t *item); +int PL_CheckType (pltype_t field_type, pltype_t item_type); +void PL_TypeMismatch (plitem_t *messages, const plitem_t *item, + const char *name, pltype_t field_type, + pltype_t item_type); + /** Parse a dictionary object into a structure. For each key in the dictionary, the corresponding field item is used to diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index c3fc5a756..273148657 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1147,8 +1147,8 @@ pl_default_parser (const plfield_t *field, const plitem_t *item, void *data, return 0; } -static int -types_match (pltype_t field_type, pltype_t item_type) +VISIBLE int +PL_CheckType (pltype_t field_type, pltype_t item_type) { if (field_type & QFMultiType) { // field_type is a mask of allowed types @@ -1159,9 +1159,9 @@ types_match (pltype_t field_type, pltype_t item_type) } } -static void -type_mismatch (plitem_t *messages, const plitem_t *item, const char *name, - pltype_t field_type, pltype_t item_type) +VISIBLE void +PL_TypeMismatch (plitem_t *messages, const plitem_t *item, const char *name, + pltype_t field_type, pltype_t item_type) { const int num_types = sizeof (pl_types) / sizeof (pl_types[0]); if (field_type & QFMultiType) { @@ -1213,9 +1213,9 @@ PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data, } else { parser = pl_default_parser; } - if (!types_match (f->type, item->type)) { - type_mismatch (messages, item, current->key, - f->type, item->type); + if (!PL_CheckType (f->type, item->type)) { + PL_TypeMismatch (messages, item, current->key, + f->type, item->type); result = 0; } else { if (!parser (f, item, flddata, messages, context)) { @@ -1268,11 +1268,11 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, plitem_t *item = plarray->values[i]; void *eledata = &arr->a[i * element->stride]; - if (!types_match (element->type, item->type)) { + if (!PL_CheckType (element->type, item->type)) { char index[16]; snprintf (index, sizeof(index) - 1, "%d", i); index[15] = 0; - type_mismatch (messages, item, index, element->type, item->type); + PL_TypeMismatch (messages, item, index, element->type, item->type); result = 0; } else { if (!parser (&f, item, eledata, messages, context)) { @@ -1320,8 +1320,8 @@ PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, const char *key = current->key; plitem_t *item = current->value; - if (!types_match (element->type, item->type)) { - type_mismatch (messages, item, key, element->type, item->type); + if (!PL_CheckType (element->type, item->type)) { + PL_TypeMismatch (messages, item, key, element->type, item->type); result = 0; continue; } From 0da99bc59ce90e1a9e59f0325151c037a3e43f43 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 23:41:13 +0900 Subject: [PATCH 192/435] [util] Add promotion from float to int to cexpr I won't go the other way nor will I add double to float. --- libs/util/cexpr-type.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index 6b02be01d..f400803cb 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -264,6 +264,13 @@ float_div_quat (const exprval_t *val1, const exprval_t *val2, *c = a * qconjf (b) / dotf (b, b); } +static void +float_cast_int (const exprval_t *val1, const exprval_t *src, exprval_t *result, + exprctx_t *ctx) +{ + *(float *) result->value = *(int *) src->value; +} + UNOP(float, pos, float, +) UNOP(float, neg, float, -) UNOP(float, tnot, float, !) @@ -278,6 +285,7 @@ binop_t float_binops[] = { { '/', &cexpr_quaternion, &cexpr_quaternion, float_div_quat }, { '%', &cexpr_float, &cexpr_float, float_rem }, { MOD, &cexpr_float, &cexpr_float, float_mod }, + { '=', &cexpr_int, &cexpr_float, float_cast_int }, {} }; From 5eb1afdcb363c6dd5d47c396bee031bdfc372a33 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 23:42:30 +0900 Subject: [PATCH 193/435] [vulkan] Implement pipeline creation The prototypes for handle parsers needed to be changes because it turned out "single" was inappropriate for handles as "single" allocates memory for the parsed object, but handles must be written directly. --- include/vid_vulkan.h | 1 + libs/video/renderer/vulkan/qfpipeline.plist | 152 +++++++------- .../renderer/vulkan/vkgen/vkfieldcustom.r | 3 +- .../video/renderer/vulkan/vkgen/vkfieldtype.h | 2 + .../video/renderer/vulkan/vkgen/vkfieldtype.r | 33 +-- libs/video/renderer/vulkan/vkgen/vkhandle.r | 15 +- libs/video/renderer/vulkan/vkparse.c | 188 ++++++++++++------ libs/video/renderer/vulkan/vkparse.h | 14 +- libs/video/renderer/vulkan/vkparse.plist | 19 +- .../video/renderer/vulkan/vulkan_vid_common.c | 9 + 10 files changed, 256 insertions(+), 180 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 74a1ef51a..d34e067fe 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -53,6 +53,7 @@ typedef struct vulkan_ctx_s { VkCommandBuffer cmdbuffer; VkFence fence; // for ctx->cmdbuffer only vulkan_renderpass_t renderpass; + VkPipeline pipeline; size_t curFrame; vulkan_framebufferset_t framebuffers; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 198604466..1f9c6de46 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -39,80 +39,88 @@ ); }; }; - pipelines = { - something = { - stages = ( - { stage = vertex; name = main; module = passthrough; }, - { stage = fragment; name = main; module = pushcolor; }, + pipeline = { + stages = ( + { stage = vertex; name = main; module = passthrough; }, + { stage = fragment; name = main; module = pushcolor; }, + ); + vertexInput = { + bindings = ( + { + binding = 0; + stride = "4 * 4"; + inputRate = vertex; + }, + ); + attributes = ( + { + location = 0; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 0; + }, ); - vertexInput = { - bindings = ( - { - binding = 0; - stride = "4 * 4"; - inputRate = vertex; - }, - ); - attributes = ( - { - location = 0; - binding = 0; - format = r32g32b32a32_sfloat; - offset = 0; - }, - ); - }; - inputAssembly = { - topology = triangle_list; - primitiveRestartEnable = 0; - }; - viewport = { - viewports = ( - { - x = 0; y = 0; - width = 640; height = 480; - minDepth = 0; maxDepth = 1000; - } - ); - scissors = ( - { - offset = { x = 0; y = 0 }; - extent = { width = 640; height = 480; }; - }, - ); - }; - rasterization = { - depthClampEnable = 1; - rasterizerDiscardEnable = 0; - polygonMode = fill; - cullMode = back; - frontFace = counter_clockwise; - depthBiasEnable = 0; - lineWidth = 1; - }; - multisample = { - rasterizationSamples = $msaaSamples; - sampleShadingEnable = 0; - minSampleShading = 0.5; - alphaToCoverageEnable = 0; - alphaToOneEnable = 0; - }; - depthStencil = { - depthTestEnable = 1; - depthWriteEnable = 1; - depthCompareOp = less; - depthBoundsTestEnable = 0; - stencilTestEnable = 0; - }; - colorBlend = { - logicOpEnable = 0; - }; - dymamic = { - dymamicState = ( viewport, scissor ); - }; - layout = something; - renderPass = renderpass; }; + inputAssembly = { + topology = triangle_list; + primitiveRestartEnable = 0; + }; + viewport = { + viewports = ( + { + x = 0; y = 0; + width = 640; height = 480; + minDepth = 0; maxDepth = 1; + } + ); + scissors = ( + { + offset = { x = 0; y = 0 }; + extent = { width = 640; height = 480; }; + }, + ); + }; + rasterization = { + depthClampEnable = 0; + rasterizerDiscardEnable = 0; + polygonMode = fill; + cullMode = back; + frontFace = counter_clockwise; + depthBiasEnable = 0; + lineWidth = 1; + }; + multisample = { + rasterizationSamples = $msaaSamples; + sampleShadingEnable = 0; + minSampleShading = 0.5f; + alphaToCoverageEnable = 0; + alphaToOneEnable = 0; + }; + depthStencil = { + depthTestEnable = 1; + depthWriteEnable = 1; + depthCompareOp = less; + depthBoundsTestEnable = 0; + stencilTestEnable = 0; + }; + colorBlend = { + logicOpEnable = 0; + attachments = ({ + blendEnable = 0; + srcColorBlendFactor = src_color; + dstColorBlendFactor = zero; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = zero; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }); + }; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = something; + //renderPass = renderpass; }; renderpass = { attachments = ( diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r index 7c7843414..611cd7a9b 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r +++ b/libs/video/renderer/vulkan/vkgen/vkfieldcustom.r @@ -2,6 +2,7 @@ #include #include "vkfieldcustom.h" +#include "vkfieldtype.h" #include "vkgen.h" #include "vktype.h" @@ -15,7 +16,7 @@ } PLItem *desc = [item getObjectForKey:"type"]; - pltype = str_hold ([[desc getObjectAtIndex:1] string]); + pltype = str_hold (parseItemType ([desc getObjectAtIndex:1])); parser = str_hold ([[desc getObjectAtIndex:2] string]); fields = [item getObjectForKey:"fields"]; diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldtype.h b/libs/video/renderer/vulkan/vkgen/vkfieldtype.h index fa27c7d8e..8e5d26bf8 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfieldtype.h +++ b/libs/video/renderer/vulkan/vkgen/vkfieldtype.h @@ -17,4 +17,6 @@ -(string)parseType; @end +string parseItemType (PLItem *item); + #endif//__renderer_vulkan_vkgen_vkfieldtype_h diff --git a/libs/video/renderer/vulkan/vkgen/vkfieldtype.r b/libs/video/renderer/vulkan/vkgen/vkfieldtype.r index cb1a04508..5f9429a20 100644 --- a/libs/video/renderer/vulkan/vkgen/vkfieldtype.r +++ b/libs/video/renderer/vulkan/vkgen/vkfieldtype.r @@ -5,6 +5,21 @@ #include "vkgen.h" #include "vktype.h" +string +parseItemType (PLItem *item) +{ + string str = [item string]; + if (str) { + return str; + } + string mask = "QFMultiType"; + for (int i = [item count]; i-- > 0; ) { + str = [[item getObjectAtIndex:i] string]; + mask = mask + " | (1 << " + str + ")"; + } + return mask; +} + @implementation FieldType +fieldType:(PLItem *)item @@ -19,21 +34,6 @@ str_free (parse_type); } -static string -parseItemType (PLItem *item) -{ - string str = [item string]; - if (str) { - return str; - } - string mask = "QFMultiType"; - for (int i = [item count]; i-- > 0; ) { - str = [[item getObjectAtIndex:i] string]; - mask = mask + " | (1 << " + str + ")"; - } - return str_hold (mask); -} - -initWithItem:(PLItem *)item { if (!(self = [super init])) { @@ -47,7 +47,8 @@ parseItemType (PLItem *item) parse_type = [field_type parseType]; parser = str_hold ("parse_" + type); } else { - parse_type = parseItemType([item getObjectForKey:"parse_type"]); + PLItem *typeItem = [item getObjectForKey:"parse_type"]; + parse_type = str_hold (parseItemType(typeItem)); type = str_hold ([[item getObjectForKey:"type"] string]); parser = str_hold ([[item getObjectForKey:"parser"] string]); } diff --git a/libs/video/renderer/vulkan/vkgen/vkhandle.r b/libs/video/renderer/vulkan/vkgen/vkhandle.r index da4a4fbcc..b76d99af4 100644 --- a/libs/video/renderer/vulkan/vkgen/vkhandle.r +++ b/libs/video/renderer/vulkan/vkgen/vkhandle.r @@ -12,10 +12,10 @@ output_handle (string name, PLItem *handle) string create = str_hold ([[handle getObjectForKey:"create"] string]); string custom = str_hold ([[handle getObjectForKey:"custom"] string]); if (!custom) { - fprintf (output_file, "static int parse_%s (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context)\n", name); + fprintf (output_file, "static int parse_%s (const plitem_t *item, void **data, plitem_t *messages, parsectx_t *context)\n", name); fprintf (output_file, "{\n"); - fprintf (output_file, "\t__auto_type handle = (%s *) data;\n", name); - fprintf (output_file, "\tvulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx;\n"); + fprintf (output_file, "\t__auto_type handle = (%s *) data[0];\n", name); + fprintf (output_file, "\tvulkan_ctx_t *ctx = context->vctx;\n"); fprintf (output_file, "\tqfv_device_t *device = ctx->device;\n"); fprintf (output_file, "\tqfv_devfuncs_t *dfunc = device->funcs;\n"); fprintf (output_file, "\tif (PL_Type (item) == QFString) {\n"); @@ -47,15 +47,18 @@ output_handle (string name, PLItem *handle) fprintf (output_file, "int parse_%s_handleref (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context)\n", name); fprintf (output_file, "{\n"); fprintf (output_file, "\thandleref_t *handleref = data;\n"); + fprintf (output_file, "\tvoid *hrdata[] = { &handleref->handle };\n"); fprintf (output_file, "\thandleref->name = strdup (field->name);\n"); if (custom) { - fprintf (output_file, "\treturn %s (field, item, &handleref->handle, messages, context);\n", custom); + fprintf (output_file, "\treturn %s (item, hrdata, messages, context);\n", custom); } else { - fprintf (output_file, "\treturn parse_%s (field, item, &handleref->handle, messages, context);\n", name); + fprintf (output_file, "\treturn parse_%s (item, hrdata, messages, context);\n", name); } fprintf (output_file, "}\n"); - fprintf (header_file, "static int parse_%s (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context);\n", name); + if (!custom) { + fprintf (header_file, "static int parse_%s (const plitem_t *item, void **data, plitem_t *messages, parsectx_t *context);\n", name); + } fprintf (header_file, "int parse_%s_handleref (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context);\n", name); str_free (custom); str_free (symtab); diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 394a402d9..45236c7ff 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -58,6 +58,7 @@ #include "QF/Vulkan/command.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/image.h" +#include "QF/Vulkan/pipeline.h" #include "QF/Vulkan/renderpass.h" #include "QF/Vulkan/shader.h" #include "QF/Vulkan/swapchain.h" @@ -159,6 +160,10 @@ parse_basic (const plfield_t *field, const plitem_t *item, *(uint32_t *) data = VK_SUBPASS_EXTERNAL; } else { ret = !cexpr_eval_string (valstr, &ectx); + if (!ret) { + PL_Message (messages, item, "error parsing %s: %s", + field->name, valstr); + } } //Sys_Printf (" %x\n", *(uint32_t *)data); @@ -224,8 +229,9 @@ parse_single (const plfield_t *field, const plitem_t *item, //Sys_Printf ("parse_single: %s %zd %d %p %p\n", field->name, field->offset, // field->type, field->parser, field->data); - if (PL_Type (item) != single->type) { - PL_Message (messages, item, "error: wrong type"); + if (!PL_CheckType (single->type, PL_Type (item))) { + PL_TypeMismatch (messages, item, field->name, single->type, + PL_Type (item)); return 0; } @@ -309,13 +315,13 @@ parse_string (const plfield_t *field, const plitem_t *item, __auto_type string = (parse_string_t *) field->data; __auto_type value = (char **) ((byte *)data + string->value_offset); - const char *str = PL_BinaryData (item); + const char *str = PL_String (item); - Sys_Printf ("parse_string: %s %zd %d %p %p %p\n", - field->name, field->offset, field->type, field->parser, - field->data, data); - Sys_Printf (" %zd\n", string->value_offset); - Sys_Printf (" %s\n", str); + //Sys_Printf ("parse_string: %s %zd %d %p %p %p\n", + // field->name, field->offset, field->type, field->parser, + // field->data, data); + //Sys_Printf (" %zd\n", string->value_offset); + //Sys_Printf (" %s\n", str); *value = strdup (str); return 1; @@ -350,11 +356,11 @@ parse_RGBA (const plitem_t *item, void **data, } static int -parse_VkShaderModule (const plfield_t *field, const plitem_t *item, void *data, - plitem_t *messages, void *context) +parse_VkShaderModule (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) { - __auto_type handle = (VkShaderModule *) data; - vulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx; + __auto_type handle = (VkShaderModule *) data[0]; + vulkan_ctx_t *ctx = context->vctx; const char *name = PL_String (item); handleref_t *hr = Hash_Find (ctx->shaderModules, name); @@ -367,10 +373,10 @@ parse_VkShaderModule (const plfield_t *field, const plitem_t *item, void *data, } static int -parse_VkShaderModule_resource (const plfield_t *field, const plitem_t *item, - void *data, plitem_t *messages, void *context) +parse_VkShaderModule_resource (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) { - __auto_type handle = (VkShaderModule *) data; + __auto_type handle = (VkShaderModule *) data[0]; vulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx; qfv_device_t *device = ctx->device; @@ -382,6 +388,15 @@ parse_VkShaderModule_resource (const plfield_t *field, const plitem_t *item, return 1; } +static int +parse_VkDescriptorSetLayout_array (const plfield_t *field, + const plitem_t *item, void *data, + plitem_t *messages, void *context) +{ + void *layout[] = { data }; + return parse_VkDescriptorSetLayout (item, layout, messages, context); +} + static const char * handleref_getkey (const void *hr, void *unused) { @@ -494,57 +509,6 @@ static plfield_t renderpass_fields[] = { {} }; -VkRenderPass -QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) -{ - qfv_device_t *device = ctx->device; - qfv_renderpass_t renderpass_data = {}; - plitem_t *messages = PL_NewArray (); - VkRenderPass renderpass; - exprsym_t var_syms[] = { - {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, - {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, - {} - }; - exprtab_t vars_tab = { var_syms, 0 }; - exprctx_t exprctx = {}; - parsectx_t parsectx = { &exprctx, ctx }; - - exprctx.external_variables = &vars_tab; - exprctx.memsuper = new_memsuper (); - exprctx.messages = messages; - exprctx.hashlinks = &ctx->hashlinks; - - cexpr_init_symtab (&vars_tab, &exprctx); - - if (!PL_ParseStruct (renderpass_fields, plist, &renderpass_data, - messages, &parsectx)) { - for (int i = 0; i < PL_A_NumObjects (messages); i++) { - Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); - } - return 0; - } - PL_Free (messages); - delete_memsuper (exprctx.memsuper); - - renderpass = QFV_CreateRenderPass (device, - renderpass_data.attachments, - renderpass_data.subpasses, - renderpass_data.dependencies); - - free (renderpass_data.attachments); - for (size_t i = 0; i < renderpass_data.subpasses->size; i++) { - free ((void *) renderpass_data.subpasses->a[i].pInputAttachments); - free ((void *) renderpass_data.subpasses->a[i].pColorAttachments); - free ((void *) renderpass_data.subpasses->a[i].pResolveAttachments); - free ((void *) renderpass_data.subpasses->a[i].pDepthStencilAttachment); - free ((void *) renderpass_data.subpasses->a[i].pPreserveAttachments); - } - free (renderpass_data.subpasses); - free (renderpass_data.dependencies); - return renderpass; -} - void QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *pipelinedef) { @@ -609,3 +573,95 @@ QFV_GetEnum (const char *name) { return Hash_Find (enum_symtab, name); } + +VkRenderPass +QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) +{ + qfv_device_t *device = ctx->device; + qfv_renderpass_t renderpass_data = {}; + plitem_t *messages = PL_NewArray (); + VkRenderPass renderpass; + exprsym_t var_syms[] = { + {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, + {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, + {} + }; + exprtab_t vars_tab = { var_syms, 0 }; + exprctx_t exprctx = {}; + parsectx_t parsectx = { &exprctx, ctx }; + + exprctx.external_variables = &vars_tab; + exprctx.memsuper = new_memsuper (); + exprctx.messages = messages; + exprctx.hashlinks = &ctx->hashlinks; + + cexpr_init_symtab (&vars_tab, &exprctx); + + if (!PL_ParseStruct (renderpass_fields, plist, &renderpass_data, + messages, &parsectx)) { + for (int i = 0; i < PL_A_NumObjects (messages); i++) { + Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); + } + return 0; + } + PL_Free (messages); + delete_memsuper (exprctx.memsuper); + + renderpass = QFV_CreateRenderPass (device, + renderpass_data.attachments, + renderpass_data.subpasses, + renderpass_data.dependencies); + + free (renderpass_data.attachments); + for (size_t i = 0; i < renderpass_data.subpasses->size; i++) { + free ((void *) renderpass_data.subpasses->a[i].pInputAttachments); + free ((void *) renderpass_data.subpasses->a[i].pColorAttachments); + free ((void *) renderpass_data.subpasses->a[i].pResolveAttachments); + free ((void *) renderpass_data.subpasses->a[i].pDepthStencilAttachment); + free ((void *) renderpass_data.subpasses->a[i].pPreserveAttachments); + } + free (renderpass_data.subpasses); + free (renderpass_data.dependencies); + return renderpass; +} + +VkPipeline +QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist) +{ + qfv_device_t *device = ctx->device; + + plitem_t *messages = PL_NewArray (); + exprctx_t exprctx = {}; + parsectx_t parsectx = { &exprctx, ctx }; + exprsym_t var_syms[] = { + {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, + {} + }; + exprtab_t vars_tab = { var_syms, 0 }; + + exprctx.external_variables = &vars_tab; + exprctx.memsuper = new_memsuper (); + exprctx.messages = messages; + exprctx.hashlinks = &ctx->hashlinks; + + cexpr_init_symtab (&vars_tab, &exprctx); + + __auto_type cInfo = QFV_AllocGraphicsPipelineCreateInfoSet (1, alloca); + memset (&cInfo->a[0], 0, sizeof (cInfo->a[0])); + + if (!parse_VkGraphicsPipelineCreateInfo (0, plist, &cInfo->a[0], + messages, &parsectx)) { + for (int i = 0; i < PL_A_NumObjects (messages); i++) { + Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); + } + return 0; + } + PL_Free (messages); + delete_memsuper (exprctx.memsuper); + + cInfo->a[0].renderPass = ctx->renderpass.renderpass; + __auto_type plSet = QFV_CreateGraphicsPipelines (device, 0, cInfo); + VkPipeline pipeline = plSet->a[0]; + free (plSet); + return pipeline; +} diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index e4fe36774..394cd296d 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -1,17 +1,17 @@ #ifndef __vkparse_h #define __vkparse_h +typedef struct parsectx_s { + struct exprctx_s *ectx; + struct vulkan_ctx_s *vctx; +} parsectx_t; + #include "QF/cexpr.h" #include "QF/Vulkan/renderpass.h" #ifdef vkparse_internal #include "libs/video/renderer/vulkan/vkparse.hinc" #endif -typedef struct parsectx_s { - struct exprctx_s *ectx; - struct vulkan_ctx_s *vctx; -} parsectx_t; - typedef struct parseres_s { const char *name; plfield_t *field; @@ -23,9 +23,11 @@ typedef struct handleref_s { uint64_t handle; } handleref_t; -VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); void QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *plist); void QFV_InitParse (vulkan_ctx_t *ctx); exprenum_t *QFV_GetEnum (const char *name); +VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); +VkPipeline QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist); + #endif//__vkparse_h diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index e270fb9be..97e767676 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -131,12 +131,8 @@ string = pName; }; module = { - type = (single, { - parse_type = QFString; - type = VkShaderModule; - parser = parse_VkShaderModule; - }); - value = module; + type = (custom, QFString, parse_VkShaderModule); + fields = (module); }; specializationInfo = { type = (single, VkSpecializationInfo); @@ -253,7 +249,7 @@ type = (array, { parse_type = (QFDictionary, QFString); type = VkDescriptorSetLayout; - parser = parse_VkDescriptorSetLayout; + parser = parse_VkDescriptorSetLayout_array; }); size = setLayoutCount; values = pSetLayouts; @@ -312,12 +308,9 @@ value = pDynamicState; }; layout = { - type = (single, { - parse_type = (QFDictionary, QFString); - type = VkPipelineLayout; - parser = parse_VkPipelineLayout; - }); - value = layout; + type = (custom, (QFDictionary, QFString), + parse_VkPipelineLayout); + fields = (layout); }; basePipelineHandle = { type = (custom, QFString, parse_BasePipeline); diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index af24c78eb..179748dfe 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -417,6 +417,15 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) void Vulkan_CreatePipelines (vulkan_ctx_t *ctx) { + qfv_load_pipeline (ctx); + + plitem_t *item = ctx->pipelineDef; + if (!item || !(item = PL_ObjectForKey (item, "pipeline"))) { + Sys_Printf ("error loading pipeline\n"); + } else { + Sys_Printf ("Found pipeline def\n"); + } + ctx->pipeline = QFV_ParsePipeline (ctx, item); } void From 3b06ca01afe61f9c2fe334f8011c9be9e82597e5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 5 Jan 2021 23:54:22 +0900 Subject: [PATCH 194/435] [vulkan] Destroy pipeline on shutdown --- include/QF/Vulkan/pipeline.h | 2 ++ libs/video/renderer/vulkan/pipeline.c | 9 +++++++++ libs/video/renderer/vulkan/vulkan_vid_common.c | 4 ++++ 3 files changed, 15 insertions(+) diff --git a/include/QF/Vulkan/pipeline.h b/include/QF/Vulkan/pipeline.h index c7d5013de..bd6e292a9 100644 --- a/include/QF/Vulkan/pipeline.h +++ b/include/QF/Vulkan/pipeline.h @@ -150,5 +150,7 @@ qfv_pipelineset_t * QFV_CreateComputePipelines (struct qfv_device_s *device, VkPipelineCache cache, qfv_computepipelinecreateinfoset_t *cpciSet); +void +QFV_DestroyPipeline (struct qfv_device_s *device, VkPipeline pipeline); #endif//__QF_Vulkan_pipeline_h diff --git a/libs/video/renderer/vulkan/pipeline.c b/libs/video/renderer/vulkan/pipeline.c index bfe48ce9f..2db39812c 100644 --- a/libs/video/renderer/vulkan/pipeline.c +++ b/libs/video/renderer/vulkan/pipeline.c @@ -153,3 +153,12 @@ QFV_CreateComputePipelines (qfv_device_t *device, pipelines->a); return pipelines; } + +void +QFV_DestroyPipeline (qfv_device_t *device, VkPipeline pipeline) +{ + VkDevice dev = device->dev; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyPipeline (dev, pipeline, 0); +} diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 179748dfe..38288c81b 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -58,6 +58,7 @@ #include "QF/Vulkan/command.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/image.h" +#include "QF/Vulkan/pipeline.h" #include "QF/Vulkan/renderpass.h" #include "QF/Vulkan/shader.h" #include "QF/Vulkan/swapchain.h" @@ -158,6 +159,9 @@ clear_table (hashtab_t **table) void Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) { + if (ctx->pipeline) { + QFV_DestroyPipeline (ctx->device, ctx->pipeline); + } if (ctx->framebuffers.size) { Vulkan_DestroyFramebuffers (ctx); } From d4277ef130af9bdc051a3cfa7edb298c33247f27 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 7 Jan 2021 01:10:25 +0900 Subject: [PATCH 195/435] [util] Mark PL_CheckType as const I keep forgetting to do optimized builds :( --- include/QF/qfplist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 3f22a9e16..8f8db669f 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -310,7 +310,7 @@ plitem_t *PL_NewString (const char *str); */ void PL_Free (plitem_t *item); -int PL_CheckType (pltype_t field_type, pltype_t item_type); +int PL_CheckType (pltype_t field_type, pltype_t item_type) __attribute__((const)); void PL_TypeMismatch (plitem_t *messages, const plitem_t *item, const char *name, pltype_t field_type, pltype_t item_type); From 90428db3d5185b2bd1fad986e82c8a82a678da88 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 7 Jan 2021 22:47:58 +0900 Subject: [PATCH 196/435] [glsl] Remove stray return statement I have no idea why that was in that patch and certainly does not seem to be correct. --- libs/video/renderer/glsl/glsl_bsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index 767000b12..acdaf22c6 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -360,7 +360,7 @@ static void update_lightmap (msurface_t *surf) { int maps; -return; + for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) if (d_lightstylevalue[surf->styles[maps]] != surf->cached_light[maps]) goto dynamic; From b6d2c630591e1d21725bab9f72cc0d296585b233 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 7 Jan 2021 22:49:43 +0900 Subject: [PATCH 197/435] [vulkan] Fix some formtatting Both code and developer output. --- libs/video/renderer/vid_render_vulkan.c | 4 +--- libs/video/renderer/vulkan/renderpass.c | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 52246162b..a2ab54024 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -124,9 +124,7 @@ vulkan_SCR_UpdateScreen (double time, void (*f)(void), void (**g)(void)) = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, - 1, - &framebuffer->imageAvailableSemaphore, - &waitStage, + 1, &framebuffer->imageAvailableSemaphore, &waitStage, 1, &framebuffer->cmdBuffer, 1, &framebuffer->renderDoneSemaphore, }; diff --git a/libs/video/renderer/vulkan/renderpass.c b/libs/video/renderer/vulkan/renderpass.c index 78cc46563..65134ffd7 100644 --- a/libs/video/renderer/vulkan/renderpass.c +++ b/libs/video/renderer/vulkan/renderpass.c @@ -74,6 +74,7 @@ QFV_CreateRenderPass (qfv_device_t *device, if (developer->int_val & SYS_VULKAN) { Sys_Printf ("attachments: %ld\n", attachments->size); for (size_t i = 0; i < attachments->size; i++) { + Sys_Printf (" attachment: %zd\n", i); Sys_Printf (" flags: %x\n", attachments->a[i].flags); Sys_Printf (" format: %d\n", attachments->a[i].format); Sys_Printf (" samples: %x\n", attachments->a[i].samples); From 5aa74df922fbc56117954aaafa02d5312a667a6d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 8 Jan 2021 14:37:52 +0900 Subject: [PATCH 198/435] [renderer] Add a default 8x8 font It is not compatible with the quake charset (it's the IBM charset). The data is a simple bitmap but a converter to quake pic format is provided. --- include/r_local.h | 5 + libs/video/renderer/Makemodule.am | 1 + libs/video/renderer/font8x8.c | 336 ++++++++++++++++++++++++++++++ 3 files changed, 342 insertions(+) create mode 100644 libs/video/renderer/font8x8.c diff --git a/include/r_local.h b/include/r_local.h index 189d38d38..ebf1a9dd6 100644 --- a/include/r_local.h +++ b/include/r_local.h @@ -346,7 +346,12 @@ extern byte crosshair_data[]; #define CROSSHAIR_TILEY 2 #define CROSSHAIR_COUNT (CROSSHAIR_TILEX * CROSSHAIR_TILEY) +//NOTE: This is packed 8x8 bitmap data, one byte per scanline, 8 scanlines +////per character. Also, it is NOT the quake font, but the IBM charset. +extern byte font8x8_data[]; + struct qpic_s *Draw_CrosshairPic (void); +struct qpic_s *Draw_Font8x8Pic (void); struct tex_s *R_DotParticleTexture (void); struct tex_s *R_SparkParticleTexture (void); diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index b5ca83cf5..990d17d88 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -13,6 +13,7 @@ EXTRA_LTLIBRARIES += \ video_renderer_common_sources = \ libs/video/renderer/crosshair.c \ + libs/video/renderer/font8x8.c \ libs/video/renderer/noisetextures.c \ libs/video/renderer/r_alias.c \ libs/video/renderer/r_bsp.c \ diff --git a/libs/video/renderer/font8x8.c b/libs/video/renderer/font8x8.c new file mode 100644 index 000000000..ab78882a5 --- /dev/null +++ b/libs/video/renderer/font8x8.c @@ -0,0 +1,336 @@ +/* + r_font8x8.c + + 8x8 bitmap font data. + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/1/8 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "QF/qtypes.h" +#include "QF/wadfile.h" + +#include "r_internal.h" + +//NOTE: This is packed 8x8 bitmap data, one byte per scanline, 8 scanlines +//per character. Also, it is NOT the quake font, but the IBM charset. +byte font8x8_data[] = { + 0xff, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xff, + 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E, + 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, + 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, + 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x92, 0x10, 0x7C, + 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C, + 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, + 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, + 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, + 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, + 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78, + 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, + 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, + 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, + 0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, + 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, + 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, + 0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0x86, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, + 0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, + 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, + 0x18, 0x7E, 0xC0, 0x7C, 0x06, 0xFC, 0x18, 0x00, + 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, + 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, + 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, + 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, + 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, + 0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xC6, 0x7C, 0x00, + 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, + 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00, + 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00, + 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, + 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00, + 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, + 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, + 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, + 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, + 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x7C, 0xC6, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, + 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, + 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, + 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, + 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3A, 0x00, + 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, + 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, + 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, + 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, + 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, + 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, + 0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0x7C, 0x0E, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, + 0x7C, 0xC6, 0xE0, 0x78, 0x0E, 0xC6, 0x7C, 0x00, + 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, + 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, + 0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, 0x00, + 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00, + 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, + 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, + 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, + 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0x38, 0x6C, 0x64, 0xF0, 0x60, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, + 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, + 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, + 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xD6, 0x00, + 0x00, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, + 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, + 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, + 0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0xF0, 0x00, + 0x00, 0x00, 0x7C, 0xC0, 0x70, 0x1C, 0xF8, 0x00, + 0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, + 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, + 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, + 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00, + 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00, + 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x0C, 0x06, 0x7C, + 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0x7E, 0x81, 0x3C, 0x06, 0x3E, 0x66, 0x3B, 0x00, + 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0x78, 0x0C, 0x38, + 0x7E, 0x81, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, + 0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, + 0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x7C, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xC6, 0x10, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, + 0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00, + 0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00, + 0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00, + 0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00, + 0x78, 0x84, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x78, 0x84, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00, + 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, + 0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18, + 0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00, + 0xCC, 0xCC, 0x78, 0x30, 0xFC, 0x30, 0xFC, 0x30, + 0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC3, + 0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70, + 0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0xF8, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0x00, + 0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00, + 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00, + 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00, + 0x18, 0x00, 0x18, 0x18, 0x30, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00, + 0xC6, 0xCC, 0xD8, 0x36, 0x6B, 0xC2, 0x84, 0x0F, + 0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6D, 0xCF, 0x03, + 0x18, 0x00, 0x18, 0x18, 0x3C, 0x3C, 0x18, 0x00, + 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, + 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, + 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, + 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0xDB, 0xF6, 0xDB, 0x6F, 0xDB, 0x7E, 0xD7, 0xED, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00, + 0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xCC, 0xF8, 0xC0, + 0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, + 0x00, 0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, + 0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00, + 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0, + 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00, + 0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC, + 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00, + 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00, + 0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00, + 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00, + 0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0, + 0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00, + 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, + 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, + 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x7E, 0x00, + 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00, + 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00, + 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70, + 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00, + 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C, + 0x58, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, + 0x70, 0x98, 0x30, 0x60, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, + 0xff, 0x99, 0x99, 0xff, 0xff, 0x99, 0x99, 0xff, +}; +#define FONT_WIDTH 8 +#define FONT_HEIGHT 8 +#define FONT_HCHARS 16 +#define FONT_VCHARS 16 +#define FONT_BYTES ((FONT_VCHARS)*(FONT_HCHARS)*(FONT_HEIGHT)*(FONT_WIDTH)) + +qpic_t * +Draw_Font8x8Pic (void) +{ + qpic_t *pic; + byte *data; + byte *out; + int i, j, x, y, ind; + + pic = calloc (1, field_offset (qpic_t, data[FONT_BYTES])); + pic->width = FONT_HCHARS * FONT_WIDTH; + pic->height = FONT_VCHARS * FONT_HEIGHT; + // convert the bitmap data to pixel data in a 16x16 character "image" + // assumes the quake palette where 254 is white, and 255 is transparent + data = font8x8_data; + for (j = 0; j < FONT_VCHARS; j++) { + for (i = 0; i < FONT_HCHARS; i++) { + for (y = 0; y < FONT_HEIGHT; y++) { + byte scanline = *data++; + ind = (j * FONT_HEIGHT + y) * FONT_WIDTH * FONT_HCHARS; + ind += i * FONT_WIDTH; + out = pic->data + ind; + for (x = 0; x < FONT_WIDTH; x++) { + *out++ = 0xff - ((scanline & 0x80) >> 7); + scanline <<= 1; + } + } + } + } + return pic; +} From 06d45cff0d23b0a0de9c89ad001f56fc2e335e3c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 9 Jan 2021 11:36:19 +0900 Subject: [PATCH 199/435] [build] Keep error messages from glslangValidator The tool is horrible as a built tool due to it not being silent when all is good (it outputs the input file name) and sends its error messages to stdout instead of stderr. Then filtering causes the error code to be lost. This uses a solution found on stack-exchange. --- Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index b59b21eb7..c869a6f3a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,11 +119,11 @@ V_XXD_1 = %.spv: % @$(mkdir_p) $(builddir)/`dirname $@` - $(V_GLSLANG)$(GLSLANGVALIDATOR) -V $< -o $@ > /dev/null + $(V_GLSLANG)(((($(GLSLANGVALIDATOR) -V $< -o $@; echo $$? >&3) | sed -e '1d' 1>&2) 3>&1) | (read xs; exit $$xs)) %.spvc: % @$(mkdir_p) $(builddir)/`dirname $@` - $(V_GLSLANG)$(GLSLANGVALIDATOR) --vn `basename $< | tr . _` -V $< -o $@ > /dev/null + $(V_GLSLANG)(((($(GLSLANGVALIDATOR) --vn `basename $< | tr . _` -V $< -o $@; echo $$? >&3) | sed -e '1d' 1>&2) 3>&1) | (read xs; exit $$xs)) shaderdir = @shaderdir@ shader_DATA = From 0c1699fdbb76da34d6463e631c94f34392430895 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 9 Jan 2021 20:42:23 +0900 Subject: [PATCH 200/435] Fix a pile of double semicolons --- libs/ruamoko/rua_set.c | 2 +- libs/util/cmem.c | 2 +- libs/util/qendian.c | 4 ++-- libs/video/renderer/gl/gl_mod_alias.c | 2 +- libs/video/renderer/glsl/glsl_textures.c | 2 +- libs/video/renderer/r_efrag.c | 2 +- libs/video/renderer/vulkan/swapchain.c | 2 +- qtv/source/sv_parse.c | 2 +- tools/bsp2img/bsp2img.c | 4 ++-- tools/qfcc/include/dags.h | 2 +- tools/qfcc/source/class.c | 2 +- tools/qfcc/source/dags.c | 2 +- tools/qfcc/source/qfcc.c | 2 +- tools/qfcc/test/old/linkdef2.r | 2 +- tools/qflight/source/entities.c | 2 +- 15 files changed, 17 insertions(+), 17 deletions(-) diff --git a/libs/ruamoko/rua_set.c b/libs/ruamoko/rua_set.c index 4e3ea732d..3bc36c06b 100644 --- a/libs/ruamoko/rua_set.c +++ b/libs/ruamoko/rua_set.c @@ -392,7 +392,7 @@ bi_set_first (progs_t *pr) res->set_iters->prev = &set_iter->next; res->set_iters = set_iter; - set_iter->iter = iter;; + set_iter->iter = iter; R_INT (pr) = res_set_iter_index (res, set_iter); } diff --git a/libs/util/cmem.c b/libs/util/cmem.c index 9dc461b87..1879f7ea3 100644 --- a/libs/util/cmem.c +++ b/libs/util/cmem.c @@ -321,7 +321,7 @@ cmemalloc (memsuper_t *super, size_t size) memblock_t *block = init_block (super, mem, super->page_size); line = block->free_lines; } - return alloc_line (line, size);; + return alloc_line (line, size); } else { void *mem = 0; memsline_t **sline = &super->last_freed[ind]; diff --git a/libs/util/qendian.c b/libs/util/qendian.c index 12873af9f..9858823be 100644 --- a/libs/util/qendian.c +++ b/libs/util/qendian.c @@ -41,9 +41,9 @@ */ #ifndef WORDS_BIGENDIAN -VISIBLE qboolean bigendien = false;; +VISIBLE qboolean bigendien = false; #else -VISIBLE qboolean bigendien = true;; +VISIBLE qboolean bigendien = true; #endif diff --git a/libs/video/renderer/gl/gl_mod_alias.c b/libs/video/renderer/gl/gl_mod_alias.c index c74e1815c..44a114ff5 100644 --- a/libs/video/renderer/gl/gl_mod_alias.c +++ b/libs/video/renderer/gl/gl_mod_alias.c @@ -190,7 +190,7 @@ GL_DrawAliasFrameMulti (vert_order_t *vo) static void GL_DrawAliasShadowTri (const aliashdr_t *paliashdr, const vert_order_t *vo) { - int count = vo->count;; + int count = vo->count; const blended_vert_t *verts = vo->verts; float height, lheight; vec3_t point; diff --git a/libs/video/renderer/glsl/glsl_textures.c b/libs/video/renderer/glsl/glsl_textures.c index 62b331662..4e6303093 100644 --- a/libs/video/renderer/glsl/glsl_textures.c +++ b/libs/video/renderer/glsl/glsl_textures.c @@ -519,7 +519,7 @@ GLSL_SubpicUpdate (subpic_t *subpic, byte *data, int batch) void GLSL_ScrapFlush (scrap_t *scrap) { - vrect_t *rect = scrap->batch;; + vrect_t *rect = scrap->batch; if (!rect) return; diff --git a/libs/video/renderer/r_efrag.c b/libs/video/renderer/r_efrag.c index 74592fa30..870c01fc1 100644 --- a/libs/video/renderer/r_efrag.c +++ b/libs/video/renderer/r_efrag.c @@ -89,7 +89,7 @@ R_ClearEfrags (void) if (!efrag_list) efrag_list = calloc (1, sizeof (t_efrag_list)); - r_free_efrags = efrag_list->efrags;; + r_free_efrags = efrag_list->efrags; for (efl = efrag_list; efl; efl = efl->next) { init_efrag_list (efl); if (efl->next) diff --git a/libs/video/renderer/vulkan/swapchain.c b/libs/video/renderer/vulkan/swapchain.c index b2007953a..478700e83 100644 --- a/libs/video/renderer/vulkan/swapchain.c +++ b/libs/video/renderer/vulkan/swapchain.c @@ -43,7 +43,7 @@ QFV_CreateSwapchain (vulkan_ctx_t *ctx, VkSwapchainKHR old_swapchain) uint32_t numModes; VkPresentModeKHR *modes; - VkPresentModeKHR useMode = VK_PRESENT_MODE_FIFO_KHR;; + VkPresentModeKHR useMode = VK_PRESENT_MODE_FIFO_KHR; ifuncs->vkGetPhysicalDeviceSurfacePresentModesKHR (physDev, ctx->surface, &numModes, 0); diff --git a/qtv/source/sv_parse.c b/qtv/source/sv_parse.c index c179d125e..1b6ca5841 100644 --- a/qtv/source/sv_parse.c +++ b/qtv/source/sv_parse.c @@ -531,7 +531,7 @@ parse_player_delta (qmsg_t *msg, plent_state_t *from, plent_state_t *to) if (flags & PF_SKINNUM) to->skinnum = MSG_ReadByte (msg); if (flags & PF_EFFECTS) - to->effects = (to->effects & 0xff00) | MSG_ReadByte (msg);; + to->effects = (to->effects & 0xff00) | MSG_ReadByte (msg); if (flags & PF_WEAPONFRAME) to->weaponframe = MSG_ReadByte (msg); if (flags & PF_QF) { diff --git a/tools/bsp2img/bsp2img.c b/tools/bsp2img/bsp2img.c index 649fe1427..7b95c35a6 100644 --- a/tools/bsp2img/bsp2img.c +++ b/tools/bsp2img/bsp2img.c @@ -672,14 +672,14 @@ render_map (bsp_t *bsp) vertexlist[i].X = -vertexlist[i].X; tempf = vertexlist[i].Z; vertexlist[i].Z = vertexlist[i].Y; - vertexlist[i].Y = tempf;; + vertexlist[i].Y = tempf; break; case 2: /* +Y -- (-x <--> +x; +y out of screen, +z up) */ tempf = vertexlist[i].Z; vertexlist[i].Z = -vertexlist[i].Y; - vertexlist[i].Y = tempf;; + vertexlist[i].Y = tempf; break; case -3: /* -Z -- negate X and Z (ie. 180 rotate diff --git a/tools/qfcc/include/dags.h b/tools/qfcc/include/dags.h index 534e58511..2c677a972 100644 --- a/tools/qfcc/include/dags.h +++ b/tools/qfcc/include/dags.h @@ -89,7 +89,7 @@ typedef struct dag_s { int num_topo; ///< number of nodes in topo (may be < ///< num_nodes after dead node removal) daglabel_t **labels; ///< array of all daglabels in this dag - int num_labels;; + int num_labels; struct set_s *roots; ///< set of root nodes struct flownode_s *flownode;///< flow node this dag represents } dag_t; diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 52a3e194a..9203e9fbf 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -1563,7 +1563,7 @@ class_finish_module (void) save_storage = current_storage; current_storage = sc_static; current_func = begin_function (init_sym, 0, current_symtab, 1); - build_code_function (init_sym, 0, init_expr);; + build_code_function (init_sym, 0, init_expr); current_func = 0; current_storage = save_storage; } diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index 8dec15fa2..1d98df411 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -500,7 +500,7 @@ static int dag_def_kill_aliases_visit (def_t *def, void *_l) { daglabel_t *l = (daglabel_t *) _l; - dagnode_t *node = l->dagnode;; + dagnode_t *node = l->dagnode; daglabel_t *label; if (def == l->op->o.def) diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 96c26e4b0..e6c3b7946 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -189,7 +189,7 @@ InitData (void) pr.entity_data = defspace_new (ds_virtual); pr.entity_fields = new_symtab (0, stab_global); - pr.entity_fields->space = pr.entity_data;; + pr.entity_fields->space = pr.entity_data; clear_functions (); clear_frame_macros (); diff --git a/tools/qfcc/test/old/linkdef2.r b/tools/qfcc/test/old/linkdef2.r index 133235f69..20a72fa3a 100644 --- a/tools/qfcc/test/old/linkdef2.r +++ b/tools/qfcc/test/old/linkdef2.r @@ -5,5 +5,5 @@ id obj; integer foo (void) { [obj message]; - return bar () + baz ();; + return bar () + baz (); } diff --git a/tools/qflight/source/entities.c b/tools/qflight/source/entities.c index c9d262356..d2bd2711c 100644 --- a/tools/qflight/source/entities.c +++ b/tools/qflight/source/entities.c @@ -183,7 +183,7 @@ LoadEntities (void) // start parsing num_entities = PL_A_NumObjects (entity_list); - entities = malloc (num_entities * sizeof (entity_t));; + entities = malloc (num_entities * sizeof (entity_t)); // go through all the entities for (i = 0; i < num_entities; i++) { From 16334158bded47847201bcf6b6a6f6f26838ea87 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 10 Jan 2021 01:35:39 +0900 Subject: [PATCH 201/435] [util] Support struct pointer accesses in cexpr --- include/QF/cexpr.h | 3 +++ libs/util/cexpr-vars.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index ac6eef683..53fc159e7 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -113,6 +113,8 @@ void cexpr_error(exprctx_t *ctx, const char *fmt, ...) __attribute__((format(pri void cexpr_struct_getfield (const exprval_t *a, const exprval_t *b, exprval_t *c, exprctx_t *ctx); +void cexpr_struct_pointer_getfield (const exprval_t *a, const exprval_t *b, + exprval_t *c, exprctx_t *ctx); exprval_t *cexpr_cvar (const char *name, exprctx_t *ctx); exprval_t *cexpr_cvar_struct (exprctx_t *ctx); @@ -132,5 +134,6 @@ extern exprtype_t cexpr_field; extern exprtype_t cexpr_function; extern binop_t cexpr_struct_binops[]; +extern binop_t cexpr_struct_pointer_binops[]; #endif diff --git a/libs/util/cexpr-vars.c b/libs/util/cexpr-vars.c index 115f0ba64..04c6871ad 100644 --- a/libs/util/cexpr-vars.c +++ b/libs/util/cexpr-vars.c @@ -58,6 +58,20 @@ VISIBLE binop_t cexpr_struct_binops[] = { {} }; +VISIBLE void +cexpr_struct_pointer_getfield (const exprval_t *a, const exprval_t *b, + exprval_t *c, exprctx_t *ctx) +{ + // "dereference" the pointer + exprval_t struct_val = { a->type, *(void **) a->value }; + cexpr_struct_getfield (&struct_val, b, c, ctx); +} + +VISIBLE binop_t cexpr_struct_pointer_binops[] = { + { '.', &cexpr_field, &cexpr_exprval, cexpr_struct_pointer_getfield }, + {} +}; + static void cvar_get (const exprval_t *a, const exprval_t *b, exprval_t *c, exprctx_t *ctx) { From e281b608e1bc3dbf972a2fa2d2022c2c39dc7a35 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 10 Jan 2021 01:38:31 +0900 Subject: [PATCH 202/435] [vulkan] Provide access to swapchain image count This necessitated hand-writing qfv_swapchain_t's descriptors as I don't feel like getting that complicated with vkgen at this stage and it's not really appropriate anyway? qfv_swapchain_t is meant to be read-only and not parsed from a plist. --- libs/video/renderer/vulkan/vkparse.c | 32 ++++++++++++++++++++++++ libs/video/renderer/vulkan/vkparse.plist | 5 ---- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 45236c7ff..b74d9af7d 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -469,6 +469,36 @@ parse_BasePipeline (const plitem_t *item, void **data, #include "libs/video/renderer/vulkan/vkparse.cinc" +static exprsym_t imageset_symbols[] = { + {"size", &cexpr_size_t, (void *)field_offset (qfv_imageset_t, size)}, + { } +}; +static exprtab_t imageset_symtab = { + imageset_symbols, +}; +exprtype_t imageset_type = { + "imageset", + sizeof (qfv_imageset_t *), + cexpr_struct_pointer_binops, + 0, + &imageset_symtab, +}; +static exprsym_t qfv_swapchain_t_symbols[] = { + {"format", &VkFormat_type, (void *)field_offset (qfv_swapchain_t, format)}, + {"images", &imageset_type, (void *)field_offset (qfv_swapchain_t, images)}, + { } +}; +static exprtab_t qfv_swapchain_t_symtab = { + qfv_swapchain_t_symbols, +}; +exprtype_t qfv_swapchain_t_type = { + "qfv_swapchain_t", + sizeof (qfv_swapchain_t), + cexpr_struct_binops, + 0, + &qfv_swapchain_t_symtab, +}; + typedef struct qfv_renderpass_s { qfv_attachmentdescription_t *attachments; qfv_subpassparametersset_t *subpasses; @@ -566,6 +596,8 @@ QFV_InitParse (vulkan_ctx_t *ctx) &ctx->hashlinks); context.hashlinks = &ctx->hashlinks; vkgen_init_symtabs (&context); + cexpr_init_symtab (&qfv_swapchain_t_symtab, &context); + cexpr_init_symtab (&imageset_symtab, &context); } exprenum_t * diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index 97e767676..f6c92e110 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -18,7 +18,6 @@ VkPushConstantRange, VkPipelineLayoutCreateInfo, VkGraphicsPipelineCreateInfo, - qfv_swapchain_t, ); handles = { VkShaderModule = { @@ -61,10 +60,6 @@ }, ); parse = { - qfv_swapchain_s = { - .name = qfv_swapchain_t; - format = auto; - }; VkSubpassDescription = { flags = auto; pipelineBindPoint = auto; From 01b9c9bf7870c42e1f49ccaf29462965e89bb3b5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 10 Jan 2021 01:53:15 +0900 Subject: [PATCH 203/435] [vulkan] Parse descriptor pools --- include/vid_vulkan.h | 1 + libs/video/renderer/vulkan/vkparse.c | 18 ++++++++++++++++++ libs/video/renderer/vulkan/vkparse.plist | 15 +++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index d34e067fe..6aff7ea32 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -48,6 +48,7 @@ typedef struct vulkan_ctx_s { struct hashtab_s *shaderModules; struct hashtab_s *setLayouts; struct hashtab_s *pipelineLayouts; + struct hashtab_s *descriptorPools; VkCommandPool cmdpool; VkCommandBuffer cmdbuffer; diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index b74d9af7d..d7060d237 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -456,6 +456,21 @@ pipelineLayout_free (void *hr, void *_ctx) handleref_free (handleref, ctx); } +static void +descriptorPool_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type pool = (VkDescriptorPool) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (pool) { + dfunc->vkDestroyDescriptorPool (device->dev, pool, 0); + }; + handleref_free (handleref, ctx); +} + static hashtab_t *enum_symtab; static int @@ -560,6 +575,9 @@ QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *pipelinedef) ctx->pipelineLayouts = Hash_NewTable (23, handleref_getkey, pipelineLayout_free, ctx, &ctx->hashlinks); + ctx->descriptorPools = Hash_NewTable (23, handleref_getkey, + descriptorPool_free, + ctx, &ctx->hashlinks); } for (parseres_t *res = parse_resources; res->name; res++) { diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index f6c92e110..fc406b4c4 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -18,6 +18,7 @@ VkPushConstantRange, VkPipelineLayoutCreateInfo, VkGraphicsPipelineCreateInfo, + VkDescriptorPoolCreateInfo, ); handles = { VkShaderModule = { @@ -25,6 +26,11 @@ class = "shader module"; custom = parse_VkShaderModule_resource; }; + VkDescriptorPool = { + symtab = descriptorPools; + class = "descriptor pool"; + create = vkCreateDescriptorPool; + }; VkDescriptorSetLayout = { symtab = setLayouts; class = "set layout"; @@ -150,6 +156,15 @@ values = pBindings; }; }; + VkDescriptorPoolCreateInfo = { + flags = auto; + maxSets = auto; + bindings = { + type = (array, VkDescriptorPoolSize); + size = poolSizeCount; + values = pPoolSizes; + }; + }; VkPipelineVertexInputStateCreateInfo = { //flags = auto; reserved for future use (Bits enum does not exist) bindings = { From a35eec387792384a07f2bd94272576c1b684df21 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 10 Jan 2021 15:02:24 +0900 Subject: [PATCH 204/435] [util] Fail gracefully when no symtab is present --- libs/util/cexpr-lex.l | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/util/cexpr-lex.l b/libs/util/cexpr-lex.l index 2cbbdaa79..9c9377beb 100644 --- a/libs/util/cexpr-lex.l +++ b/libs/util/cexpr-lex.l @@ -258,6 +258,9 @@ parse_name (const char *name, exprctx_t *context) { exprtab_t *symtab = context->symtab; + if (!symtab) { + return 0; + } __auto_type sym = (exprsym_t *) Hash_Find (symtab->tab, name); return sym; } From e7106cce9eacad81cac5b1d42da1aa256188431e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 10 Jan 2021 15:22:39 +0900 Subject: [PATCH 205/435] [plugin] Remove Draw_Init from draw funcs It's never called outside the renderers. --- include/QF/plugin/vid_render.h | 1 - libs/video/renderer/vid_render_gl.c | 1 - libs/video/renderer/vid_render_glsl.c | 1 - libs/video/renderer/vid_render_sw.c | 1 - libs/video/renderer/vid_render_sw32.c | 1 - libs/video/renderer/vid_render_vulkan.c | 1 - 6 files changed, 6 deletions(-) diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index bdec285d1..6de6e9af7 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -108,7 +108,6 @@ typedef struct vid_model_funcs_s { } vid_model_funcs_t; typedef struct vid_render_funcs_s { - void (*Draw_Init) (void); void (*Draw_Character) (int x, int y, unsigned ch); void (*Draw_String) (int x, int y, const char *str); void (*Draw_nString) (int x, int y, const char *str, int count); diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 9085e751d..434588894 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -72,7 +72,6 @@ static vid_model_funcs_t model_funcs = { }; vid_render_funcs_t gl_vid_render_funcs = { - gl_Draw_Init, gl_Draw_Character, gl_Draw_String, gl_Draw_nString, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 22de04ea3..f8ca47174 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -72,7 +72,6 @@ static vid_model_funcs_t model_funcs = { }; vid_render_funcs_t glsl_vid_render_funcs = { - glsl_Draw_Init, glsl_Draw_Character, glsl_Draw_String, glsl_Draw_nString, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index dcfb4abc7..a418d200c 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -65,7 +65,6 @@ static vid_model_funcs_t model_funcs = { }; vid_render_funcs_t sw_vid_render_funcs = { - Draw_Init, Draw_Character, Draw_String, Draw_nString, diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index ed7414a85..9fffb0298 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -70,7 +70,6 @@ static vid_model_funcs_t model_funcs = { }; vid_render_funcs_t sw32_vid_render_funcs = { - sw32_Draw_Init, sw32_Draw_Character, sw32_Draw_String, sw32_Draw_nString, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index a2ab54024..a4299d827 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -194,7 +194,6 @@ static vid_model_funcs_t model_funcs = { }; vid_render_funcs_t vulkan_vid_render_funcs = { - 0,//vulkan_Draw_Init, 0,//vulkan_Draw_Character, 0,//vulkan_Draw_String, 0,//vulkan_Draw_nString, From ef817a5cbf51dabc0e501944b6960e4c38f91c2c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 10 Jan 2021 15:26:09 +0900 Subject: [PATCH 206/435] [vulkan] Allow images to be created initialized Needed for loaded textures. --- include/QF/Vulkan/image.h | 3 ++- libs/video/renderer/vulkan/image.c | 8 +++++--- libs/video/renderer/vulkan/vulkan_vid_common.c | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index edb5e025e..dc6bc5eea 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -37,7 +37,8 @@ VkImage QFV_CreateImage (struct qfv_device_s *device, int cubemap, uint32_t num_mipmaps, uint32_t num_layers, VkSampleCountFlagBits samples, - VkImageUsageFlags usage_scenarios); + VkImageUsageFlags usage_scenarios, + int initialized); VkDeviceMemory QFV_AllocImageMemory (struct qfv_device_s *device, VkImage image, diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index 68decb94a..a60435a9d 100644 --- a/libs/video/renderer/vulkan/image.c +++ b/libs/video/renderer/vulkan/image.c @@ -69,7 +69,8 @@ QFV_CreateImage (qfv_device_t *device, int cubemap, uint32_t num_mipmaps, uint32_t num_layers, VkSampleCountFlagBits samples, - VkImageUsageFlags usage_scenarios) + VkImageUsageFlags usage_scenarios, + int initialized) { VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; @@ -79,11 +80,12 @@ QFV_CreateImage (qfv_device_t *device, int cubemap, type, format, size, num_mipmaps, cubemap ? 6 * num_layers : num_layers, samples, - VK_IMAGE_TILING_OPTIMAL, + initialized ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL, usage_scenarios, VK_SHARING_MODE_EXCLUSIVE, 0, 0, - VK_IMAGE_LAYOUT_UNDEFINED, + initialized ? VK_IMAGE_LAYOUT_PREINITIALIZED + : VK_IMAGE_LAYOUT_UNDEFINED, }; VkImage image; dfunc->vkCreateImage (dev, &createInfo, 0, &image); diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 38288c81b..8d0aa4870 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -319,7 +319,7 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, sc->format, extent, 1, 1, ctx->msaaSamples, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT - | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0); colorImage->object = QFV_AllocImageMemory (device, colorImage->image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); @@ -336,7 +336,7 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) depthImage->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, depthFormat, extent, 1, 1, ctx->msaaSamples, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0); depthImage->object = QFV_AllocImageMemory (device, depthImage->image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); From fd07169a80607f4be4e030ee154c776ea8727c41 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 10 Jan 2021 15:27:39 +0900 Subject: [PATCH 207/435] [util] Support casts from int/uint to size_t I don't want to do implicit down casts (size_t to uint) but I needed to be able to reference swapchain array size. --- libs/util/cexpr-type.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index f400803cb..57c7a945b 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -31,6 +31,7 @@ #include "QF/cexpr.h" #include "QF/mathlib.h" +#include "QF/qfplist.h" #include "QF/simd/vec4f.h" #include "libs/util/cexpr-parse.h" @@ -181,6 +182,26 @@ BINOP(size_t, bor, unsigned, |) BINOP(size_t, xor, unsigned, ^) BINOP(size_t, rem, unsigned, %) +static void +size_t_cast_int (const exprval_t *val1, const exprval_t *src, + exprval_t *result, exprctx_t *ctx) +{ + int val = *(int *) src->value; + if (val < 0) { + PL_Message (ctx->messages, ctx->item, "int value clamped to 0: %d", + val); + val = 0; + } + *(size_t *) result->value = val; +} + +static void +size_t_cast_uint (const exprval_t *val1, const exprval_t *src, + exprval_t *result, exprctx_t *ctx) +{ + *(size_t *) result->value = *(unsigned *) src->value; +} + UNOP(size_t, pos, unsigned, +) UNOP(size_t, neg, unsigned, -) UNOP(size_t, tnot, unsigned, !) @@ -198,6 +219,8 @@ binop_t size_t_binops[] = { { '^', &cexpr_size_t, &cexpr_size_t, size_t_xor }, { '%', &cexpr_size_t, &cexpr_size_t, size_t_rem }, { MOD, &cexpr_size_t, &cexpr_size_t, size_t_rem }, + { '=', &cexpr_int, &cexpr_size_t, size_t_cast_int }, + { '=', &cexpr_uint, &cexpr_size_t, size_t_cast_uint }, {} }; From b40b3cff1c32d8c1bbdd69f4f8629f019c864215 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 10 Jan 2021 15:29:47 +0900 Subject: [PATCH 208/435] [vulkan] Use a size_t temp to parse uint32 values Needed for swapbuffer frame count --- libs/video/renderer/vulkan/vkparse.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index d7060d237..fbba8238b 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -175,8 +175,9 @@ parse_uint32_t (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context) { int ret = 1; + size_t val = 0; exprctx_t ectx = *((parsectx_t *) context)->ectx; - exprval_t result = { &cexpr_uint, data }; + exprval_t result = { &cexpr_size_t, &val }; ectx.symtab = 0; ectx.result = &result; const char *valstr = PL_String (item); @@ -191,6 +192,11 @@ parse_uint32_t (const plfield_t *field, const plitem_t *item, // field->name, field->offset, field->type, field->parser, // field->data, valstr); ret = !cexpr_eval_string (valstr, &ectx); + if (!ret) { + PL_Message (messages, item, "error parsing %s: %s", + field->name, valstr); + } + *(uint32_t *) data = val; //Sys_Printf (" %d\n", *(uint32_t *)data); } From fed7149508c887d0d3abffe68099b009b71a6360 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 10 Jan 2021 15:50:24 +0900 Subject: [PATCH 209/435] [vulkan] Parse sampler definitions --- libs/video/renderer/vulkan/vkparse.c | 49 ++++++++++++++----- libs/video/renderer/vulkan/vkparse.h | 1 + libs/video/renderer/vulkan/vkparse.plist | 20 ++++++++ .../video/renderer/vulkan/vulkan_vid_common.c | 2 + 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index fbba8238b..cd5e98502 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -477,6 +477,21 @@ descriptorPool_free (void *hr, void *_ctx) handleref_free (handleref, ctx); } +static void +sampler_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type sampler = (VkSampler) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (sampler) { + dfunc->vkDestroySampler (device->dev, sampler, 0); + }; + handleref_free (handleref, ctx); +} + static hashtab_t *enum_symtab; static int @@ -560,10 +575,23 @@ static plfield_t renderpass_fields[] = { {} }; +static hashtab_t * +handlref_symtab (void (*free_func)(void*,void*), vulkan_ctx_t *ctx) +{ + return Hash_NewTable (23, handleref_getkey, free_func, + ctx, &ctx->hashlinks); +} + void QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *pipelinedef) { plitem_t *messages = PL_NewArray (); + exprsym_t var_syms[] = { + {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, + {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, + {} + }; + exprtab_t vars_tab = { var_syms, 0 }; exprctx_t exprctx = {}; parsectx_t parsectx = { &exprctx, ctx }; int ret = 1; @@ -571,19 +599,15 @@ QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *pipelinedef) exprctx.memsuper = new_memsuper (); exprctx.messages = messages; exprctx.hashlinks = &ctx->hashlinks; + exprctx.external_variables = &vars_tab; + cexpr_init_symtab (&vars_tab, &exprctx); if (!ctx->setLayouts) { - ctx->shaderModules = Hash_NewTable (23, handleref_getkey, - shaderModule_free, - ctx, &ctx->hashlinks); - ctx->setLayouts = Hash_NewTable (23, handleref_getkey, setLayout_free, - ctx, &ctx->hashlinks); - ctx->pipelineLayouts = Hash_NewTable (23, handleref_getkey, - pipelineLayout_free, - ctx, &ctx->hashlinks); - ctx->descriptorPools = Hash_NewTable (23, handleref_getkey, - descriptorPool_free, - ctx, &ctx->hashlinks); + ctx->shaderModules = handlref_symtab (shaderModule_free, ctx); + ctx->setLayouts = handlref_symtab (setLayout_free, ctx); + ctx->pipelineLayouts = handlref_symtab (pipelineLayout_free, ctx); + ctx->descriptorPools = handlref_symtab (descriptorPool_free, ctx); + ctx->samplers = handlref_symtab (sampler_free, ctx); } for (parseres_t *res = parse_resources; res->name; res++) { @@ -646,11 +670,10 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) exprctx_t exprctx = {}; parsectx_t parsectx = { &exprctx, ctx }; - exprctx.external_variables = &vars_tab; exprctx.memsuper = new_memsuper (); exprctx.messages = messages; exprctx.hashlinks = &ctx->hashlinks; - + exprctx.external_variables = &vars_tab; cexpr_init_symtab (&vars_tab, &exprctx); if (!PL_ParseStruct (renderpass_fields, plist, &renderpass_data, diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index 394cd296d..75dd8fe9d 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -7,6 +7,7 @@ typedef struct parsectx_s { } parsectx_t; #include "QF/cexpr.h" +#include "QF/qfplist.h" #include "QF/Vulkan/renderpass.h" #ifdef vkparse_internal #include "libs/video/renderer/vulkan/vkparse.hinc" diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index fc406b4c4..edf68541e 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -19,6 +19,7 @@ VkPipelineLayoutCreateInfo, VkGraphicsPipelineCreateInfo, VkDescriptorPoolCreateInfo, + VkSamplerCreateInfo, ); handles = { VkShaderModule = { @@ -41,6 +42,11 @@ class = "pipeline layout"; create = vkCreatePipelineLayout; }; + VkSampler = { + symtab = samplers; + class = "sampler"; + create = vkCreateSampler; + }; }; resources = ( { @@ -64,6 +70,20 @@ type = handleref_t; table = pipelineLayouts; }, + { + name = descriptorPools; + parse_type = QFDictionary; + parser = parse_VkDescriptorPool_handleref; + type = handleref_t; + table = descriptorPools; + }, + { + name = samplers; + parse_type = QFDictionary; + parser = parse_VkSampler_handleref; + type = handleref_t; + table = samplers; + }, ); parse = { VkSubpassDescription = { diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 8d0aa4870..3f701e27a 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -176,6 +176,8 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) clear_table (&ctx->pipelineLayouts); clear_table (&ctx->setLayouts); clear_table (&ctx->shaderModules); + clear_table (&ctx->descriptorPools); + clear_table (&ctx->samplers); if (ctx->device) { QFV_DestroyDevice (ctx->device); } From ba6450d0b4630abca73d6b0a9dd46140495aad92 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 10 Jan 2021 15:52:27 +0900 Subject: [PATCH 210/435] [vulkan] Make a start on the 2D pipeline Short wrappers for Draw functins are in vid_render_vulkan.c so the vulkan context can be passed on to the actual functions. The 2D shaders are set up similar to those in glsl, but with full 32-bit color (rgba) support instead of paletted. However, the textures are not loaded yet, nor is anything bound. --- include/QF/Vulkan/draw.h | 237 ++++++++++++++++++ include/QF/Vulkan/qf_draw.h | 52 +++- include/QF/Vulkan/qf_vid.h | 2 +- include/vid_vulkan.h | 3 + libs/video/renderer/Makemodule.am | 12 +- libs/video/renderer/vid_render_vulkan.c | 154 ++++++++++-- libs/video/renderer/vulkan/device.c | 3 +- libs/video/renderer/vulkan/qfpipeline.plist | 224 +++++++++++------ libs/video/renderer/vulkan/shader.c | 6 + libs/video/renderer/vulkan/twod.frag | 19 ++ libs/video/renderer/vulkan/twod.vert | 27 ++ libs/video/renderer/vulkan/vulkan_draw.c | 142 ++++++++--- .../video/renderer/vulkan/vulkan_vid_common.c | 19 +- 13 files changed, 742 insertions(+), 158 deletions(-) create mode 100644 include/QF/Vulkan/draw.h create mode 100644 libs/video/renderer/vulkan/twod.frag create mode 100644 libs/video/renderer/vulkan/twod.vert diff --git a/include/QF/Vulkan/draw.h b/include/QF/Vulkan/draw.h new file mode 100644 index 000000000..8f6b78889 --- /dev/null +++ b/include/QF/Vulkan/draw.h @@ -0,0 +1,237 @@ +/* + draw.h + + Video buffer handling definitions and prototypes + + Copyright (C) 1996-1997 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_draw_h +#define __QF_draw_h + +/** \defgroup video Video Sub-sytem */ + +/** \defgroup video_renderer Renderer Sub-system + \ingroup video +*/ + +/** \defgroup video_renderer_draw Generic draw functions + \ingroup video_renderer +*/ +///@{ + +#include "QF/wad.h" + +extern byte *draw_chars; + +/** Initialize the draw stuff. +*/ +void Draw_Init (void); + +/** Draws one 8*8 graphics character with 0 being transparent. + It can be clipped to the top of the screen to allow the console to be + smoothly scrolled off. + \param x horizontal location of the top left corner of the character. + \param y vertical location of the top left corner of the character. + \param ch 8 bit character to draw. + \note The character drawn is from the quake character set, which is + (by default) standard ascii for 0x20-0x7e (white). 0xa0-0xfe is + also standard ascii (brown). 0x01-0x1f and 0x80-0x9f are + various drawing characters, and 0x7f is a backwards arrow. +*/ +void Draw_Character (int x, int y, unsigned ch); + +/** Draws a character string to the screen. + No line wrapping is performed. + \param x horizontal location of the top left corner of the character. + \param y vertical location of the top left corner of the character. + \param str 8 bit character string to draw. + \note See Draw_Character() for character set description. + String is normal nul terminated C string. +*/ +void Draw_String (int x, int y, const char *str); + +/** Draws a character sub-string to the screen. + No line wrapping is performed. + \param x horizontal location of the top left corner of the character. + \param y vertical location of the top left corner of the character. + \param str 8 bit character string to draw. + \param count Maximum characters of the string to draw. + \note See Draw_Character() for character set description. + Draws up to \p count characters, or stops at the first nul + character. +*/ +void Draw_nString (int x, int y, const char *str, int count); + +/** Draws a character string to the screen. + No line wrapping is performed. + \param x horizontal location of the top left corner of the character. + \param y vertical location of the top left corner of the character. + \param str 8 bit character string to draw. + \note See Draw_Character() for character set description. + String is normal nul terminated C string. + Characters of the string are forced to have their high bit set + (ie, they will be in the range 0x80-0xff). +*/ +void Draw_AltString (int x, int y, const char *str); + +/** Draw the console background with various optional effects. + \param lines Vertical size in pixels of the console. + \param alpha Console transparency level (255 = opaque). + \note \p alpha is effective only in the OpenGL renderer. Effectively + 255 (opaque) for the software renderer. + + \c gl_conspin causes the background to spin. + + \c gl_constretch causes the background to stretch rather than slide. +*/ +void Draw_ConsoleBackground (int lines, byte alpha); + +/** Draw a crosshair at the center of the screen. + \c crosshair specifies which crosshair (1 = '+', 2 = large 'x' shape, + 3 = fancy '+' shape) + \c cl_crossx and \c cl_crossy offset the crosshair from the center of the + screen. +*/ +void Draw_Crosshair (void); + +/** Draw the specified crosshair on the screen. + \param ch crosshair to draw + \param x horizontal position of the center of the crosshair. + \param y vertical position of the center of the crosshair. + + See Draw_Crosshair() for description of crosshair values. +*/ +void Draw_CrosshairAt (int ch, int x, int y); + +/** Clear a rectangle with a tiled background. + \param x horizontal position of the upper left corner of the rectangle + \param y horizontal position of the upper left corner of the rectangle + \param w width of the rectangle + \param h height of the rectangle + + The background used is the "backtile" WAD lump. +*/ +void Draw_TileClear (int x, int y, int w, int h); + +/** Clear a rectangle with a solid color. + \param x horizontal position of the upper left corner of the rectangle + \param y horizontal position of the upper left corner of the rectangle + \param w width of the rectangle + \param h height of the rectangle + \param c 8 bit color index. + + The color comes from the quake palette. +*/ +void Draw_Fill (int x, int y, int w, int h, int c); + +/** Draw a text box on the screen + \param x horizontal location of the upper left corner of the box + \param y vertical location of the upper left corner of the box + \param width horizontal size in character cells of the region + \param lines vertical size in character cells of the region + \param alpha transparency of the box +*/ +void Draw_TextBox (int x, int y, int width, int lines, byte alpha); + +/** Darken the screen. +*/ +void Draw_FadeScreen (void); + +/** Shift the screen colors. +*/ +void Draw_BlendScreen (quat_t color); +///@} + +/** \defgroup video_renderer_draw_qpic QPic functions + \ingroup video_renderer_draw +*/ +///@{ +/** Load a qpic from the filesystem. + \param path path of the file within the quake filesystem + \param alpha transparency level of the pic. + \return pointer qpic data. + \note Up to MAX_CACHED_PICS qpics can be loaded at a time this way +*/ +qpic_t *Draw_CachePic (const char *path, qboolean alpha); + +/** Remove a qpic from the qpic cache. + + This affects only those qpics that were loaded via Draw_CachePic. + + \param path path of the file within the quake filesystem +*/ +void Draw_UncachePic (const char *path); + +/** Create a qpic from raw data. + + \param width The width of the pic. + \param height The height of the pic. + \param data The raw data bytes. The system palette will be used for + colors. + \return pointer qpic data. +*/ +qpic_t *Draw_MakePic (int width, int height, const byte *data); + +/** Destroy a qpic created by Draw_MakePic. + + \param pic The qpic to destory. +*/ +void Draw_DestroyPic (qpic_t *pic); + +/** Load a qpic from gfx.wad. + \param name name of the was lump to load + \return pointer qpic data. +*/ +qpic_t *Draw_PicFromWad (const char *name); + +/** Draw a qpic to the screen + \param x horizontal location of the upper left corner of the qpic + \param y vertical location of the upper left corner of the qpic + \param pic qpic to draw +*/ +void Draw_Pic (int x, int y, qpic_t *pic); + +/** Draw a qpic to the screen + \param x horizontal location of the upper left corner of the qpic + \param y vertical location of the upper left corner of the qpic + \param pic qpic to draw +*/ +void Draw_Picf (float x, float y, qpic_t *pic); + +/** Draw a sub-region of a qpic to the screan + \param x horizontal screen location of the upper left corner of the + sub-region + \param y vertical screen location of the upper left corner of the + sub-region + \param pic qpic to draw + \param srcx horizontal qpic location of the upper left corner of the + sub-region + \param srcy vertical qpic location of the upper left corner of the + sub-region + \param width horizontal size of the sub-region to be drawn + \param height vertical size of the sub-region to be drawn +*/ +void Draw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height); +///@} + +#endif//__QF_draw_h diff --git a/include/QF/Vulkan/qf_draw.h b/include/QF/Vulkan/qf_draw.h index e4716f7ed..b0297c2d0 100644 --- a/include/QF/Vulkan/qf_draw.h +++ b/include/QF/Vulkan/qf_draw.h @@ -25,13 +25,49 @@ */ -#ifndef __gl_draw_h -#define __gl_draw_h +#ifndef __QF_Vulkan_qf_draw_h +#define __QF_Vulkan_qf_draw_h -void Vulkan_Set2D (void); -void Vulkan_Set2DScaled (void); -void Vulkan_End2D (void); -void Vulkan_DrawReset (void); -void Vulkan_FlushText (void); +struct vulkan_ctx_s; -#endif//__gl_draw_h +void Vulkan_Draw_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Character (int x, int y, unsigned ch, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_String (int x, int y, const char *str, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_nString (int x, int y, const char *str, int count, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_AltString (int x, int y, const char *str, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_ConsoleBackground (int lines, byte alpha, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Crosshair (struct vulkan_ctx_s *ctx); +void Vulkan_Draw_CrosshairAt (int ch, int x, int y, struct vulkan_ctx_s *ctx); +void Vulkan_Draw_TileClear (int x, int y, int w, int h, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Fill (int x, int y, int w, int h, int c, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_FadeScreen (struct vulkan_ctx_s *ctx); +void Vulkan_Draw_BlendScreen (quat_t color, struct vulkan_ctx_s *ctx); +qpic_t *Vulkan_Draw_CachePic (const char *path, qboolean alpha, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_UncachePic (const char *path, struct vulkan_ctx_s *ctx); +qpic_t *Vulkan_Draw_MakePic (int width, int height, const byte *data, + struct vulkan_ctx_s *ctx); +void Vulkan_Draw_DestroyPic (qpic_t *pic, struct vulkan_ctx_s *ctx); +qpic_t *Vulkan_Draw_PicFromWad (const char *name, struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Pic (int x, int y, qpic_t *pic, struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Picf (float x, float y, qpic_t *pic, struct vulkan_ctx_s *ctx); +void Vulkan_Draw_SubPic(int x, int y, qpic_t *pic, + int srcx, int srcy, int width, int height, + struct vulkan_ctx_s *ctx); + +void Vulkan_Set2D (struct vulkan_ctx_s *ctx); +void Vulkan_Set2DScaled (struct vulkan_ctx_s *ctx); +void Vulkan_End2D (struct vulkan_ctx_s *ctx); +void Vulkan_DrawReset (struct vulkan_ctx_s *ctx); +void Vulkan_FlushText (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_draw_h diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index d380d1236..f859d93f2 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -40,7 +40,7 @@ void Vulkan_DestroyFramebuffers (struct vulkan_ctx_s *ctx); void Vulkan_CreateFramebuffers (struct vulkan_ctx_s *ctx); void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx); void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx); -void Vulkan_CreatePipelines (struct vulkan_ctx_s *ctx); +VkPipeline Vulkan_CreatePipeline (struct vulkan_ctx_s *ctx, const char *name); void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx); void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx); void Vulkan_Init_Common (struct vulkan_ctx_s *ctx); diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 6aff7ea32..0bc8d629d 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -20,6 +20,8 @@ typedef struct vulkan_framebuffer_s { VkSemaphore imageAvailableSemaphore; VkSemaphore renderDoneSemaphore; VkCommandBuffer cmdBuffer; + + VkDescriptorSet twodDescriptors; } vulkan_framebuffer_t; typedef struct vulkan_framebufferset_s @@ -49,6 +51,7 @@ typedef struct vulkan_ctx_s { struct hashtab_s *setLayouts; struct hashtab_s *pipelineLayouts; struct hashtab_s *descriptorPools; + struct hashtab_s *samplers; VkCommandPool cmdpool; VkCommandBuffer cmdbuffer; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 990d17d88..1d6c5eaea 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -213,7 +213,7 @@ libs_video_renderer_vid_render_vulkan_la_LDFLAGS= $(plugin_ldflags) libs_video_renderer_vid_render_vulkan_la_LIBADD= $(vulkan_libs) libs_video_renderer_vid_render_vulkan_la_DEPENDENCIES=$(vulkan_libs) libs_video_renderer_vid_render_vulkan_la_SOURCES = \ - $(common_sources) \ + $(video_renderer_common_sources) \ libs/video/renderer/vid_render_vulkan.c \ libs/video/renderer/vulkan/buffer.c \ libs/video/renderer/vulkan/command.c \ @@ -249,16 +249,26 @@ vkparse_src = \ vkparse_plist = \ $(srcdir)/libs/video/renderer/vulkan/vkparse.plist +twodv_src = libs/video/renderer/vulkan/twod.vert +twodv_c = libs/video/renderer/vulkan/twod.vert.spvc +twodf_src = libs/video/renderer/vulkan/twod.frag +twodf_c = libs/video/renderer/vulkan/twod.frag.spvc passthrough_src = libs/video/renderer/vulkan/passthrough.vert passthrough_c = libs/video/renderer/vulkan/passthrough.vert.spvc pushcolor_src = libs/video/renderer/vulkan/pushcolor.frag pushcolor_c = libs/video/renderer/vulkan/pushcolor.frag.spvc +$(twodv_c): $(twodv_src) + +$(twodf_c): $(twodf_src) + $(passthrough_c): $(passthrough_src) $(pushcolor_c): $(pushcolor_src) vkshader_c = \ + $(twodv_c) \ + $(twodf_c) \ $(passthrough_c) \ $(pushcolor_c) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index a4299d827..f84f9eb84 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -39,6 +39,7 @@ #include "QF/plugin/general.h" #include "QF/plugin/vid_render.h" +#include "QF/Vulkan/qf_draw.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" @@ -66,7 +67,8 @@ vulkan_R_Init (void) Vulkan_CreateFramebuffers (vulkan_ctx); // FIXME this should be staged so screen updates can begin while pipelines // are being built - Vulkan_CreatePipelines (vulkan_ctx); + vulkan_ctx->pipeline = Vulkan_CreatePipeline (vulkan_ctx, "pipeline"); + Vulkan_Draw_Init (vulkan_ctx); qfv_swapchain_t *sc = vulkan_ctx->swapchain; @@ -81,7 +83,7 @@ vulkan_R_Init (void) VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 0, vulkan_ctx->renderpass.renderpass, 0, { {0, 0}, sc->extent }, - 2, clearValues + 2, clearValues + 2 }; for (size_t i = 0; i < vulkan_ctx->framebuffers.size; i++) { __auto_type framebuffer = &vulkan_ctx->framebuffers.a[i]; @@ -153,18 +155,124 @@ vulkan_SCR_UpdateScreen (double time, void (*f)(void), void (**g)(void)) } } +static void +vulkan_Draw_Character (int x, int y, unsigned ch) +{ + Vulkan_Draw_Character (x, y, ch, vulkan_ctx); +} + +static void +vulkan_Draw_String (int x, int y, const char *str) +{ + Vulkan_Draw_String (x, y, str, vulkan_ctx); +} + +static void +vulkan_Draw_nString (int x, int y, const char *str, int count) +{ + Vulkan_Draw_nString (x, y, str, count, vulkan_ctx); +} + +static void +vulkan_Draw_AltString (int x, int y, const char *str) +{ + Vulkan_Draw_AltString (x, y, str, vulkan_ctx); +} + +static void +vulkan_Draw_ConsoleBackground (int lines, byte alpha) +{ + Vulkan_Draw_ConsoleBackground (lines, alpha, vulkan_ctx); +} + +static void +vulkan_Draw_Crosshair (void) +{ + Vulkan_Draw_Crosshair (vulkan_ctx); +} + +static void +vulkan_Draw_CrosshairAt (int ch, int x, int y) +{ + Vulkan_Draw_CrosshairAt (ch, x, y, vulkan_ctx); +} + +static void +vulkan_Draw_TileClear (int x, int y, int w, int h) +{ + Vulkan_Draw_TileClear (x, y, w, h, vulkan_ctx); +} + +static void +vulkan_Draw_Fill (int x, int y, int w, int h, int c) +{ + Vulkan_Draw_Fill (x, y, w, h, c, vulkan_ctx); +} + +static void +vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha) +{ + Vulkan_Draw_TextBox (x, y, width, lines, alpha, vulkan_ctx); +} + +static void +vulkan_Draw_FadeScreen (void) +{ + Vulkan_Draw_FadeScreen (vulkan_ctx); +} + +static void +vulkan_Draw_BlendScreen (quat_t color) +{ + Vulkan_Draw_BlendScreen (color, vulkan_ctx); +} + static qpic_t * vulkan_Draw_CachePic (const char *path, qboolean alpha) { - return 0; + return Vulkan_Draw_CachePic (path, alpha, vulkan_ctx); } -static qpic_t qpic = { 1, 1, {0} }; +static void +vulkan_Draw_UncachePic (const char *path) +{ + Vulkan_Draw_UncachePic (path, vulkan_ctx); +} static qpic_t * vulkan_Draw_MakePic (int width, int height, const byte *data) { - return &qpic; + return Vulkan_Draw_MakePic (width, height, data, vulkan_ctx); +} + +static void +vulkan_Draw_DestroyPic (qpic_t *pic) +{ + Vulkan_Draw_DestroyPic (pic, vulkan_ctx); +} + +static qpic_t * +vulkan_Draw_PicFromWad (const char *name) +{ + return Vulkan_Draw_PicFromWad (name, vulkan_ctx); +} + +static void +vulkan_Draw_Pic (int x, int y, qpic_t *pic) +{ + Vulkan_Draw_Pic (x, y, pic, vulkan_ctx); +} + +static void +vulkan_Draw_Picf (float x, float y, qpic_t *pic) +{ + Vulkan_Draw_Picf (x, y, pic, vulkan_ctx); +} + +static void +vulkan_Draw_SubPic (int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height) +{ + Vulkan_Draw_SubPic (x, y, pic, srcx, srcy, width, height, vulkan_ctx); } static vid_model_funcs_t model_funcs = { @@ -194,26 +302,26 @@ static vid_model_funcs_t model_funcs = { }; vid_render_funcs_t vulkan_vid_render_funcs = { - 0,//vulkan_Draw_Character, - 0,//vulkan_Draw_String, - 0,//vulkan_Draw_nString, - 0,//vulkan_Draw_AltString, - 0,//vulkan_Draw_ConsoleBackground, - 0,//vulkan_Draw_Crosshair, - 0,//vulkan_Draw_CrosshairAt, - 0,//vulkan_Draw_TileClear, - 0,//vulkan_Draw_Fill, - 0,//vulkan_Draw_TextBox, - 0,//vulkan_Draw_FadeScreen, - 0,//vulkan_Draw_BlendScreen, + vulkan_Draw_Character, + vulkan_Draw_String, + vulkan_Draw_nString, + vulkan_Draw_AltString, + vulkan_Draw_ConsoleBackground, + vulkan_Draw_Crosshair, + vulkan_Draw_CrosshairAt, + vulkan_Draw_TileClear, + vulkan_Draw_Fill, + vulkan_Draw_TextBox, + vulkan_Draw_FadeScreen, + vulkan_Draw_BlendScreen, vulkan_Draw_CachePic, - 0,//vulkan_Draw_UncachePic, + vulkan_Draw_UncachePic, vulkan_Draw_MakePic, - 0,//vulkan_Draw_DestroyPic, - 0,//vulkan_Draw_PicFromWad, - 0,//vulkan_Draw_Pic, - 0,//vulkan_Draw_Picf, - 0,//vulkan_Draw_SubPic, + vulkan_Draw_DestroyPic, + vulkan_Draw_PicFromWad, + vulkan_Draw_Pic, + vulkan_Draw_Picf, + vulkan_Draw_SubPic, vulkan_SCR_UpdateScreen, SCR_DrawRam, diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index 0457d0570..86ba71f73 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -165,7 +165,7 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0, family, 1, &priority }; - VkPhysicalDeviceFeatures features; + VkPhysicalDeviceFeatures features = {}; VkDeviceCreateInfo dCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0, 1, &qCreateInfo, @@ -173,7 +173,6 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) next, ext, &features }; - memset (&features, 0, sizeof (features)); qfv_device_t *device = calloc (1, sizeof (qfv_device_t) + sizeof (qfv_devfuncs_t)); device->funcs = (qfv_devfuncs_t *) (device + 1); diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 1f9c6de46..03a4243b2 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -7,8 +7,61 @@ // $builtin refers to compiled-in shaders passthrough = $builtin/passthrough.vert; pushcolor = $builtin/pushcolor.frag; + twodv = $builtin/twod.vert; + twodf = $builtin/twod.frag; + }; + samplers = { + quakepic = { + magFilter = nearest; + minFilter = nearest; + mipmapMode = nearest; + addressModeU = clamp_to_edge; + addressModeV = clamp_to_edge; + addressModeW = clamp_to_edge; + mipLodBias = 0; + anisotropyEnable = 0;//FIXME false!!! + maxAnisotropy = 0; + compareEnable = 0;//FIXME false!!! + compareOp = always; + minLod = 0; + maxLod = 0.25f; + borderColor = float_transparent_black; + unnormalizedCoordinates = 0;//FIXME false!!! + }; + }; + descriptorPools = { + twod = { + flags = 0; + maxSets = $swapchain.images.size; + bindings = ( + { + type = uniform_buffer; + descriptorCount = $swapchain.images.size; + }, + { + type = combined_image_sampler; + descriptorCount = $swapchain.images.size; + }, + ); + }; }; setLayouts = { + twod = { + bindings = ( + { + binding = 0; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = vertex; + }, + { + binding = 1; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; something = { flags = 0; bindings = ( @@ -28,6 +81,9 @@ }; }; pipelineLayouts = { + twod = { + setLayouts = (twod); + }; something = { setLayouts = (something); pushConstantRanges = ( @@ -39,88 +95,96 @@ ); }; }; - pipeline = { - stages = ( - { stage = vertex; name = main; module = passthrough; }, - { stage = fragment; name = main; module = pushcolor; }, - ); - vertexInput = { - bindings = ( - { - binding = 0; - stride = "4 * 4"; - inputRate = vertex; - }, - ); - attributes = ( - { - location = 0; - binding = 0; - format = r32g32b32a32_sfloat; - offset = 0; - }, + pipelines = { + twod = { + stages = ( + { stage = vertex; name = main; module = twodv; }, + { stage = fragment; name = main; module = twodf; }, ); + vertexInput = { + bindings = ( + { + binding = 0; + stride = "2 * 4 * 4"; + inputRate = vertex; + }, + ); + attributes = ( + { + location = 0; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 0; + }, + { + location = 1; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 4; + }, + ); + }; + inputAssembly = { + topology = triangle_list; + primitiveRestartEnable = 0; + }; + viewport = { + viewports = ( + { + x = 0; y = 0; + width = 640; height = 480; + minDepth = 0; maxDepth = 1; + } + ); + scissors = ( + { + offset = { x = 0; y = 0 }; + extent = { width = 640; height = 480; }; + }, + ); + }; + rasterization = { + depthClampEnable = 0; + rasterizerDiscardEnable = 0; + polygonMode = fill; + cullMode = back; + frontFace = counter_clockwise; + depthBiasEnable = 0; + lineWidth = 1; + }; + multisample = { + rasterizationSamples = $msaaSamples; + sampleShadingEnable = 0; + minSampleShading = 0.5f; + alphaToCoverageEnable = 0; + alphaToOneEnable = 0; + }; + depthStencil = { + depthTestEnable = 1; + depthWriteEnable = 1; + depthCompareOp = less; + depthBoundsTestEnable = 0; + stencilTestEnable = 0; + }; + colorBlend = { + logicOpEnable = 0; + attachments = ({ + blendEnable = 0; + srcColorBlendFactor = src_color; + dstColorBlendFactor = zero; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = zero; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }); + }; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = twod; + //renderPass = renderpass; }; - inputAssembly = { - topology = triangle_list; - primitiveRestartEnable = 0; - }; - viewport = { - viewports = ( - { - x = 0; y = 0; - width = 640; height = 480; - minDepth = 0; maxDepth = 1; - } - ); - scissors = ( - { - offset = { x = 0; y = 0 }; - extent = { width = 640; height = 480; }; - }, - ); - }; - rasterization = { - depthClampEnable = 0; - rasterizerDiscardEnable = 0; - polygonMode = fill; - cullMode = back; - frontFace = counter_clockwise; - depthBiasEnable = 0; - lineWidth = 1; - }; - multisample = { - rasterizationSamples = $msaaSamples; - sampleShadingEnable = 0; - minSampleShading = 0.5f; - alphaToCoverageEnable = 0; - alphaToOneEnable = 0; - }; - depthStencil = { - depthTestEnable = 1; - depthWriteEnable = 1; - depthCompareOp = less; - depthBoundsTestEnable = 0; - stencilTestEnable = 0; - }; - colorBlend = { - logicOpEnable = 0; - attachments = ({ - blendEnable = 0; - srcColorBlendFactor = src_color; - dstColorBlendFactor = zero; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = zero; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }); - }; - dynamic = { - dynamicState = ( viewport, scissor ); - }; - layout = something; - //renderPass = renderpass; }; renderpass = { attachments = ( diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index f0064bb35..25e1049ea 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -54,6 +54,10 @@ #include "vid_vulkan.h" +static +#include "libs/video/renderer/vulkan/twod.vert.spvc" +static +#include "libs/video/renderer/vulkan/twod.frag.spvc" static #include "libs/video/renderer/vulkan/passthrough.vert.spvc" static @@ -66,6 +70,8 @@ typedef struct shaderdata_s { } shaderdata_t; static shaderdata_t builtin_shaders[] = { + { "twod.vert", twod_vert, sizeof (twod_vert) }, + { "twod.frag", twod_frag, sizeof (twod_frag) }, { "passthrough.vert", passthrough_vert, sizeof (passthrough_vert) }, { "pushcolor.frag", pushcolor_frag, sizeof (pushcolor_frag) }, {} diff --git a/libs/video/renderer/vulkan/twod.frag b/libs/video/renderer/vulkan/twod.frag new file mode 100644 index 000000000..83bda0874 --- /dev/null +++ b/libs/video/renderer/vulkan/twod.frag @@ -0,0 +1,19 @@ +#version 450 + +layout (set = 0, binding = 1) uniform sampler2D Texture; + +layout (location = 0) in vec2 st; +layout (location = 1) in vec4 color; + +layout (location = 0) out vec4 frag_color; + +void +main (void) +{ + vec4 pix; + + pix = texture (Texture, st); + if (pix.a < 0.5) + discard; + frag_color = pix * color; +} diff --git a/libs/video/renderer/vulkan/twod.vert b/libs/video/renderer/vulkan/twod.vert new file mode 100644 index 000000000..83655d6a7 --- /dev/null +++ b/libs/video/renderer/vulkan/twod.vert @@ -0,0 +1,27 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Model; +}; +/** Vertex position. + + x, y, s, t + + \a vertex provides the onscreen location at which to draw the icon + (\a x, \a y) and texture coordinate for the icon (\a s=z, \a t=w). +*/ +layout (location = 0) in vec4 vertex; +layout (location = 1) in vec4 vcolor; + +layout (location = 0) out vec2 st; +layout (location = 1) out vec4 color; + +void +main (void) +{ + gl_Position = Projection * vec4 (vertex.xy, 0.0, 1.0); + st = vertex.zw; + color = vcolor; +} diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 628306044..7f5e11111 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -3,10 +3,10 @@ 2D drawing support for Vulkan - Copyright (C) 2011 Bill Currie + Copyright (C) 2021 Bill Currie Author: Bill Currie - Date: 2011/12/23 + Date: 2021/1/10 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -49,10 +49,24 @@ #include "QF/sys.h" #include "QF/vid.h" +#include "compat.h" #include "QF/Vulkan/qf_draw.h" #include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" #include "r_internal.h" +#include "vid_vulkan.h" +#include "vkparse.h" + +//FIXME move into a context struct +VkImage conchars_image; +VkDeviceMemory conchars_memory; +VkImageView conchars_view; +VkSampler conchars_sampler; + +VkPipeline twod; static qpic_t * pic_data (const char *name, int w, int h, const byte *data) @@ -67,135 +81,189 @@ pic_data (const char *name, int w, int h, const byte *data) } qpic_t * -vulkan_Draw_MakePic (int width, int height, const byte *data) +Vulkan_Draw_MakePic (int width, int height, const byte *data, + vulkan_ctx_t *ctx) { return pic_data (0, width, height, data); } void -vulkan_Draw_DestroyPic (qpic_t *pic) +Vulkan_Draw_DestroyPic (qpic_t *pic, vulkan_ctx_t *ctx) { } qpic_t * -vulkan_Draw_PicFromWad (const char *name) +Vulkan_Draw_PicFromWad (const char *name, vulkan_ctx_t *ctx) { return pic_data (0, 1, 1, (const byte *)""); } qpic_t * -vulkan_Draw_CachePic (const char *path, qboolean alpha) +Vulkan_Draw_CachePic (const char *path, qboolean alpha, vulkan_ctx_t *ctx) { return pic_data (0, 1, 1, (const byte *)""); } void -vulkan_Draw_UncachePic (const char *path) +Vulkan_Draw_UncachePic (const char *path, vulkan_ctx_t *ctx) { } void -vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha) +Vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha, + vulkan_ctx_t *ctx) +{ +} + +static void +Vulkan_Draw_Shutdown (void *data) +{ + vulkan_ctx_t *ctx = data; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyPipeline (device->dev, twod, 0); + dfunc->vkDestroyImageView (device->dev, conchars_view, 0); + dfunc->vkFreeMemory (device->dev, conchars_memory, 0); + dfunc->vkDestroyImage (device->dev, conchars_image, 0); +} + +void +Vulkan_Draw_Init (vulkan_ctx_t *ctx) +{ + Sys_RegisterShutdown (Vulkan_Draw_Shutdown, ctx); + + qfv_device_t *device = ctx->device; + qpic_t *charspic = Draw_Font8x8Pic (); + VkExtent3D extent = { charspic->width, charspic->height, 1 }; + conchars_image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, + VK_FORMAT_A8B8G8R8_UNORM_PACK32, + extent, 1, 1, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_TRANSFER_SRC_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT, + 1); + conchars_memory = QFV_AllocImageMemory (device, conchars_image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, 0); + QFV_BindImageMemory (device, conchars_image, conchars_memory, 0); + conchars_view = QFV_CreateImageView (device, conchars_image, + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_A8B8G8R8_UNORM_PACK32, + VK_IMAGE_ASPECT_COLOR_BIT); + conchars_sampler = Hash_Find (ctx->samplers, "quakepic"); + + twod = Vulkan_CreatePipeline (ctx, "twod"); + + handleref_t *h; + __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (ctx->framebuffers.size, alloca); + for (size_t i = 0; i < layouts->size; i++) { + h = Hash_Find (ctx->setLayouts, "twod"); + layouts->a[i] = (VkDescriptorSetLayout) h->handle; + } + h = Hash_Find (ctx->descriptorPools, "twod"); + __auto_type pool = (VkDescriptorPool) h->handle; + __auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); + for (size_t i = 0; i < ctx->framebuffers.size; i++) { + ctx->framebuffers.a[i].twodDescriptors = sets->a[i]; + } +} + +void +Vulkan_Draw_Character (int x, int y, unsigned int chr, vulkan_ctx_t *ctx) { } void -vulkan_Draw_Init (void) +Vulkan_Draw_String (int x, int y, const char *str, vulkan_ctx_t *ctx) { } void -vulkan_Draw_Character (int x, int y, unsigned int chr) +Vulkan_Draw_nString (int x, int y, const char *str, int count, + vulkan_ctx_t *ctx) { } void -vulkan_Draw_String (int x, int y, const char *str) +Vulkan_Draw_AltString (int x, int y, const char *str, vulkan_ctx_t *ctx) { } void -vulkan_Draw_nString (int x, int y, const char *str, int count) +Vulkan_Draw_CrosshairAt (int ch, int x, int y, vulkan_ctx_t *ctx) { } void -vulkan_Draw_AltString (int x, int y, const char *str) +Vulkan_Draw_Crosshair (vulkan_ctx_t *ctx) { } void -vulkan_Draw_CrosshairAt (int ch, int x, int y) +Vulkan_Draw_Pic (int x, int y, qpic_t *pic, vulkan_ctx_t *ctx) { } void -vulkan_Draw_Crosshair (void) +Vulkan_Draw_Picf (float x, float y, qpic_t *pic, vulkan_ctx_t *ctx) { } void -vulkan_Draw_Pic (int x, int y, qpic_t *pic) +Vulkan_Draw_SubPic (int x, int y, qpic_t *pic, + int srcx, int srcy, int width, int height, + vulkan_ctx_t *ctx) { } void -vulkan_Draw_Picf (float x, float y, qpic_t *pic) +Vulkan_Draw_ConsoleBackground (int lines, byte alpha, vulkan_ctx_t *ctx) { } void -vulkan_Draw_SubPic (int x, int y, qpic_t *pic, int srcx, int srcy, int width, - int height) +Vulkan_Draw_TileClear (int x, int y, int w, int h, vulkan_ctx_t *ctx) { } void -vulkan_Draw_ConsoleBackground (int lines, byte alpha) +Vulkan_Draw_Fill (int x, int y, int w, int h, int c, vulkan_ctx_t *ctx) { } void -vulkan_Draw_TileClear (int x, int y, int w, int h) +Vulkan_Draw_FadeScreen (vulkan_ctx_t *ctx) { } void -vulkan_Draw_Fill (int x, int y, int w, int h, int c) +Vulkan_Set2D (vulkan_ctx_t *ctx) { } void -vulkan_Draw_FadeScreen (void) +Vulkan_Set2DScaled (vulkan_ctx_t *ctx) { } void -Vulkan_Set2D (void) +Vulkan_End2D (vulkan_ctx_t *ctx) { } void -Vulkan_Set2DScaled (void) +Vulkan_DrawReset (vulkan_ctx_t *ctx) { } void -Vulkan_End2D (void) +Vulkan_FlushText (vulkan_ctx_t *ctx) { } void -Vulkan_DrawReset (void) -{ -} - -void -Vulkan_FlushText (void) -{ -} - -void -vulkan_Draw_BlendScreen (quat_t color) +Vulkan_Draw_BlendScreen (quat_t color, vulkan_ctx_t *ctx) { } diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 3f701e27a..c2b17d0fe 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -420,18 +420,25 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) ctx->renderpass.depthImage = 0; } -void -Vulkan_CreatePipelines (vulkan_ctx_t *ctx) +VkPipeline +Vulkan_CreatePipeline (vulkan_ctx_t *ctx, const char *name) { qfv_load_pipeline (ctx); plitem_t *item = ctx->pipelineDef; - if (!item || !(item = PL_ObjectForKey (item, "pipeline"))) { - Sys_Printf ("error loading pipeline\n"); + if (!item || !(item = PL_ObjectForKey (item, "pipelines"))) { + Sys_Printf ("error loading pipelines\n"); + return 0; } else { - Sys_Printf ("Found pipeline def\n"); + Sys_Printf ("Found pipelines def\n"); } - ctx->pipeline = QFV_ParsePipeline (ctx, item); + if (!(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading pipeline %s\n", name); + return 0; + } else { + Sys_Printf ("Found pipeline def %s\n", name); + } + return QFV_ParsePipeline (ctx, item); } void From 23db917ec4efea4b2964009c95579b1ed766cd4e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 11 Jan 2021 01:24:15 +0900 Subject: [PATCH 211/435] [vulkan] Create a staging buffer struct And move the barrier prefabs into a more convenient place. --- include/QF/Vulkan/barrier.h | 21 ++++ include/QF/Vulkan/qf_vid.h | 1 + include/QF/Vulkan/staging.h | 18 ++++ include/vid_vulkan.h | 1 + libs/video/renderer/Makemodule.am | 2 + libs/video/renderer/vid_render_vulkan.c | 1 + libs/video/renderer/vulkan/barrier.c | 92 ++++++++++++++++++ libs/video/renderer/vulkan/staging.c | 96 +++++++++++++++++++ .../video/renderer/vulkan/vulkan_vid_common.c | 82 +++------------- 9 files changed, 243 insertions(+), 71 deletions(-) create mode 100644 include/QF/Vulkan/barrier.h create mode 100644 include/QF/Vulkan/staging.h create mode 100644 libs/video/renderer/vulkan/barrier.c create mode 100644 libs/video/renderer/vulkan/staging.c diff --git a/include/QF/Vulkan/barrier.h b/include/QF/Vulkan/barrier.h new file mode 100644 index 000000000..12cea49ab --- /dev/null +++ b/include/QF/Vulkan/barrier.h @@ -0,0 +1,21 @@ +#ifndef __QF_Vulkan_barrier_h +#define __QF_Vulkan_barrier_h + +typedef struct { + VkPipelineStageFlags src; + VkPipelineStageFlags dst; +} qfv_pipelinestagepair_t; + +//XXX Note: imageLayoutTransitionBarriers, imageLayoutTransitionStages and +// the enum must be kept in sync +enum { + qfv_LT_Undefined_to_TransferDst, + qfv_LT_TransferDst_to_ShaderReadOnly, + qfv_LT_Undefined_to_DepthStencil, + qfv_LT_Undefined_to_Color, +}; + +extern const VkImageMemoryBarrier imageLayoutTransitionBarriers[]; +extern const qfv_pipelinestagepair_t imageLayoutTransitionStages[]; + +#endif//__QF_Vulkan_barrier_h diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index f859d93f2..d5f59cc84 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -45,5 +45,6 @@ void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx); void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx); void Vulkan_Init_Common (struct vulkan_ctx_s *ctx); void Vulkan_Shutdown_Common (struct vulkan_ctx_s *ctx); +void Vulkan_CreateStagingBuffers (struct vulkan_ctx_s *ctx); #endif // __QF_Vulkan_vid_h diff --git a/include/QF/Vulkan/staging.h b/include/QF/Vulkan/staging.h new file mode 100644 index 000000000..d281f1854 --- /dev/null +++ b/include/QF/Vulkan/staging.h @@ -0,0 +1,18 @@ +#ifndef __QF_Vulkan_staging_h +#define __QF_Vulkan_staging_h + +typedef struct qfv_stagebuf_s { + struct qfv_device_s *device; + VkBuffer buffer; + VkDeviceMemory memory; + size_t size; + void *data; +} qfv_stagebuf_t; + + +qfv_stagebuf_t *QFV_CreateStagingBuffer (struct qfv_device_s *device, + size_t size); +void QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage); +void QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size); + +#endif//__QF_Vulkan_staging_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 0bc8d629d..05e127825 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -57,6 +57,7 @@ typedef struct vulkan_ctx_s { VkCommandBuffer cmdbuffer; VkFence fence; // for ctx->cmdbuffer only vulkan_renderpass_t renderpass; + struct qfv_stagebuf_s *staging[2]; VkPipeline pipeline; size_t curFrame; vulkan_framebufferset_t framebuffers; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 1d6c5eaea..36b013d97 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -215,6 +215,7 @@ libs_video_renderer_vid_render_vulkan_la_DEPENDENCIES=$(vulkan_libs) libs_video_renderer_vid_render_vulkan_la_SOURCES = \ $(video_renderer_common_sources) \ libs/video/renderer/vid_render_vulkan.c \ + libs/video/renderer/vulkan/barrier.c \ libs/video/renderer/vulkan/buffer.c \ libs/video/renderer/vulkan/command.c \ libs/video/renderer/vulkan/descriptor.c \ @@ -226,6 +227,7 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/pipeline.c \ libs/video/renderer/vulkan/renderpass.c \ libs/video/renderer/vulkan/shader.c \ + libs/video/renderer/vulkan/staging.c \ libs/video/renderer/vulkan/swapchain.c \ libs/video/renderer/vulkan/util.c \ libs/video/renderer/vulkan/util.h \ diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index f84f9eb84..64d8f3766 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -62,6 +62,7 @@ vulkan_R_Init (void) qfv_device_t *device = vulkan_ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + Vulkan_CreateStagingBuffers (vulkan_ctx); Vulkan_CreateSwapchain (vulkan_ctx); Vulkan_CreateRenderPass (vulkan_ctx); Vulkan_CreateFramebuffers (vulkan_ctx); diff --git a/libs/video/renderer/vulkan/barrier.c b/libs/video/renderer/vulkan/barrier.c new file mode 100644 index 000000000..c7c1f21a3 --- /dev/null +++ b/libs/video/renderer/vulkan/barrier.c @@ -0,0 +1,92 @@ +/* + barrier.c + + Memory barrier helpers + + Copyright (C) 2021 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/barrier.h" + +const VkImageMemoryBarrier imageLayoutTransitionBarriers[] = { + // undefined -> transfer dst optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }, + // transfer dst optimal -> shader read only optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }, + // undefined -> depth stencil attachment optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + 0, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT + | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1 } + }, + // undefined -> color attachment optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + 0, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT + | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }, + { /* end of transition barriers */ } +}; + +const qfv_pipelinestagepair_t imageLayoutTransitionStages[] = { + // undefined -> transfer dst optimal + { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT }, + // preinitialized -> shader read only optimal + { VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT }, + // transfer dst optimal -> shader read only optimal + { VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT }, + // undefined -> depth stencil attachment optimal + { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT }, + // undefined -> color attachment optimal + { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }, +}; diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c new file mode 100644 index 000000000..de791239c --- /dev/null +++ b/libs/video/renderer/vulkan/staging.c @@ -0,0 +1,96 @@ +/* + shader.c + + Vulkan shader manager + + Copyright (C) 2021 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/qfplist.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/staging.h" + +#include "vid_vulkan.h" + +qfv_stagebuf_t * +QFV_CreateStagingBuffer (qfv_device_t *device, size_t size) +{ + qfv_devfuncs_t *dfunc = device->funcs; + + qfv_stagebuf_t *stage = malloc (sizeof (qfv_stagebuf_t)); + stage->device = device; + stage->buffer = QFV_CreateBuffer (device, size, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + stage->memory = QFV_AllocBufferMemory (device, stage->buffer, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + size, 0); + QFV_BindBufferMemory (device, stage->buffer, stage->memory, 0); + dfunc->vkMapMemory (device->dev, stage->memory, 0, size, 0, &stage->data); + return stage; +} + +void +QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage) +{ + qfv_device_t *device = stage->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkUnmapMemory (device->dev, stage->memory); + dfunc->vkFreeMemory (device->dev, stage->memory, 0); + dfunc->vkDestroyBuffer (device->dev, stage->buffer, 0); + free (stage); +} + +void +QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size) +{ + qfv_device_t *device = stage->device; + qfv_devfuncs_t *dfunc = device->funcs; + + VkMappedMemoryRange range = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + stage->memory, offset, size + }; + dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); +} diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index c2b17d0fe..c230955dc 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -53,6 +53,7 @@ #include "QF/va.h" #include "QF/vid.h" #include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/barrier.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/command.h" @@ -61,6 +62,7 @@ #include "QF/Vulkan/pipeline.h" #include "QF/Vulkan/renderpass.h" #include "QF/Vulkan/shader.h" +#include "QF/Vulkan/staging.h" #include "QF/Vulkan/swapchain.h" #include "compat.h" @@ -171,6 +173,8 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) if (ctx->swapchain) { QFV_DestroySwapchain (ctx->swapchain); } + QFV_DestroyStagingBuffer (ctx->staging[0]); + QFV_DestroyStagingBuffer (ctx->staging[1]); ctx->instance->funcs->vkDestroySurfaceKHR (ctx->instance->instance, ctx->surface, 0); clear_table (&ctx->pipelineLayouts); @@ -194,6 +198,13 @@ Vulkan_CreateDevice (vulkan_ctx_t *ctx) ctx->device = QFV_CreateDevice (ctx, device_extensions); } +void +Vulkan_CreateStagingBuffers (vulkan_ctx_t *ctx) +{ + ctx->staging[0] = QFV_CreateStagingBuffer (ctx->device, 1024*1024); + ctx->staging[1] = QFV_CreateStagingBuffer (ctx->device, 1024*1024); +} + void Vulkan_CreateSwapchain (vulkan_ctx_t *ctx) { @@ -209,77 +220,6 @@ Vulkan_CreateSwapchain (vulkan_ctx_t *ctx) } } -typedef struct { - VkPipelineStageFlags src; - VkPipelineStageFlags dst; -} qfv_pipelinestagepair_t; - -//XXX Note: imageLayoutTransitionBarriers, imageLayoutTransitionStages and -// the enum be kept in sync -enum { - qfv_LT_Undefined_to_TransferDst, - qfv_LT_TransferDst_to_ShaderReadOnly, - qfv_LT_Undefined_to_DepthStencil, - qfv_LT_Undefined_to_Color, -}; - -static VkImageMemoryBarrier imageLayoutTransitionBarriers[] = { - // undefined -> transfer dst optimal - { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, - 0, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, - { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } - }, - // transfer dst optimal -> shader read only optimal - { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_SHADER_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, - { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } - }, - // undefined -> depth stencil attachment optimal - { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, - 0, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT - | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, - { VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1 } - }, - // undefined -> color attachment optimal - { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, - 0, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT - | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, - { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } - }, - { /* end of transition barriers */ } -}; - -static qfv_pipelinestagepair_t imageLayoutTransitionStages[] = { - // undefined -> transfer dst optimal - { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT }, - // transfer dst optimal -> shader read only optimal - { VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT }, - // undefined -> depth stencil attachment optimal - { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT }, - // undefined -> color attachment optimal - { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }, -}; - static void qfv_load_pipeline (vulkan_ctx_t *ctx) { From b584d6f40381c6e223cef113aef7893dbf0abc01 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 11 Jan 2021 01:25:55 +0900 Subject: [PATCH 212/435] [vulkan] Abandon image "preinitialized" layout Turn's out it's not useful for transfers. I might bring it back when I figure out how to use it. --- include/QF/Vulkan/image.h | 3 +-- libs/video/renderer/vulkan/image.c | 8 +++----- libs/video/renderer/vulkan/qfpipeline.plist | 2 +- libs/video/renderer/vulkan/vulkan_draw.c | 3 +-- libs/video/renderer/vulkan/vulkan_vid_common.c | 4 ++-- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index dc6bc5eea..edb5e025e 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -37,8 +37,7 @@ VkImage QFV_CreateImage (struct qfv_device_s *device, int cubemap, uint32_t num_mipmaps, uint32_t num_layers, VkSampleCountFlagBits samples, - VkImageUsageFlags usage_scenarios, - int initialized); + VkImageUsageFlags usage_scenarios); VkDeviceMemory QFV_AllocImageMemory (struct qfv_device_s *device, VkImage image, diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index a60435a9d..68decb94a 100644 --- a/libs/video/renderer/vulkan/image.c +++ b/libs/video/renderer/vulkan/image.c @@ -69,8 +69,7 @@ QFV_CreateImage (qfv_device_t *device, int cubemap, uint32_t num_mipmaps, uint32_t num_layers, VkSampleCountFlagBits samples, - VkImageUsageFlags usage_scenarios, - int initialized) + VkImageUsageFlags usage_scenarios) { VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; @@ -80,12 +79,11 @@ QFV_CreateImage (qfv_device_t *device, int cubemap, type, format, size, num_mipmaps, cubemap ? 6 * num_layers : num_layers, samples, - initialized ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_TILING_OPTIMAL, usage_scenarios, VK_SHARING_MODE_EXCLUSIVE, 0, 0, - initialized ? VK_IMAGE_LAYOUT_PREINITIALIZED - : VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_UNDEFINED, }; VkImage image; dfunc->vkCreateImage (dev, &createInfo, 0, &image); diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 03a4243b2..819492c93 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -26,7 +26,7 @@ minLod = 0; maxLod = 0.25f; borderColor = float_transparent_black; - unnormalizedCoordinates = 0;//FIXME false!!! + unnormalizedCoordinates = 1;//FIXME true!!! }; }; descriptorPools = { diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 7f5e11111..634e401eb 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -142,8 +142,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT - | VK_IMAGE_USAGE_SAMPLED_BIT, - 1); + | VK_IMAGE_USAGE_SAMPLED_BIT); conchars_memory = QFV_AllocImageMemory (device, conchars_image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index c230955dc..e35d5765c 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -261,7 +261,7 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, sc->format, extent, 1, 1, ctx->msaaSamples, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT - | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0); + | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); colorImage->object = QFV_AllocImageMemory (device, colorImage->image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); @@ -278,7 +278,7 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) depthImage->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, depthFormat, extent, 1, 1, ctx->msaaSamples, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0); + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); depthImage->object = QFV_AllocImageMemory (device, depthImage->image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); From 88d48944cb7791f96bd568ac6619a3a382e24d51 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 11 Jan 2021 01:27:40 +0900 Subject: [PATCH 213/435] [vulkan] Upload the default character set Nothing's shown yet, and the code is a tad messy, but it's serving as a proof of concept for now. --- libs/video/renderer/vulkan/vulkan_draw.c | 65 +++++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 634e401eb..a7459bd4c 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -52,9 +52,11 @@ #include "compat.h" #include "QF/Vulkan/qf_draw.h" #include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/barrier.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" +#include "QF/Vulkan/staging.h" #include "r_internal.h" #include "vid_vulkan.h" @@ -134,10 +136,13 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) Sys_RegisterShutdown (Vulkan_Draw_Shutdown, ctx); qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + VkCommandBuffer cmd = ctx->cmdbuffer; + qpic_t *charspic = Draw_Font8x8Pic (); VkExtent3D extent = { charspic->width, charspic->height, 1 }; conchars_image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, - VK_FORMAT_A8B8G8R8_UNORM_PACK32, + VK_FORMAT_A1R5G5B5_UNORM_PACK16, extent, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT @@ -149,10 +154,66 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) QFV_BindImageMemory (device, conchars_image, conchars_memory, 0); conchars_view = QFV_CreateImageView (device, conchars_image, VK_IMAGE_VIEW_TYPE_2D, - VK_FORMAT_A8B8G8R8_UNORM_PACK32, + VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_IMAGE_ASPECT_COLOR_BIT); conchars_sampler = Hash_Find (ctx->samplers, "quakepic"); + uint16_t *chars_data = ctx->staging[0]->data; + size_t size = charspic->width * charspic->height; + for (size_t i = 0; i < size; i++) { + // convert 0xff = transparent, 0xfe = white to 0x0000 and 0xffff + // for a1r5g5b5 + uint16_t pix = (charspic->data[i] & 1) - 1; + chars_data[i] = ~pix; + } + QFV_FlushStagingBuffer (ctx->staging[0], 0, size); + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + dfunc->vkWaitForFences (device->dev, 1, &ctx->fence, VK_TRUE, ~0ull); + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier=imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.image = conchars_image; + dfunc->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, + 0, 0, + 0, 0, + 1, &barrier); + + VkBufferImageCopy region = { + 0, 0, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }, + { 0, 0, 0 }, + { charspic->width, charspic->height, 1 }, + }; + dfunc->vkCmdCopyBufferToImage (cmd, + ctx->staging[0]->buffer, conchars_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ®ion); + + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = conchars_image; + dfunc->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, + 0, 0, + 0, 0, + 1, &barrier); + dfunc->vkEndCommandBuffer (cmd); + + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, + 0, 0, 0, + 1, &cmd, + 0, 0, + }; + dfunc->vkResetFences (device->dev, 1, &ctx->fence); + dfunc->vkQueueSubmit (device->queue.queue, 1, &submitInfo, ctx->fence); + twod = Vulkan_CreatePipeline (ctx, "twod"); handleref_t *h; From 6e636a27d06e8aef530af862eeb29c732a178a42 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 11 Jan 2021 16:57:31 +0900 Subject: [PATCH 214/435] [renderer] Continue the job of merging SCR_UpdateScreen I think this is probably as merged as it will get (though the update callbacks can probably do with some merging). --- include/QF/plugin/vid_render.h | 4 +-- include/QF/screen.h | 3 +++ include/r_internal.h | 2 +- libs/video/renderer/gl/gl_screen.c | 34 +++++-------------------- libs/video/renderer/gl/namehack.h | 4 +-- libs/video/renderer/glsl/glsl_screen.c | 18 +++---------- libs/video/renderer/glsl/namehack.h | 4 +-- libs/video/renderer/r_screen.c | 31 ++++++++++++++++++++++ libs/video/renderer/sw/screen.c | 30 +--------------------- libs/video/renderer/sw32/namehack.h | 4 +-- libs/video/renderer/sw32/screen.c | 30 +--------------------- libs/video/renderer/vid_render_gl.c | 2 +- libs/video/renderer/vid_render_glsl.c | 2 +- libs/video/renderer/vid_render_sw.c | 2 +- libs/video/renderer/vid_render_sw32.c | 2 +- libs/video/renderer/vid_render_vulkan.c | 4 +-- libs/video/renderer/vulkan/namehack.h | 2 -- nq/source/cl_screen.c | 2 +- qw/source/cl_screen.c | 2 +- ruamoko/qwaq/builtins/qwaq-bi.c | 2 +- 20 files changed, 63 insertions(+), 121 deletions(-) diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 6de6e9af7..fc011a8b6 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -130,9 +130,6 @@ typedef struct vid_render_funcs_s { void (*Draw_SubPic) (int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height); - // scr_funcs is a null terminated array - void (*SCR_UpdateScreen) (double realtime, SCR_Func scr_3dfunc, - SCR_Func *scr_funcs); void (*SCR_DrawRam) (void); void (*SCR_DrawTurtle) (void); void (*SCR_DrawPause) (void); @@ -146,6 +143,7 @@ typedef struct vid_render_funcs_s { void (*Fog_ParseWorldspawn) (struct plitem_s *worldspawn); void (*R_Init) (void); + void (*R_RenderFrame) (SCR_Func scr_3dfunc, SCR_Func *scr_funcs); void (*R_ClearState) (void); void (*R_LoadSkys) (const char *); void (*R_NewMap) (model_t *worldmodel, model_t **models, int num_models); diff --git a/include/QF/screen.h b/include/QF/screen.h index 8dda2deb4..b904f1c7c 100644 --- a/include/QF/screen.h +++ b/include/QF/screen.h @@ -35,6 +35,9 @@ void SCR_Init_Cvars (void); void SCR_Init (void); typedef void (*SCR_Func)(void); +// scr_funcs is a null terminated array +void SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, + SCR_Func *scr_funcs); void SCR_SizeUp (void); void SCR_SizeDown (void); diff --git a/include/r_internal.h b/include/r_internal.h index 547d4d1bf..de11978fa 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -44,7 +44,7 @@ void gl_R_Init (void); void glsl_R_Init (void); void sw_R_Init (void); void sw32_R_Init (void); - +void R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs); void R_Init_Cvars (void); void R_InitEfrags (void); void R_ClearState (void); diff --git a/libs/video/renderer/gl/gl_screen.c b/libs/video/renderer/gl/gl_screen.c index fbe47106f..5758b5941 100644 --- a/libs/video/renderer/gl/gl_screen.c +++ b/libs/video/renderer/gl/gl_screen.c @@ -188,37 +188,23 @@ SCR_TileClear (void) } } -/* - SCR_UpdateScreen - - This is called every frame, and can also be called explicitly to flush - text to the screen. - - WARNING: be very careful calling this from elsewhere, because the refresh - needs almost the entire 256k of stack space! -*/ void -gl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) +gl_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) { double time1 = 0, time2; static int begun = 0; - if (scr_skipupdate) - return; - - if (begun) + if (begun) { gl_ctx->end_rendering (); - - vr_data.realtime = realtime; + begun = 0; + } vid.numpages = 2 + gl_triplebuffer->int_val; - scr_copytop = 0; + //FIXME forces the status bar to redraw. needed because it does not fully + //update in sw modes but must in gl mode vr_data.scr_copyeverything = 1; - if (!scr_initialized) - return; // not initialized yet - begun = 1; if (r_speeds->int_val) { @@ -227,14 +213,6 @@ gl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) gl_c_alias_polys = 0; } - if (oldfov != scr_fov->value) { // determine size of refresh window - oldfov = scr_fov->value; - vid.recalc_refdef = true; - } - - if (vid.recalc_refdef) - SCR_CalcRefdef (); - // do 3D refresh drawing, and then update the screen scr_3dfunc (); diff --git a/libs/video/renderer/gl/namehack.h b/libs/video/renderer/gl/namehack.h index 075e31836..e33d0aef6 100644 --- a/libs/video/renderer/gl/namehack.h +++ b/libs/video/renderer/gl/namehack.h @@ -69,7 +69,7 @@ #define SCR_CaptureBGR gl_SCR_CaptureBGR #define SCR_ScreenShot gl_SCR_ScreenShot #define SCR_ScreenShot_f gl_SCR_ScreenShot_f -#define SCR_UpdateScreen gl_SCR_UpdateScreen +#define R_RenderFrame gl_R_RenderFrame #define c_alias_polys gl_c_alias_polys #define c_brush_polys gl_c_brush_polys #define r_easter_eggs_f gl_r_easter_eggs_f @@ -125,7 +125,7 @@ #undef SCR_CaptureBGR #undef SCR_ScreenShot #undef SCR_ScreenShot_f -#undef SCR_UpdateScreen +#undef R_RenderFrame #undef c_alias_polys #undef c_brush_polys #undef r_easter_eggs_f diff --git a/libs/video/renderer/glsl/glsl_screen.c b/libs/video/renderer/glsl/glsl_screen.c index 89276999d..098f6a816 100644 --- a/libs/video/renderer/glsl/glsl_screen.c +++ b/libs/video/renderer/glsl/glsl_screen.c @@ -155,8 +155,7 @@ SCR_TileClear (void) } void -glsl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, - SCR_Func *scr_funcs) +glsl_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) { static int begun = 0; @@ -169,23 +168,14 @@ glsl_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, glsl_ctx->end_rendering (); } - vr_data.realtime = realtime; - vr_data.scr_copyeverything = 1; //FIXME useless cvar? vid.numpages = 2 + gl_triplebuffer->int_val; - if (!scr_initialized) - return; - qfeglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); begun = 1; - - if (oldfov != scr_fov->value) { - oldfov = scr_fov->value; - vid.recalc_refdef = true; - } - if (vid.recalc_refdef) - SCR_CalcRefdef (); + //FIXME forces the status bar to redraw. needed because it does not fully + //update in sw modes but must in glsl mode + vr_data.scr_copyeverything = 1; scr_3dfunc (); diff --git a/libs/video/renderer/glsl/namehack.h b/libs/video/renderer/glsl/namehack.h index 7edaed944..aed6d2e21 100644 --- a/libs/video/renderer/glsl/namehack.h +++ b/libs/video/renderer/glsl/namehack.h @@ -72,7 +72,7 @@ #define SCR_CaptureBGR glsl_SCR_CaptureBGR #define SCR_ScreenShot glsl_SCR_ScreenShot #define SCR_ScreenShot_f glsl_SCR_ScreenShot_f -#define SCR_UpdateScreen glsl_SCR_UpdateScreen +#define R_RenderFrame glsl_R_RenderFrame #define c_alias_polys glsl_c_alias_polys #define c_brush_polys glsl_c_brush_polys #define r_easter_eggs_f glsl_r_easter_eggs_f @@ -128,7 +128,7 @@ #undef SCR_CaptureBGR #undef SCR_ScreenShot #undef SCR_ScreenShot_f -#undef SCR_UpdateScreen +#undef R_RenderFrame #undef c_alias_polys #undef c_brush_polys #undef r_easter_eggs_f diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index 6eb307229..db6dcbcf7 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -170,6 +170,37 @@ SCR_CalcRefdef (void) vr_funcs->R_ViewChanged (vid.aspect); } +/* + SCR_UpdateScreen + + This is called every frame, and can also be called explicitly to flush + text to the screen. + + WARNING: be very careful calling this from elsewhere, because the refresh + needs almost the entire 256k of stack space! +*/ +void +SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) +{ + if (scr_skipupdate || !scr_initialized) { + return; + } + + vr_data.realtime = realtime; + scr_copytop = vr_data.scr_copyeverything = 0; + + if (oldfov != scr_fov->value) { + oldfov = scr_fov->value; + vid.recalc_refdef = true; + } + + if (vid.recalc_refdef) { + SCR_CalcRefdef (); + } + + vr_funcs->R_RenderFrame (scr_3dfunc, scr_funcs); +} + float CalcFov (float fov_x, float width, float height) { diff --git a/libs/video/renderer/sw/screen.c b/libs/video/renderer/sw/screen.c index 5b69e7a0d..4ab9302c1 100644 --- a/libs/video/renderer/sw/screen.c +++ b/libs/video/renderer/sw/screen.c @@ -178,39 +178,11 @@ SCR_ScreenShot_f (void) dstring_delete (pcxname); } -/* - SCR_UpdateScreen - - This is called every frame, and can also be called explicitly to flush - text to the screen. - - WARNING: be very careful calling this from elsewhere, because the refresh - needs almost the entire 256k of stack space! -*/ void -SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) +R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) { vrect_t vrect; - if (scr_skipupdate) - return; - - vr_data.realtime = realtime; - - scr_copytop = 0; - vr_data.scr_copyeverything = 0; - - if (!scr_initialized) - return; // not initialized yet - - if (oldfov != scr_fov->value) { // determine size of refresh window - oldfov = scr_fov->value; - vid.recalc_refdef = true; - } - - if (vid.recalc_refdef) - SCR_CalcRefdef (); - // do 3D refresh drawing, and then update the screen D_EnableBackBufferAccess (); // of all overlay stuff if drawing // directly diff --git a/libs/video/renderer/sw32/namehack.h b/libs/video/renderer/sw32/namehack.h index cbdb673ce..6642d2d54 100644 --- a/libs/video/renderer/sw32/namehack.h +++ b/libs/video/renderer/sw32/namehack.h @@ -110,7 +110,7 @@ #define SCR_CaptureBGR sw32_SCR_CaptureBGR #define SCR_ScreenShot sw32_SCR_ScreenShot #define SCR_ScreenShot_f sw32_SCR_ScreenShot_f -#define SCR_UpdateScreen sw32_SCR_UpdateScreen +#define R_RenderFrame sw32_R_RenderFrame #define TransformVector sw32_TransformVector #define Turbulent sw32_Turbulent #define acolormap sw32_acolormap @@ -351,7 +351,7 @@ extern struct surf_s *sw32_surfaces; #undef SCR_CaptureBGR #undef SCR_ScreenShot #undef SCR_ScreenShot_f -#undef SCR_UpdateScreen +#undef R_RenderFrame #undef TransformVector #undef Turbulent #undef VID_InitBuffers diff --git a/libs/video/renderer/sw32/screen.c b/libs/video/renderer/sw32/screen.c index e4779d8da..543c8602a 100644 --- a/libs/video/renderer/sw32/screen.c +++ b/libs/video/renderer/sw32/screen.c @@ -136,39 +136,11 @@ sw32_SCR_ScreenShot_f (void) dstring_delete (pcxname); } -/* - SCR_UpdateScreen - - This is called every frame, and can also be called explicitly to flush - text to the screen. - - WARNING: be very careful calling this from elsewhere, because the refresh - needs almost the entire 256k of stack space! -*/ void -sw32_SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) +sw32_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) { vrect_t vrect; - if (scr_skipupdate) - return; - - vr_data.realtime = realtime; - - scr_copytop = 0; - vr_data.scr_copyeverything = 0; - - if (!scr_initialized) - return; // not initialized yet - - if (oldfov != scr_fov->value) { // determine size of refresh window - oldfov = scr_fov->value; - vid.recalc_refdef = true; - } - - if (vid.recalc_refdef) - SCR_CalcRefdef (); - // do 3D refresh drawing, and then update the screen sw32_D_EnableBackBufferAccess (); // of all overlay stuff if drawing // directly diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 434588894..c27b5d4ac 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -93,7 +93,6 @@ vid_render_funcs_t gl_vid_render_funcs = { gl_Draw_Picf, gl_Draw_SubPic, - gl_SCR_UpdateScreen, SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, @@ -105,6 +104,7 @@ vid_render_funcs_t gl_vid_render_funcs = { gl_Fog_ParseWorldspawn, gl_R_Init, + gl_R_RenderFrame, gl_R_ClearState, gl_R_LoadSkys, gl_R_NewMap, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index f8ca47174..e3b549e35 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -93,7 +93,6 @@ vid_render_funcs_t glsl_vid_render_funcs = { glsl_Draw_Picf, glsl_Draw_SubPic, - glsl_SCR_UpdateScreen, SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, @@ -105,6 +104,7 @@ vid_render_funcs_t glsl_vid_render_funcs = { glsl_Fog_ParseWorldspawn, glsl_R_Init, + glsl_R_RenderFrame, glsl_R_ClearState, glsl_R_LoadSkys, glsl_R_NewMap, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index a418d200c..5c9264381 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -86,7 +86,6 @@ vid_render_funcs_t sw_vid_render_funcs = { Draw_Picf, Draw_SubPic, - SCR_UpdateScreen, SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, @@ -98,6 +97,7 @@ vid_render_funcs_t sw_vid_render_funcs = { 0, sw_R_Init, + R_RenderFrame, R_ClearState, R_LoadSkys, R_NewMap, diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index 9fffb0298..be727c8a9 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -91,7 +91,6 @@ vid_render_funcs_t sw32_vid_render_funcs = { sw32_Draw_Picf, sw32_Draw_SubPic, - sw32_SCR_UpdateScreen, SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, @@ -103,6 +102,7 @@ vid_render_funcs_t sw32_vid_render_funcs = { 0, sw32_R_Init, + sw32_R_RenderFrame, sw32_R_ClearState, sw32_R_LoadSkys, sw32_R_NewMap, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 64d8f3766..a61a911a2 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -105,7 +105,7 @@ vulkan_R_Init (void) } static void -vulkan_SCR_UpdateScreen (double time, void (*f)(void), void (**g)(void)) +vulkan_R_RenderFrame (void (*f)(void), void (**g)(void)) { static int count = 0; static double startTime; @@ -324,7 +324,6 @@ vid_render_funcs_t vulkan_vid_render_funcs = { vulkan_Draw_Picf, vulkan_Draw_SubPic, - vulkan_SCR_UpdateScreen, SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, @@ -336,6 +335,7 @@ vid_render_funcs_t vulkan_vid_render_funcs = { 0,//vulkan_Fog_ParseWorldspawn, vulkan_R_Init, + vulkan_R_RenderFrame, 0,//vulkan_R_ClearState, 0,//vulkan_R_LoadSkys, 0,//vulkan_R_NewMap, diff --git a/libs/video/renderer/vulkan/namehack.h b/libs/video/renderer/vulkan/namehack.h index 7289995f2..17f107080 100644 --- a/libs/video/renderer/vulkan/namehack.h +++ b/libs/video/renderer/vulkan/namehack.h @@ -72,7 +72,6 @@ #define SCR_CaptureBGR vulkan_SCR_CaptureBGR #define SCR_ScreenShot vulkan_SCR_ScreenShot #define SCR_ScreenShot_f vulkan_SCR_ScreenShot_f -#define SCR_UpdateScreen vulkan_SCR_UpdateScreen #define c_alias_polys vulkan_c_alias_polys #define c_brush_polys vulkan_c_brush_polys #define r_easter_eggs_f vulkan_r_easter_eggs_f @@ -128,7 +127,6 @@ #undef SCR_CaptureBGR #undef SCR_ScreenShot #undef SCR_ScreenShot_f -#undef SCR_UpdateScreen #undef c_alias_polys #undef c_brush_polys #undef r_easter_eggs_f diff --git a/nq/source/cl_screen.c b/nq/source/cl_screen.c index c7940e305..509352a1c 100644 --- a/nq/source/cl_screen.c +++ b/nq/source/cl_screen.c @@ -146,5 +146,5 @@ CL_UpdateScreen (double realtime) scr_funcs_normal[3] = r_funcs->SCR_DrawPause; V_PrepBlend (); - r_funcs->SCR_UpdateScreen (realtime, V_RenderView, scr_funcs[index]); + SCR_UpdateScreen (realtime, V_RenderView, scr_funcs[index]); } diff --git a/qw/source/cl_screen.c b/qw/source/cl_screen.c index 5b81f65a7..7827c30db 100644 --- a/qw/source/cl_screen.c +++ b/qw/source/cl_screen.c @@ -147,5 +147,5 @@ CL_UpdateScreen (double realtime) scr_funcs_normal[3] = r_funcs->SCR_DrawPause; V_PrepBlend (); - r_funcs->SCR_UpdateScreen (realtime, V_RenderView, scr_funcs[index]); + SCR_UpdateScreen (realtime, V_RenderView, scr_funcs[index]); } diff --git a/ruamoko/qwaq/builtins/qwaq-bi.c b/ruamoko/qwaq/builtins/qwaq-bi.c index 27a7ae04f..a78dd7763 100644 --- a/ruamoko/qwaq/builtins/qwaq-bi.c +++ b/ruamoko/qwaq/builtins/qwaq-bi.c @@ -127,7 +127,7 @@ bi_refresh (progs_t *pr) IN_ProcessEvents (); //GIB_Thread_Execute (); Cbuf_Execute_Stack (qwaq_cbuf); - r_funcs->SCR_UpdateScreen (con_realtime, bi_3d, bi_2dfuncs); + SCR_UpdateScreen (con_realtime, bi_3d, bi_2dfuncs); R_FLOAT (pr) = con_frametime; } From bf4613acd5b2e57b01c2081ea49a93e6da25cbbd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 12 Jan 2021 10:43:05 +0900 Subject: [PATCH 215/435] [vulkan] Remove missed preinitialized stages --- libs/video/renderer/vulkan/barrier.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/libs/video/renderer/vulkan/barrier.c b/libs/video/renderer/vulkan/barrier.c index c7c1f21a3..e257eb990 100644 --- a/libs/video/renderer/vulkan/barrier.c +++ b/libs/video/renderer/vulkan/barrier.c @@ -77,9 +77,6 @@ const qfv_pipelinestagepair_t imageLayoutTransitionStages[] = { // undefined -> transfer dst optimal { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT }, - // preinitialized -> shader read only optimal - { VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT }, // transfer dst optimal -> shader read only optimal { VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT }, From 8f6f32981c0d9b7034ebfd00585fa2722f2541ac Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 12 Jan 2021 11:26:20 +0900 Subject: [PATCH 216/435] [vulkan] Add some matrix buffers It seems they could all be in the one buffer: there are indications that uniform binding can be fairly fine-grained. I need to investigate that. --- include/QF/Vulkan/qf_vid.h | 4 + include/vid_vulkan.h | 12 ++ libs/video/renderer/Makemodule.am | 1 + libs/video/renderer/vid_render_vulkan.c | 9 +- libs/video/renderer/vulkan/vulkan_matrices.c | 204 ++++++++++++++++++ .../video/renderer/vulkan/vulkan_vid_common.c | 1 + 6 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 libs/video/renderer/vulkan/vulkan_matrices.c diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index d5f59cc84..7e30a3a57 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -41,6 +41,10 @@ void Vulkan_CreateFramebuffers (struct vulkan_ctx_s *ctx); void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx); void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx); VkPipeline Vulkan_CreatePipeline (struct vulkan_ctx_s *ctx, const char *name); +void Vulkan_CreateMatrices (struct vulkan_ctx_s *ctx); +void Vulkan_DestroyMatrices (struct vulkan_ctx_s *ctx); +void Vulkan_CalcProjectionMatrices (struct vulkan_ctx_s *ctx, float aspect); +void Vulkan_CalcViewMatrix (struct vulkan_ctx_s *ctx); void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx); void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx); void Vulkan_Init_Common (struct vulkan_ctx_s *ctx); diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 05e127825..3ffa0052c 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -24,6 +24,15 @@ typedef struct vulkan_framebuffer_s { VkDescriptorSet twodDescriptors; } vulkan_framebuffer_t; +typedef struct vulkan_matrices_s { + VkBuffer buffer_2d; + VkBuffer buffer_3d; + VkDeviceMemory memory; + float *projection_2d; + float *projection_3d; + float *view_3d; +} vulkan_matrices_t; + typedef struct vulkan_framebufferset_s DARRAY_TYPE (vulkan_framebuffer_t) vulkan_framebufferset_t; @@ -62,6 +71,9 @@ typedef struct vulkan_ctx_s { size_t curFrame; vulkan_framebufferset_t framebuffers; + // projection and view matrices (model is push constant) + vulkan_matrices_t matrices; + #define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname; #define GLOBAL_LEVEL_VULKAN_FUNCTION(fname) PFN_##fname fname; #include "QF/Vulkan/funclist.h" diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 36b013d97..d6187a93a 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -233,6 +233,7 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/util.h \ libs/video/renderer/vulkan/vkparse.c \ libs/video/renderer/vulkan/vulkan_draw.c \ + libs/video/renderer/vulkan/vulkan_matrices.c \ libs/video/renderer/vulkan/vulkan_vid_common.c libs/video/renderer/vulkan/vkparse.lo: libs/video/renderer/vulkan/vkparse.c $(vkparse_src) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index a61a911a2..77368d093 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -63,6 +63,7 @@ vulkan_R_Init (void) qfv_devfuncs_t *dfunc = device->funcs; Vulkan_CreateStagingBuffers (vulkan_ctx); + Vulkan_CreateMatrices (vulkan_ctx); Vulkan_CreateSwapchain (vulkan_ctx); Vulkan_CreateRenderPass (vulkan_ctx); Vulkan_CreateFramebuffers (vulkan_ctx); @@ -276,6 +277,12 @@ vulkan_Draw_SubPic (int x, int y, qpic_t *pic, int srcx, int srcy, int width, in Vulkan_Draw_SubPic (x, y, pic, srcx, srcy, width, height, vulkan_ctx); } +static void +vulkan_R_ViewChanged (float aspect) +{ + Vulkan_CalcProjectionMatrices (vulkan_ctx, aspect); +} + static vid_model_funcs_t model_funcs = { 0,//vulkan_Mod_LoadExternalTextures, 0,//vulkan_Mod_LoadLighting, @@ -347,7 +354,7 @@ vid_render_funcs_t vulkan_vid_render_funcs = { R_AllocEntity, 0,//vulkan_R_RenderView, R_DecayLights, - 0,//vulkan_R_ViewChanged, + vulkan_R_ViewChanged, 0,//vulkan_R_ClearParticles, 0,//vulkan_R_InitParticles, 0,//vulkan_SCR_ScreenShot_f, diff --git a/libs/video/renderer/vulkan/vulkan_matrices.c b/libs/video/renderer/vulkan/vulkan_matrices.c new file mode 100644 index 000000000..c734f82d0 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_matrices.c @@ -0,0 +1,204 @@ +/* + vid_common_vulkan.c + + Common Vulkan video driver functions + + Copyright (C) 2021 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/device.h" + +#include "compat.h" +#include "d_iface.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#include "util.h" + +#define MAT_SIZE (16 * sizeof (float)) + +static void +ortho_mat (float *proj, float xmin, float xmax, float ymin, float ymax, + float znear, float zfar) +{ + proj[0] = 2 / (xmax - xmin); + proj[4] = 0; + proj[8] = 0; + proj[12] = -(xmax + xmin) / (xmax - xmin); + + proj[1] = 0; + proj[5] = 2 / (ymax - ymin); + proj[9] = 0; + proj[13] = -(ymax + ymin) / (ymax - ymin); + + proj[2] = 0; + proj[6] = 0; + proj[10] = -2 / (zfar - znear); + proj[14] = -(zfar + znear) / (zfar - znear); + + proj[3] = 0; + proj[7] = 0; + proj[11] = 0; + proj[15] = 1; +} + +static void +persp_mat (float *proj, float xmin, float xmax, float ymin, float ymax, + float aspect) +{ + float fovx, fovy, neard, fard; + + fovx = r_refdef.fov_x; + fovy = r_refdef.fov_y; + neard = r_nearclip->value; + fard = r_farclip->value; + + ymax = neard * tan (fovy * M_PI / 360); // fov_2 / 2 + ymin = -ymax; + xmax = neard * tan (fovx * M_PI / 360); // fov_2 / 2 + xmin = -xmax; + + proj[0] = (2 * neard) / (xmax - xmin); + proj[4] = 0; + proj[8] = (xmax + xmin) / (xmax - xmin); + proj[12] = 0; + + proj[1] = 0; + proj[5] = (2 * neard) / (ymax - ymin); + proj[9] = (ymax + ymin) / (ymax - ymin); + proj[13] = 0; + + proj[2] = 0; + proj[6] = 0; + proj[10] = (fard + neard) / (neard - fard); + proj[14] = (2 * fard * neard) / (neard - fard); + + proj[3] = 0; + proj[7] = 0; + proj[11] = -1; + proj[15] = 0; +} + +void +Vulkan_DestroyMatrices (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + __auto_type mat = &ctx->matrices; + + dfunc->vkUnmapMemory (device->dev, mat->memory); + dfunc->vkFreeMemory (device->dev, mat->memory, 0); + dfunc->vkDestroyBuffer (device->dev, mat->buffer_2d, 0); + dfunc->vkDestroyBuffer (device->dev, mat->buffer_3d, 0); +} + +void +Vulkan_CreateMatrices (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + __auto_type mat = &ctx->matrices; + mat->buffer_2d = QFV_CreateBuffer (device, 1 * MAT_SIZE, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + mat->buffer_3d = QFV_CreateBuffer (device, 2 * MAT_SIZE, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + + size_t size = 0; + size_t offset; + VkMemoryRequirements req; + + dfunc->vkGetBufferMemoryRequirements (device->dev, mat->buffer_2d, &req); + size += req.size; + offset = size; + + dfunc->vkGetBufferMemoryRequirements (device->dev, mat->buffer_3d, &req); + offset = (offset + req.alignment - 1) & ~(req.alignment - 1); + size += req.size; + + mat->memory = QFV_AllocBufferMemory (device, mat->buffer_2d, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + size, 0); + QFV_BindBufferMemory (device, mat->buffer_2d, mat->memory, 0); + QFV_BindBufferMemory (device, mat->buffer_3d, mat->memory, offset); + void *data; + dfunc->vkMapMemory (device->dev, mat->memory, 0, size, 0, &data); + mat->projection_2d = data; + mat->projection_3d = mat->projection_2d + offset / sizeof (float); + mat->view_3d = mat->projection_3d + 16; +} + +void +Vulkan_CalcProjectionMatrices (vulkan_ctx_t *ctx, float aspect) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + __auto_type mat = &ctx->matrices; + + int width = vid.conwidth; + int height = vid.conheight; + + ortho_mat (mat->projection_2d, 0, width, 0, height, -99999, 99999); + persp_mat (mat->projection_3d, 0, width, 0, height, aspect); + + Sys_MaskPrintf (SYS_VULKAN, "ortho:\n"); + Sys_MaskPrintf (SYS_VULKAN, " [[%g, %g, %g, %g],\n", + QuatExpand (mat->projection_2d + 0)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g],\n", + QuatExpand (mat->projection_2d + 4)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g],\n", + QuatExpand (mat->projection_2d + 8)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g]]\n", + QuatExpand (mat->projection_2d + 12)); + Sys_MaskPrintf (SYS_VULKAN, "presp:\n"); + Sys_MaskPrintf (SYS_VULKAN, " [[%g, %g, %g, %g],\n", + QuatExpand (mat->projection_3d + 0)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g],\n", + QuatExpand (mat->projection_3d + 4)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g],\n", + QuatExpand (mat->projection_3d + 8)); + Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g]]\n", + QuatExpand (mat->projection_3d + 12)); + + VkMappedMemoryRange ranges[] = { + { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, mat->memory, 0, MAT_SIZE }, + { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, mat->memory, + (mat->projection_3d - mat->projection_2d) * sizeof (float), + MAT_SIZE}, + }; + dfunc->vkFlushMappedMemoryRanges (device->dev, 2, ranges); +} diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index e35d5765c..c166c239b 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -175,6 +175,7 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) } QFV_DestroyStagingBuffer (ctx->staging[0]); QFV_DestroyStagingBuffer (ctx->staging[1]); + Vulkan_DestroyMatrices (ctx); ctx->instance->funcs->vkDestroySurfaceKHR (ctx->instance->instance, ctx->surface, 0); clear_table (&ctx->pipelineLayouts); From bb4ca7683ee028a107d5cebae98f93186491f0ef Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 12 Jan 2021 11:27:41 +0900 Subject: [PATCH 217/435] [vulkan] Get the 2D pipeline up and running First pixels! This was a nightmare of little issues that the validation layers couldn't help with: incorrect input assembly, incorrect vertex attribute specs. Though the layers did help with getting the queues working. Still, lots of work to go but this is a major breakthrough as I now have access to visual debugging for textures and the like. --- include/QF/Vulkan/funclist.h | 8 + include/QF/Vulkan/qf_draw.h | 1 + include/vid_vulkan.h | 2 + libs/video/renderer/vid_render_vulkan.c | 67 ++-- libs/video/renderer/vulkan/qfpipeline.plist | 16 +- libs/video/renderer/vulkan/twod.vert | 9 +- libs/video/renderer/vulkan/vulkan_draw.c | 286 +++++++++++++++++- .../video/renderer/vulkan/vulkan_vid_common.c | 7 +- 8 files changed, 343 insertions(+), 53 deletions(-) diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 8ab62852a..534097b5d 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -166,6 +166,14 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdNextSubpass) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdEndRenderPass) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindPipeline) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdClearColorImage) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdExecuteCommands) + +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdSetViewport) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdSetScissor) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindVertexBuffers) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindIndexBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindDescriptorSets) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdDrawIndexed) #undef DEVICE_LEVEL_VULKAN_FUNCTION diff --git a/include/QF/Vulkan/qf_draw.h b/include/QF/Vulkan/qf_draw.h index b0297c2d0..c9e8b20ad 100644 --- a/include/QF/Vulkan/qf_draw.h +++ b/include/QF/Vulkan/qf_draw.h @@ -31,6 +31,7 @@ struct vulkan_ctx_s; void Vulkan_Draw_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Draw_Shutdown (struct vulkan_ctx_s *ctx); void Vulkan_Draw_Character (int x, int y, unsigned ch, struct vulkan_ctx_s *ctx); void Vulkan_Draw_String (int x, int y, const char *str, diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 3ffa0052c..784c74312 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -21,6 +21,8 @@ typedef struct vulkan_framebuffer_s { VkSemaphore renderDoneSemaphore; VkCommandBuffer cmdBuffer; + struct qfv_cmdbufferset_s *subCommand; + VkDescriptorSet twodDescriptors; } vulkan_framebuffer_t; diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 77368d093..431f6e0b4 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -59,9 +59,6 @@ static vulkan_ctx_t *vulkan_ctx; static void vulkan_R_Init (void) { - qfv_device_t *device = vulkan_ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; - Vulkan_CreateStagingBuffers (vulkan_ctx); Vulkan_CreateMatrices (vulkan_ctx); Vulkan_CreateSwapchain (vulkan_ctx); @@ -72,41 +69,18 @@ vulkan_R_Init (void) vulkan_ctx->pipeline = Vulkan_CreatePipeline (vulkan_ctx, "pipeline"); Vulkan_Draw_Init (vulkan_ctx); - qfv_swapchain_t *sc = vulkan_ctx->swapchain; - - VkCommandBufferBeginInfo beginInfo - = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - VkClearValue clearValues[3] = { - { { {0.7294, 0.8549, 0.3333, 1.0} } }, - { { {1.0, 0.0} } }, - { { {0, 0, 0, 0} } }, - }; - VkRenderPassBeginInfo renderPassInfo = { - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 0, - vulkan_ctx->renderpass.renderpass, 0, - { {0, 0}, sc->extent }, - 2, clearValues + 2 - }; - for (size_t i = 0; i < vulkan_ctx->framebuffers.size; i++) { - __auto_type framebuffer = &vulkan_ctx->framebuffers.a[i]; - dfunc->vkBeginCommandBuffer (framebuffer->cmdBuffer, &beginInfo); - renderPassInfo.framebuffer = framebuffer->framebuffer; - dfunc->vkCmdBeginRenderPass (framebuffer->cmdBuffer, &renderPassInfo, - VK_SUBPASS_CONTENTS_INLINE); - - dfunc->vkCmdEndRenderPass (framebuffer->cmdBuffer); - dfunc->vkEndCommandBuffer (framebuffer->cmdBuffer); - } Sys_Printf ("R_Init %p %d", vulkan_ctx->swapchain->swapchain, vulkan_ctx->swapchain->numImages); for (int32_t i = 0; i < vulkan_ctx->swapchain->numImages; i++) { Sys_Printf (" %p", vulkan_ctx->swapchain->images->a[i]); } Sys_Printf ("\n"); + + SCR_Init (); } static void -vulkan_R_RenderFrame (void (*f)(void), void (**g)(void)) +vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) { static int count = 0; static double startTime; @@ -116,6 +90,12 @@ vulkan_R_RenderFrame (void (*f)(void), void (**g)(void)) VkDevice dev = device->dev; qfv_queue_t *queue = &vulkan_ctx->device->queue; + scr_3dfunc (); + while (*scr_funcs) { + (*scr_funcs) (); + scr_funcs++; + } + __auto_type framebuffer = &vulkan_ctx->framebuffers.a[vulkan_ctx->curFrame]; @@ -124,6 +104,34 @@ vulkan_R_RenderFrame (void (*f)(void), void (**g)(void)) framebuffer->imageAvailableSemaphore, 0, &imageIndex); + Vulkan_FlushText (vulkan_ctx); + + qfv_swapchain_t *sc = vulkan_ctx->swapchain; + VkCommandBufferBeginInfo beginInfo + = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + VkClearValue clearValues[2] = { + { { {0.0, 0.0, 0.0, 1.0} } }, + { { {1.0, 0.0} } }, + }; + VkRenderPassBeginInfo renderPassInfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 0, + vulkan_ctx->renderpass.renderpass, 0, + { {0, 0}, sc->extent }, + 2, clearValues + }; + + dfunc->vkBeginCommandBuffer (framebuffer->cmdBuffer, &beginInfo); + renderPassInfo.framebuffer = framebuffer->framebuffer; + dfunc->vkCmdBeginRenderPass (framebuffer->cmdBuffer, &renderPassInfo, + VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + + dfunc->vkCmdExecuteCommands (framebuffer->cmdBuffer, + framebuffer->subCommand->size, + framebuffer->subCommand->a); + + dfunc->vkCmdEndRenderPass (framebuffer->cmdBuffer); + dfunc->vkEndCommandBuffer (framebuffer->cmdBuffer); + VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submitInfo = { @@ -425,6 +433,7 @@ vulkan_vid_render_shutdown (void) QFV_DeviceWaitIdle (device); df->vkDestroyFence (dev, vulkan_ctx->fence, 0); df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0); + Vulkan_Draw_Shutdown (vulkan_ctx); Vulkan_Shutdown_Common (vulkan_ctx); } diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 819492c93..3d7ec1f10 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -24,7 +24,7 @@ compareEnable = 0;//FIXME false!!! compareOp = always; minLod = 0; - maxLod = 0.25f; + maxLod = 0; borderColor = float_transparent_black; unnormalizedCoordinates = 1;//FIXME true!!! }; @@ -113,20 +113,26 @@ { location = 0; binding = 0; - format = r32g32b32a32_sfloat; + format = r32g32_sfloat; offset = 0; }, { location = 1; binding = 0; + format = r32g32_sint; + offset = 8; + }, + { + location = 2; + binding = 0; format = r32g32b32a32_sfloat; - offset = 4; + offset = 16; }, ); }; inputAssembly = { - topology = triangle_list; - primitiveRestartEnable = 0; + topology = triangle_strip; + primitiveRestartEnable = 1; }; viewport = { viewports = ( diff --git a/libs/video/renderer/vulkan/twod.vert b/libs/video/renderer/vulkan/twod.vert index 83655d6a7..5db2990db 100644 --- a/libs/video/renderer/vulkan/twod.vert +++ b/libs/video/renderer/vulkan/twod.vert @@ -2,8 +2,6 @@ layout (set = 0, binding = 0) uniform Matrices { mat4 Projection; - mat4 View; - mat4 Model; }; /** Vertex position. @@ -12,8 +10,9 @@ layout (set = 0, binding = 0) uniform Matrices { \a vertex provides the onscreen location at which to draw the icon (\a x, \a y) and texture coordinate for the icon (\a s=z, \a t=w). */ -layout (location = 0) in vec4 vertex; -layout (location = 1) in vec4 vcolor; +layout (location = 0) in vec2 vertex; +layout (location = 1) in ivec2 uv; +layout (location = 2) in vec4 vcolor; layout (location = 0) out vec2 st; layout (location = 1) out vec4 color; @@ -22,6 +21,6 @@ void main (void) { gl_Position = Projection * vec4 (vertex.xy, 0.0, 1.0); - st = vertex.zw; + st = vec2(uv); color = vcolor; } diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index a7459bd4c..76cbb0c82 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -53,6 +53,8 @@ #include "QF/Vulkan/qf_draw.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/command.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" @@ -62,13 +64,86 @@ #include "vid_vulkan.h" #include "vkparse.h" +typedef struct { + float xy[2]; + int st[2]; + float color[4]; +} drawvert_t; + +#define MAX_QUADS (65536) +#define VERTS_PER_QUAD (4) +#define INDS_PER_QUAD (5) // one per vert plus primitive reset + //FIXME move into a context struct VkImage conchars_image; VkDeviceMemory conchars_memory; VkImageView conchars_view; VkSampler conchars_sampler; -VkPipeline twod; +VkBuffer quad_vert_buffer; +VkBuffer quad_ind_buffer; +VkDeviceMemory quad_memory; +drawvert_t *quad_verts; +uint32_t *quad_inds; +uint32_t num_quads; + +VkPipeline twod_pipeline; +VkPipelineLayout twod_layout; +size_t draw_cmdBuffer; + +static void +create_quad_buffers (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + //FIXME quad_inds can be a completely separate buffer that is + //pre-initialized to draw 2-tri triangle strips as the actual indices will + //never change + size_t vert_size = MAX_QUADS * VERTS_PER_QUAD * sizeof (drawvert_t); + size_t ind_size = MAX_QUADS * INDS_PER_QUAD * sizeof (uint32_t); + + quad_vert_buffer = QFV_CreateBuffer (device, vert_size, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + quad_ind_buffer = QFV_CreateBuffer (device, ind_size, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + quad_memory = QFV_AllocBufferMemory (device, quad_vert_buffer, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + vert_size + ind_size, 0); + QFV_BindBufferMemory (device, quad_vert_buffer, quad_memory, 0); + QFV_BindBufferMemory (device, quad_ind_buffer, quad_memory, vert_size); + void *data; + dfunc->vkMapMemory (device->dev, quad_memory, 0, vert_size + ind_size, + 0, &data); + quad_verts = data; + quad_inds = (uint32_t *) (quad_verts + MAX_QUADS * VERTS_PER_QUAD); + // pre-initialize quad_inds as the indices will never change + uint32_t *ind = quad_inds; + for (int i = 0; i < MAX_QUADS; i++) { + for (int j = 0; j < VERTS_PER_QUAD; j++) { + *ind++ = i * VERTS_PER_QUAD + j; + } + // mark end of primitive + *ind++ = -1; + } + VkMappedMemoryRange range = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + quad_memory, vert_size, ind_size, + }; + dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); +} + +static void +destroy_quad_buffers (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkUnmapMemory (device->dev, quad_memory); + dfunc->vkFreeMemory (device->dev, quad_memory, 0); + dfunc->vkDestroyBuffer (device->dev, quad_vert_buffer, 0); + dfunc->vkDestroyBuffer (device->dev, quad_ind_buffer, 0); +} static qpic_t * pic_data (const char *name, int w, int h, const byte *data) @@ -117,14 +192,15 @@ Vulkan_Draw_TextBox (int x, int y, int width, int lines, byte alpha, { } -static void -Vulkan_Draw_Shutdown (void *data) +void +Vulkan_Draw_Shutdown (vulkan_ctx_t *ctx) { - vulkan_ctx_t *ctx = data; qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - dfunc->vkDestroyPipeline (device->dev, twod, 0); + destroy_quad_buffers (ctx); + + dfunc->vkDestroyPipeline (device->dev, twod_pipeline, 0); dfunc->vkDestroyImageView (device->dev, conchars_view, 0); dfunc->vkFreeMemory (device->dev, conchars_memory, 0); dfunc->vkDestroyImage (device->dev, conchars_image, 0); @@ -133,12 +209,12 @@ Vulkan_Draw_Shutdown (void *data) void Vulkan_Draw_Init (vulkan_ctx_t *ctx) { - Sys_RegisterShutdown (Vulkan_Draw_Shutdown, ctx); - qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; VkCommandBuffer cmd = ctx->cmdbuffer; + create_quad_buffers (ctx); + qpic_t *charspic = Draw_Font8x8Pic (); VkExtent3D extent = { charspic->width, charspic->height, 1 }; conchars_image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, @@ -156,7 +232,9 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_IMAGE_ASPECT_COLOR_BIT); - conchars_sampler = Hash_Find (ctx->samplers, "quakepic"); + handleref_t *h; + h = Hash_Find (ctx->samplers, "quakepic"); + conchars_sampler = (VkSampler) h->handle; uint16_t *chars_data = ctx->staging[0]->data; size_t size = charspic->width * charspic->height; @@ -164,9 +242,9 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) // convert 0xff = transparent, 0xfe = white to 0x0000 and 0xffff // for a1r5g5b5 uint16_t pix = (charspic->data[i] & 1) - 1; - chars_data[i] = ~pix; + chars_data[i] = pix; } - QFV_FlushStagingBuffer (ctx->staging[0], 0, size); + QFV_FlushStagingBuffer (ctx->staging[0], 0, size * sizeof (uint16_t)); VkImageMemoryBarrier barrier; qfv_pipelinestagepair_t stages; dfunc->vkWaitForFences (device->dev, 1, &ctx->fence, VK_TRUE, ~0ull); @@ -214,9 +292,11 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) dfunc->vkResetFences (device->dev, 1, &ctx->fence); dfunc->vkQueueSubmit (device->queue.queue, 1, &submitInfo, ctx->fence); - twod = Vulkan_CreatePipeline (ctx, "twod"); + twod_pipeline = Vulkan_CreatePipeline (ctx, "twod"); + + h = Hash_Find (ctx->pipelineLayouts, "twod"); + twod_layout = (VkPipelineLayout) h->handle; - handleref_t *h; __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (ctx->framebuffers.size, alloca); for (size_t i = 0; i < layouts->size; i++) { h = Hash_Find (ctx->setLayouts, "twod"); @@ -224,31 +304,167 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) } h = Hash_Find (ctx->descriptorPools, "twod"); __auto_type pool = (VkDescriptorPool) h->handle; + + VkDescriptorBufferInfo bufferInfo = { + ctx->matrices.buffer_2d, 0, VK_WHOLE_SIZE + }; + VkDescriptorImageInfo imageInfo = { + conchars_sampler, + conchars_view, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + __auto_type cmdBuffers + = QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, + ctx->framebuffers.size); + __auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); for (size_t i = 0; i < ctx->framebuffers.size; i++) { - ctx->framebuffers.a[i].twodDescriptors = sets->a[i]; + __auto_type frame = &ctx->framebuffers.a[i]; + frame->twodDescriptors = sets->a[i]; + + VkWriteDescriptorSet write[] = { + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, + frame->twodDescriptors, 0, 0, 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, &bufferInfo, 0 }, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, + frame->twodDescriptors, 1, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + &imageInfo, 0, 0 }, + }; + dfunc->vkUpdateDescriptorSets (device->dev, 2, write, 0, 0); + draw_cmdBuffer = frame->subCommand->size; + DARRAY_APPEND (frame->subCommand, cmdBuffers->a[i]); } + free (sets); + free (cmdBuffers); +} + +static inline void +draw_pic (float x, float y, int w, int h, qpic_t *pic, + int srcx, int srcy, int srcw, int srch, + float *color) +{ + if (num_quads + VERTS_PER_QUAD > MAX_QUADS) { + return; + } + + drawvert_t *verts = quad_verts + num_quads * VERTS_PER_QUAD; + num_quads += VERTS_PER_QUAD; + + float sl = (srcx); + float sr = (srcx + srcw); + float st = (srcy); + float sb = (srcy + srch); + + verts[0].xy[0] = x; + verts[0].xy[1] = y; + verts[0].st[0] = sl; + verts[0].st[1] = st; + QuatCopy (color, verts[0].color); + + verts[1].xy[0] = x; + verts[1].xy[1] = y + h; + verts[1].st[0] = sl; + verts[1].st[1] = sb; + QuatCopy (color, verts[1].color); + + verts[2].xy[0] = x + w; + verts[2].xy[1] = y; + verts[2].st[0] = sr; + verts[2].st[1] = st; + QuatCopy (color, verts[2].color); + + verts[3].xy[0] = x + w; + verts[3].xy[1] = y + h; + verts[3].st[0] = sr; + verts[3].st[1] = sb; + QuatCopy (color, verts[3].color); +} + +static inline void +queue_character (int x, int y, byte chr, vulkan_ctx_t *ctx) +{ + quat_t color = {1, 1, 1, 1}; + int cx, cy; + cx = chr % 16; + cy = chr / 16; + + draw_pic (x, y, 8, 8, 0/*FIXME*/, cx * 8, cy * 8, 8, 8, color); } void Vulkan_Draw_Character (int x, int y, unsigned int chr, vulkan_ctx_t *ctx) { + if (chr == ' ') { + return; + } + if (y <= -8 || y >= vid.conheight) { + return; + } + if (x <= -8 || x >= vid.conwidth) { + return; + } + queue_character (x, y, chr, ctx); } void Vulkan_Draw_String (int x, int y, const char *str, vulkan_ctx_t *ctx) { + byte chr; + + if (!str || !str[0]) { + return; + } + if (y <= -8 || y >= vid.conheight) { + return; + } + while (*str) { + if ((chr = *str++) != ' ' && x >= -8 && x < vid.conwidth) { + queue_character (x, y, chr, ctx); + } + x += 8; + } } void Vulkan_Draw_nString (int x, int y, const char *str, int count, vulkan_ctx_t *ctx) { + byte chr; + + if (!str || !str[0]) { + return; + } + if (y <= -8 || y >= vid.conheight) { + return; + } + while (count-- > 0 && *str) { + if ((chr = *str++) != ' ' && x >= -8 && x < vid.conwidth) { + queue_character (x, y, chr, ctx); + } + x += 8; + } } void Vulkan_Draw_AltString (int x, int y, const char *str, vulkan_ctx_t *ctx) { + byte chr; + + if (!str || !str[0]) { + return; + } + if (y <= -8 || y >= vid.conheight) { + return; + } + while (*str) { + if ((chr = *str++ | 0x80) != (' ' | 0x80) + && x >= -8 && x < vid.conwidth) { + queue_character (x, y, chr, ctx); + } + x += 8; + } } void @@ -321,6 +537,50 @@ Vulkan_DrawReset (vulkan_ctx_t *ctx) void Vulkan_FlushText (vulkan_ctx_t *ctx) { + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + __auto_type frame = &ctx->framebuffers.a[ctx->curFrame]; + VkCommandBuffer cmd = frame->subCommand->a[draw_cmdBuffer]; + + VkMappedMemoryRange range = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + quad_memory, 0, num_quads * VERTS_PER_QUAD * sizeof (drawvert_t), + }; + dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); + + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + ctx->renderpass.renderpass, 0, + frame->framebuffer, + 0, 0, 0 + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + twod_pipeline); + VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; + VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; + dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); + VkDeviceSize offsets[] = {0}; + dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &quad_vert_buffer, offsets); + dfunc->vkCmdBindIndexBuffer (cmd, quad_ind_buffer, 0, + VK_INDEX_TYPE_UINT32); + VkDescriptorSet set = frame->twodDescriptors; + VkPipelineLayout layout = twod_layout; + dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + layout, 0, 1, &set, 0, 0); + dfunc->vkCmdDrawIndexed (cmd, num_quads * INDS_PER_QUAD, 1, 0, 0, 0); + + dfunc->vkEndCommandBuffer (cmd); + + num_quads = 0; } void diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index c166c239b..126d602fd 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -3,7 +3,6 @@ Common Vulkan video driver functions - Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2019 Bill Currie This program is free software; you can redistribute it and/or @@ -54,6 +53,7 @@ #include "QF/vid.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/buffer.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/command.h" @@ -127,6 +127,7 @@ Vulkan_Init_Cvars (void) msaaSamples = Cvar_Get ("msaaSamples", "VK_SAMPLE_COUNT_1_BIT", CVAR_NONE, msaaSamples_f, "desired MSAA sample size."); + R_Init_Cvars (); } static const char *instance_extensions[] = { @@ -415,7 +416,11 @@ Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) frame->imageAvailableSemaphore = QFV_CreateSemaphore (device); frame->renderDoneSemaphore = QFV_CreateSemaphore (device); frame->cmdBuffer = cmdBuffers->a[i]; + + frame->subCommand = malloc (sizeof (qfv_cmdbufferset_t)); + DARRAY_INIT (frame->subCommand, 4); } + free (cmdBuffers); } void From 03f614ccb90bd99243c83674c7a05fb7ff7fd129 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 12 Jan 2021 13:07:51 +0900 Subject: [PATCH 218/435] [vulkan] Parse VkBool32 correctly as bool type This makes it much clearer whether something is just a flag or an index of some sort. --- libs/video/renderer/vulkan/qfpipeline.plist | 32 ++++++++++----------- libs/video/renderer/vulkan/vkgen/vkalias.r | 22 ++++++++++++-- libs/video/renderer/vulkan/vkgen/vkenum.r | 6 ++++ libs/video/renderer/vulkan/vkgen/vkgen.r | 5 +++- 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 3d7ec1f10..437ab5854 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -19,14 +19,14 @@ addressModeV = clamp_to_edge; addressModeW = clamp_to_edge; mipLodBias = 0; - anisotropyEnable = 0;//FIXME false!!! + anisotropyEnable = false; maxAnisotropy = 0; - compareEnable = 0;//FIXME false!!! + compareEnable = false; compareOp = always; minLod = 0; maxLod = 0; borderColor = float_transparent_black; - unnormalizedCoordinates = 1;//FIXME true!!! + unnormalizedCoordinates = true; }; }; descriptorPools = { @@ -132,7 +132,7 @@ }; inputAssembly = { topology = triangle_strip; - primitiveRestartEnable = 1; + primitiveRestartEnable = true; }; viewport = { viewports = ( @@ -150,32 +150,32 @@ ); }; rasterization = { - depthClampEnable = 0; - rasterizerDiscardEnable = 0; + depthClampEnable = false; + rasterizerDiscardEnable = false; polygonMode = fill; cullMode = back; frontFace = counter_clockwise; - depthBiasEnable = 0; + depthBiasEnable = false; lineWidth = 1; }; multisample = { rasterizationSamples = $msaaSamples; - sampleShadingEnable = 0; + sampleShadingEnable = false; minSampleShading = 0.5f; - alphaToCoverageEnable = 0; - alphaToOneEnable = 0; + alphaToCoverageEnable = false; + alphaToOneEnable = false; }; depthStencil = { - depthTestEnable = 1; - depthWriteEnable = 1; + depthTestEnable = true; + depthWriteEnable = true; depthCompareOp = less; - depthBoundsTestEnable = 0; - stencilTestEnable = 0; + depthBoundsTestEnable = false; + stencilTestEnable = false; }; colorBlend = { - logicOpEnable = 0; + logicOpEnable = false; attachments = ({ - blendEnable = 0; + blendEnable = false; srcColorBlendFactor = src_color; dstColorBlendFactor = zero; colorBlendOp = add; diff --git a/libs/video/renderer/vulkan/vkgen/vkalias.r b/libs/video/renderer/vulkan/vkgen/vkalias.r index be783b207..cde6eb270 100644 --- a/libs/video/renderer/vulkan/vkgen/vkalias.r +++ b/libs/video/renderer/vulkan/vkgen/vkalias.r @@ -28,14 +28,16 @@ [enumObj addToQueue]; } } else if (name == "VkBool32") { - // drop + id enumObj = [(id) Hash_Find (available_types, name) resolveType]; + [enumObj addToQueue]; } else if ([alias class] == [Enum class] || [alias class] == [Struct class]) { [alias addToQueue]; } else if (alias.type.meta == ty_basic && alias.type.type == ev_pointer) { Type *type = [Type findType:alias.type.fldptr.aux_type]; if (!type) { - // pointer to opaque struct. Probably VK_DEFINE_NON_DISPATCHABLE_HANDLE or VK_DEFINE_HANDLE + // pointer to opaque struct. Probably + // VK_DEFINE_NON_DISPATCHABLE_HANDLE or VK_DEFINE_HANDLE string createInfo = name + "CreateInfo"; id structObj = (id) Hash_Find (available_types, createInfo); if (structObj) { @@ -62,6 +64,10 @@ return [enumObj cexprType]; } } + if (name == "VkBool32") { + id enumObj = [(id) Hash_Find (available_types, name) resolveType]; + return [enumObj cexprType]; + } if (name == "uint32_t") { return "cexpr_uint"; } @@ -83,6 +89,10 @@ return [enumObj parseType]; } } + if (name == "VkBool32") { + id enumObj = [(id) Hash_Find (available_types, name) resolveType]; + return [enumObj parseType]; + } if (name == "uint32_t" || name == "size_t") { return "QFString"; } @@ -101,6 +111,10 @@ return [enumObj parseFunc]; } } + if (name == "VkBool32") { + id enumObj = [(id) Hash_Find (available_types, name) resolveType]; + return [enumObj parseFunc]; + } if (name == "uint32_t") { return "parse_uint32_t"; } @@ -119,6 +133,10 @@ return [enumObj parseData]; } } + if (name == "VkBool32") { + id enumObj = [(id) Hash_Find (available_types, name) resolveType]; + return [enumObj parseData]; + } if (name == "uint32_t" || name == "size_t") { return "0"; } diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.r b/libs/video/renderer/vulkan/vkgen/vkenum.r index 537916800..7c974f6fb 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.r +++ b/libs/video/renderer/vulkan/vkgen/vkenum.r @@ -3,6 +3,12 @@ #include "vkenum.h" #include "vkgen.h" +typedef enum VkBool32 { + VK_FALSE, + VK_TRUE, + VK_MAX_ENUM = VK_TRUE +} VkBool32; + @implementation Enum -(void)process { diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r index 4636df52f..01637c54a 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.r +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -117,7 +117,10 @@ scan_types (void) string tag = str_mid(type.strct.tag, 4); Type *avail_type = [Type fromType: type]; if (avail_type) { - Hash_Add (available_types, avail_type); + if (!Hash_Find (available_types, [avail_type name])) { + printf ("scan: %s %s\n", tag, [avail_type name]); + Hash_Add (available_types, avail_type); + } } } } From 8a85b5c610b5c3d475bae6b3c51a3ce0f3b76690 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 12 Jan 2021 13:51:41 +0900 Subject: [PATCH 219/435] [vulkan] Switch to float/normalized for pics It gives better results when pics are squished or expanded. --- libs/video/renderer/vulkan/qfpipeline.plist | 4 ++-- libs/video/renderer/vulkan/twod.vert | 4 ++-- libs/video/renderer/vulkan/vulkan_draw.c | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 437ab5854..a291ddf09 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -26,7 +26,7 @@ minLod = 0; maxLod = 0; borderColor = float_transparent_black; - unnormalizedCoordinates = true; + unnormalizedCoordinates = false; }; }; descriptorPools = { @@ -119,7 +119,7 @@ { location = 1; binding = 0; - format = r32g32_sint; + format = r32g32_sfloat; offset = 8; }, { diff --git a/libs/video/renderer/vulkan/twod.vert b/libs/video/renderer/vulkan/twod.vert index 5db2990db..c5dc5063a 100644 --- a/libs/video/renderer/vulkan/twod.vert +++ b/libs/video/renderer/vulkan/twod.vert @@ -11,7 +11,7 @@ layout (set = 0, binding = 0) uniform Matrices { (\a x, \a y) and texture coordinate for the icon (\a s=z, \a t=w). */ layout (location = 0) in vec2 vertex; -layout (location = 1) in ivec2 uv; +layout (location = 1) in vec2 uv; layout (location = 2) in vec4 vcolor; layout (location = 0) out vec2 st; @@ -21,6 +21,6 @@ void main (void) { gl_Position = Projection * vec4 (vertex.xy, 0.0, 1.0); - st = vec2(uv); + st = uv; color = vcolor; } diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 76cbb0c82..5dca3b98e 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -66,7 +66,7 @@ typedef struct { float xy[2]; - int st[2]; + float st[2]; float color[4]; } drawvert_t; @@ -352,10 +352,10 @@ draw_pic (float x, float y, int w, int h, qpic_t *pic, drawvert_t *verts = quad_verts + num_quads * VERTS_PER_QUAD; num_quads += VERTS_PER_QUAD; - float sl = (srcx); - float sr = (srcx + srcw); - float st = (srcy); - float sb = (srcy + srch); + float sl = (srcx + 0.03125) / 128.0; + float sr = (srcx + srcw - 0.03125) / 128.0; + float st = (srcy + 0.03125) / 128.0; + float sb = (srcy + srch - 0.03125) / 128.0; verts[0].xy[0] = x; verts[0].xy[1] = y; From 93aa038d9e8511a5857109c4468ce8bd027436a5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 12 Jan 2021 14:56:02 +0900 Subject: [PATCH 220/435] [vulkan] Generate handle get functions Cleans up (hides) the casting when fetching a handle. --- libs/video/renderer/vulkan/vkgen/vkhandle.r | 7 +++++++ libs/video/renderer/vulkan/vkparse.h | 7 +++++++ libs/video/renderer/vulkan/vulkan_draw.c | 13 ++++--------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/libs/video/renderer/vulkan/vkgen/vkhandle.r b/libs/video/renderer/vulkan/vkgen/vkhandle.r index b76d99af4..ec78c22ba 100644 --- a/libs/video/renderer/vulkan/vkgen/vkhandle.r +++ b/libs/video/renderer/vulkan/vkgen/vkhandle.r @@ -56,10 +56,17 @@ output_handle (string name, PLItem *handle) } fprintf (output_file, "}\n"); + fprintf (output_file, "%s QFV_Get%s (vulkan_ctx_t *ctx, const char *name)\n", name, str_mid (name, 2)); + fprintf (output_file, "{\n"); + fprintf (output_file, "\thandleref_t *handleref = Hash_Find (ctx->%s, name);\n", symtab); + fprintf (output_file, "\treturn handleref ? (%s) handleref->handle : 0;\n", name); + fprintf (output_file, "}\n"); + if (!custom) { fprintf (header_file, "static int parse_%s (const plitem_t *item, void **data, plitem_t *messages, parsectx_t *context);\n", name); } fprintf (header_file, "int parse_%s_handleref (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context);\n", name); + fprintf (output_file, "%s QFV_Get%s (vulkan_ctx_t *ctx, const char *name);\n", name, str_mid (name, 2)); str_free (custom); str_free (symtab); str_free (class); diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index 75dd8fe9d..459c0f6a2 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -24,6 +24,13 @@ typedef struct handleref_s { uint64_t handle; } handleref_t; +VkShaderModule QFV_GetShaderModule (vulkan_ctx_t *ctx, const char *name); +VkDescriptorPool QFV_GetDescriptorPool (vulkan_ctx_t *ctx, const char *name); +VkDescriptorSetLayout QFV_GetDescriptorSetLayout (vulkan_ctx_t *ctx, + const char *name); +VkPipelineLayout QFV_GetPipelineLayout (vulkan_ctx_t *ctx, const char *name); +VkSampler QFV_GetSampler (vulkan_ctx_t *ctx, const char *name); + void QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *plist); void QFV_InitParse (vulkan_ctx_t *ctx); exprenum_t *QFV_GetEnum (const char *name); diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 5dca3b98e..89ead5380 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -232,9 +232,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_IMAGE_ASPECT_COLOR_BIT); - handleref_t *h; - h = Hash_Find (ctx->samplers, "quakepic"); - conchars_sampler = (VkSampler) h->handle; + conchars_sampler = QFV_GetSampler (ctx, "quakepic"); uint16_t *chars_data = ctx->staging[0]->data; size_t size = charspic->width * charspic->height; @@ -294,16 +292,13 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) twod_pipeline = Vulkan_CreatePipeline (ctx, "twod"); - h = Hash_Find (ctx->pipelineLayouts, "twod"); - twod_layout = (VkPipelineLayout) h->handle; + twod_layout = QFV_GetPipelineLayout (ctx, "twod"); __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (ctx->framebuffers.size, alloca); for (size_t i = 0; i < layouts->size; i++) { - h = Hash_Find (ctx->setLayouts, "twod"); - layouts->a[i] = (VkDescriptorSetLayout) h->handle; + layouts->a[i] = QFV_GetDescriptorSetLayout (ctx, "twod"); } - h = Hash_Find (ctx->descriptorPools, "twod"); - __auto_type pool = (VkDescriptorPool) h->handle; + __auto_type pool = QFV_GetDescriptorPool (ctx, "twod"); VkDescriptorBufferInfo bufferInfo = { ctx->matrices.buffer_2d, 0, VK_WHOLE_SIZE From 858ac1932726a239e272a0aa1449149588ba141f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 12 Jan 2021 16:14:46 +0900 Subject: [PATCH 221/435] [renderer] Move r_screen and r_cvar into main bin r_screen because of SCR_UpdateScreen, and r_cvar because the cvars really should never have been in a plugin in the first place (and r_screen needed access). --- include/QF/plugin/vid_render.h | 1 + libs/video/renderer/Makemodule.am | 4 +- libs/video/renderer/r_cvar.c | 22 ++++++---- libs/video/renderer/r_main.c | 2 - libs/video/renderer/r_screen.c | 56 +++++++++++++------------ libs/video/renderer/vid_render_gl.c | 1 + libs/video/renderer/vid_render_glsl.c | 1 + libs/video/renderer/vid_render_sw.c | 1 + libs/video/renderer/vid_render_sw32.c | 1 + libs/video/renderer/vid_render_vulkan.c | 1 + 10 files changed, 51 insertions(+), 39 deletions(-) diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index fc011a8b6..462aaabf4 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -153,6 +153,7 @@ typedef struct vid_render_funcs_s { void (*R_LineGraph) (int x, int y, int *h_vals, int count); dlight_t *(*R_AllocDlight) (int key); entity_t *(*R_AllocEntity) (void); + void (*R_MaxDlightsCheck) (struct cvar_s *var); void (*R_RenderView) (void); void (*R_DecayLights) (double frametime); diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index d6187a93a..3e5dd4f70 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -17,7 +17,6 @@ video_renderer_common_sources = \ libs/video/renderer/noisetextures.c \ libs/video/renderer/r_alias.c \ libs/video/renderer/r_bsp.c \ - libs/video/renderer/r_cvar.c \ libs/video/renderer/r_dyn_textures.c \ libs/video/renderer/r_efrag.c \ libs/video/renderer/r_ent.c \ @@ -26,7 +25,6 @@ video_renderer_common_sources = \ libs/video/renderer/r_light.c \ libs/video/renderer/r_main.c \ libs/video/renderer/r_part.c \ - libs/video/renderer/r_screen.c \ libs/video/renderer/vid_common.c renderer_libs= \ @@ -37,7 +35,9 @@ libs_video_renderer_libQFrenderer_la_LDFLAGS= @STATIC@ libs_video_renderer_libQFrenderer_la_LIBADD= $(renderer_libs) libs_video_renderer_libQFrenderer_la_DEPENDENCIES= $(renderer_libs) libs_video_renderer_libQFrenderer_la_SOURCES=\ + libs/video/renderer/r_cvar.c \ libs/video/renderer/r_init.c \ + libs/video/renderer/r_screen.c \ libs/video/renderer/r_progs.c video_renderer_gl_libs= \ diff --git a/libs/video/renderer/r_cvar.c b/libs/video/renderer/r_cvar.c index d9f3e14d2..98cd22858 100644 --- a/libs/video/renderer/r_cvar.c +++ b/libs/video/renderer/r_cvar.c @@ -138,7 +138,7 @@ r_farclip_f (cvar_t *var) Cvar_SetValue (r_particles_nearclip, bound (r_nearclip->value, r_particles_nearclip->value, r_farclip->value)); - vid.recalc_refdef = true; + r_data->vid->recalc_refdef = true; } static void @@ -149,7 +149,7 @@ r_nearclip_f (cvar_t *var) Cvar_SetValue (r_particles_nearclip, bound (r_nearclip->value, r_particles_nearclip->value, r_farclip->value)); - vid.recalc_refdef = true; + r_data->vid->recalc_refdef = true; } static void @@ -176,13 +176,19 @@ viewsize_f (cvar_t *var) if (var->int_val < 30 || var->int_val > 120) { Cvar_SetValue (var, bound (30, var->int_val, 120)); } else { - vid.recalc_refdef = true; + r_data->vid->recalc_refdef = true; r_viewsize = bound (0, var->int_val, 100); - if (vr_data.viewsize_callback) - vr_data.viewsize_callback (var); + if (r_data->viewsize_callback) + r_data->viewsize_callback (var); } } +static void +r_dlight_max_f (cvar_t *var) +{ + r_funcs->R_MaxDlightsCheck (var); +} + void R_Init_Cvars (void) { @@ -218,7 +224,7 @@ R_Init_Cvars (void) NULL, "Set to 1 for high quality dynamic " "lighting."); r_dlight_max = Cvar_Get ("r_dlight_max", "32", CVAR_ARCHIVE, - R_MaxDlightsCheck, "Number of dynamic lights."); + r_dlight_max_f, "Number of dynamic lights."); r_drawentities = Cvar_Get ("r_drawentities", "1", CVAR_NONE, NULL, "Toggles drawing of entities (almost " "everything but the world)"); @@ -309,6 +315,6 @@ R_Init_Cvars (void) scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE, viewsize_f, "Set the screen size 30 minimum, 120 maximum"); - vr_data.graphheight = r_graphheight; - vr_data.scr_viewsize = scr_viewsize; + r_data->graphheight = r_graphheight; + r_data->scr_viewsize = scr_viewsize; } diff --git a/libs/video/renderer/r_main.c b/libs/video/renderer/r_main.c index 0d38123d3..bc1590dd0 100644 --- a/libs/video/renderer/r_main.c +++ b/libs/video/renderer/r_main.c @@ -70,8 +70,6 @@ vec3_t r_entorigin; // the currently rendering entity in world entity_t *currententity; entity_t r_worldentity; -qboolean r_cache_thrash; // set if surface cache is thrashing - // view origin vec3_t vup, base_vup; vec3_t vpn, base_vpn; diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index db6dcbcf7..5e4e3ba61 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -97,6 +97,8 @@ byte *draw_chars; // 8*8 graphic characters FIXME location float oldfov; int oldsbar; +qboolean r_cache_thrash; // set if surface cache is thrashing + qboolean scr_initialized; // ready to draw qpic_t *scr_ram; @@ -117,7 +119,7 @@ R_SetVrect (vrect_t *vrectin, vrect_t *vrect, int lineadj) // intermission is always full screen size = min (r_viewsize, 100); - if (vr_data.force_fullscreen) { + if (r_data->force_fullscreen) { size = 100.0; lineadj = 0; } @@ -148,18 +150,18 @@ SCR_CalcRefdef (void) refdef_t *refdef = r_data->refdef; // force a background redraw - vr_data.scr_fullupdate = 0; - vid.recalc_refdef = 0; + r_data->scr_fullupdate = 0; + r_data->vid->recalc_refdef = 0; // bound field of view Cvar_SetValue (scr_fov, bound (1, scr_fov->value, 170)); vrect.x = 0; vrect.y = 0; - vrect.width = vid.width; - vrect.height = vid.height; + vrect.width = r_data->vid->width; + vrect.height = r_data->vid->height; - R_SetVrect (&vrect, &scr_vrect, vr_data.lineadj); + R_SetVrect (&vrect, &scr_vrect, r_data->lineadj); refdef->vrect = scr_vrect; refdef->fov_x = scr_fov->value; @@ -167,7 +169,7 @@ SCR_CalcRefdef (void) CalcFov (refdef->fov_x, refdef->vrect.width, refdef->vrect.height); // notify the refresh of the change - vr_funcs->R_ViewChanged (vid.aspect); + r_funcs->R_ViewChanged (r_data->vid->aspect); } /* @@ -186,19 +188,19 @@ SCR_UpdateScreen (double realtime, SCR_Func scr_3dfunc, SCR_Func *scr_funcs) return; } - vr_data.realtime = realtime; - scr_copytop = vr_data.scr_copyeverything = 0; + r_data->realtime = realtime; + scr_copytop = r_data->scr_copyeverything = 0; if (oldfov != scr_fov->value) { oldfov = scr_fov->value; - vid.recalc_refdef = true; + r_data->vid->recalc_refdef = true; } - if (vid.recalc_refdef) { + if (r_data->vid->recalc_refdef) { SCR_CalcRefdef (); } - vr_funcs->R_RenderFrame (scr_3dfunc, scr_funcs); + r_funcs->R_RenderFrame (scr_3dfunc, scr_funcs); } float @@ -221,7 +223,7 @@ CalcFov (float fov_x, float width, float height) static void ScreenShot_f (void) { - vr_funcs->SCR_ScreenShot_f (); + r_funcs->SCR_ScreenShot_f (); } /* @@ -234,7 +236,7 @@ SCR_SizeUp_f (void) { if (scr_viewsize->int_val < 120) { Cvar_SetValue (scr_viewsize, scr_viewsize->int_val + 10); - vid.recalc_refdef = 1; + r_data->vid->recalc_refdef = 1; } } @@ -247,7 +249,7 @@ static void SCR_SizeDown_f (void) { Cvar_SetValue (scr_viewsize, scr_viewsize->int_val - 10); - vid.recalc_refdef = 1; + r_data->vid->recalc_refdef = 1; } void @@ -259,7 +261,7 @@ SCR_DrawRam (void) if (!r_cache_thrash) return; - vr_funcs->Draw_Pic (scr_vrect.x + 32, scr_vrect.y, scr_ram); + r_funcs->Draw_Pic (scr_vrect.x + 32, scr_vrect.y, scr_ram); } void @@ -270,7 +272,7 @@ SCR_DrawTurtle (void) if (!scr_showturtle->int_val) return; - if (vr_data.frametime < 0.1) { + if (r_data->frametime < 0.1) { count = 0; return; } @@ -279,7 +281,7 @@ SCR_DrawTurtle (void) if (count < 3) return; - vr_funcs->Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle); + r_funcs->Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle); } void @@ -290,12 +292,12 @@ SCR_DrawPause (void) if (!scr_showpause->int_val) // turn off for screenshots return; - if (!vr_data.paused) + if (!r_data->paused) return; - pic = vr_funcs->Draw_CachePic ("gfx/pause.lmp", true); - vr_funcs->Draw_Pic ((vid.conwidth - pic->width) / 2, - (vid.conheight - 48 - pic->height) / 2, pic); + pic = r_funcs->Draw_CachePic ("gfx/pause.lmp", true); + r_funcs->Draw_Pic ((r_data->vid->conwidth - pic->width) / 2, + (r_data->vid->conheight - 48 - pic->height) / 2, pic); } void @@ -323,9 +325,9 @@ MipColor (int r, int g, int b) for (i = 0; i < 256; i++) { int j; j = i * 3; - r1 = vid.palette[j] - r; - g1 = vid.palette[j + 1] - g; - b1 = vid.palette[j + 2] - b; + r1 = r_data->vid->palette[j] - r; + g1 = r_data->vid->palette[j + 1] - g; + b1 = r_data->vid->palette[j + 2] - b; dist = r1 * r1 + g1 * g1 + b1 * b1; if (dist < bestdist) { bestdist = dist; @@ -391,8 +393,8 @@ SCR_Init (void) Cmd_AddCommand ("sizeup", SCR_SizeUp_f, "Increases the screen size"); Cmd_AddCommand ("sizedown", SCR_SizeDown_f, "Decreases the screen size"); - scr_ram = vr_funcs->Draw_PicFromWad ("ram"); - scr_turtle = vr_funcs->Draw_PicFromWad ("turtle"); + scr_ram = r_funcs->Draw_PicFromWad ("ram"); + scr_turtle = r_funcs->Draw_PicFromWad ("turtle"); scr_initialized = true; } diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index c27b5d4ac..852a0a423 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -114,6 +114,7 @@ vid_render_funcs_t gl_vid_render_funcs = { gl_R_LineGraph, R_AllocDlight, R_AllocEntity, + R_MaxDlightsCheck, gl_R_RenderView, R_DecayLights, gl_R_ViewChanged, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index e3b549e35..25bdb9224 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -114,6 +114,7 @@ vid_render_funcs_t glsl_vid_render_funcs = { glsl_R_LineGraph, R_AllocDlight, R_AllocEntity, + R_MaxDlightsCheck, glsl_R_RenderView, R_DecayLights, glsl_R_ViewChanged, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 5c9264381..02ff562e6 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -107,6 +107,7 @@ vid_render_funcs_t sw_vid_render_funcs = { R_LineGraph, R_AllocDlight, R_AllocEntity, + R_MaxDlightsCheck, R_RenderView, R_DecayLights, R_ViewChanged, diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index be727c8a9..97097e2ad 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -112,6 +112,7 @@ vid_render_funcs_t sw32_vid_render_funcs = { sw32_R_LineGraph, R_AllocDlight, R_AllocEntity, + R_MaxDlightsCheck, sw32_R_RenderView, R_DecayLights, sw32_R_ViewChanged, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 431f6e0b4..995763baf 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -360,6 +360,7 @@ vid_render_funcs_t vulkan_vid_render_funcs = { 0,//vulkan_R_LineGraph, R_AllocDlight, R_AllocEntity, + R_MaxDlightsCheck, 0,//vulkan_R_RenderView, R_DecayLights, vulkan_R_ViewChanged, From db14025935b79ae2a87b42281307647ce42b4a2e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 12 Jan 2021 17:34:57 +0900 Subject: [PATCH 222/435] [gamecode] Put strings and debug back in load funcs It turns out they're required to be initialized before most of the rest of the system. --- libs/gamecode/pr_debug.c | 1 - libs/gamecode/pr_load.c | 2 ++ libs/gamecode/pr_strings.c | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index d8105c5f6..a272babf8 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -1702,7 +1702,6 @@ PR_Debug_Init (progs_t *pr) pr->hashlink_freelist); PR_Resources_Register (pr, "PR_Debug", res, pr_debug_clear); - PR_AddLoadFunc (pr, PR_LoadDebug); } void diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index 6ef18cc15..32033ae90 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -378,7 +378,9 @@ pr_run_ctors (progs_t *pr) } static int (*load_funcs_1[])(progs_t *) = { + PR_LoadStrings, PR_RelocateBuiltins, + PR_LoadDebug, 0, }; diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index 7cb295284..82e9540da 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -1222,5 +1222,4 @@ PR_Strings_Init (progs_t *pr) res->print_str = dstring_new (); PR_Resources_Register (pr, "Strings", res, pr_strings_clear); - PR_AddLoadFunc (pr, PR_LoadStrings); } From bfbfd7af61d0bed1f921ec9786c5cb9abcf74f72 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 12 Jan 2021 18:45:44 +0900 Subject: [PATCH 223/435] [glsl] Remove subpic_t's tnum It's never actually used (the texture can be fetched using GLSL_ScrapTexture) and gets in the way of sharing the scrap system with the vulkan renderer. --- include/QF/GLSL/qf_textures.h | 1 - libs/video/renderer/glsl/glsl_textures.c | 1 - 2 files changed, 2 deletions(-) diff --git a/include/QF/GLSL/qf_textures.h b/include/QF/GLSL/qf_textures.h index 5f30fbf68..0a6e3ba6d 100644 --- a/include/QF/GLSL/qf_textures.h +++ b/include/QF/GLSL/qf_textures.h @@ -35,7 +35,6 @@ typedef struct subpic_s { const struct subpic_s * const next; const scrap_t * const scrap; const struct vrect_s * const rect; - const int tnum; ///< texture number const int width; ///< requested width const int height; ///< requested height const float size; ///< size factor for tex coords (mult) diff --git a/libs/video/renderer/glsl/glsl_textures.c b/libs/video/renderer/glsl/glsl_textures.c index 4e6303093..8130dfdf5 100644 --- a/libs/video/renderer/glsl/glsl_textures.c +++ b/libs/video/renderer/glsl/glsl_textures.c @@ -437,7 +437,6 @@ GLSL_ScrapSubpic (scrap_t *scrap, int width, int height) scrap->subpics = subpic; *((scrap_t **) &subpic->scrap) = scrap; *((vrect_t **) &subpic->rect) = rect; - *((int *) &subpic->tnum) = scrap->tnum; *((int *) &subpic->width) = width; *((int *) &subpic->height) = height; *((float *) &subpic->size) = 1.0 / scrap->size; From b6bc8ed5537ca99171ac6bf728e46092d7fa8c0d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 12 Jan 2021 21:10:22 +0900 Subject: [PATCH 224/435] [renderer] Move core of scrap into shared code The actual 2d area management code is now shared, with the actual definition for scrap_t being left to the renderer specific implementation. --- include/QF/GLSL/qf_textures.h | 16 +- include/QF/render.h | 9 ++ include/r_scrap.h | 49 ++++++ libs/video/renderer/Makemodule.am | 1 + libs/video/renderer/glsl/glsl_textures.c | 120 +++------------ libs/video/renderer/r_init.c | 2 + libs/video/renderer/r_scrap.c | 183 +++++++++++++++++++++++ 7 files changed, 273 insertions(+), 107 deletions(-) create mode 100644 include/r_scrap.h create mode 100644 libs/video/renderer/r_scrap.c diff --git a/include/QF/GLSL/qf_textures.h b/include/QF/GLSL/qf_textures.h index 0a6e3ba6d..2298c3e16 100644 --- a/include/QF/GLSL/qf_textures.h +++ b/include/QF/GLSL/qf_textures.h @@ -31,14 +31,6 @@ #include "QF/qtypes.h" typedef struct scrap_s scrap_t; -typedef struct subpic_s { - const struct subpic_s * const next; - const scrap_t * const scrap; - const struct vrect_s * const rect; - const int width; ///< requested width - const int height; ///< requested height - const float size; ///< size factor for tex coords (mult) -} subpic_t; int GLSL_LoadQuakeTexture (const char *identifier, int width, int height, byte *data); @@ -55,9 +47,11 @@ scrap_t *GLSL_CreateScrap (int size, int format, int linear); void GLSL_DestroyScrap (scrap_t *scrap); void GLSL_ScrapClear (scrap_t *scrap); int GLSL_ScrapTexture (scrap_t *scrap) __attribute__((pure)); -subpic_t *GLSL_ScrapSubpic (scrap_t *scrap, int width, int height); //XXX slow! -void GLSL_SubpicDelete (subpic_t *subpic); //XXX slow! -void GLSL_SubpicUpdate (subpic_t *subpic, byte *data, int batch); +//XXX slow! +struct subpic_s *GLSL_ScrapSubpic (scrap_t *scrap, int width, int height); +//XXX slow! +void GLSL_SubpicDelete (struct subpic_s *subpic); +void GLSL_SubpicUpdate (struct subpic_s *subpic, byte *data, int batch); void GLSL_ScrapFlush (scrap_t *scrap); #endif//__QF_GLSL_textures_h diff --git a/include/QF/render.h b/include/QF/render.h index 7f02672e2..607b8b800 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -55,6 +55,15 @@ typedef enum { extern struct vid_render_funcs_s *r_funcs; extern struct vid_render_data_s *r_data; +typedef struct subpic_s { + const struct subpic_s *const next; + const struct scrap_s *const scrap; ///< renderer specific type + const struct vrect_s *const rect; + const int width; ///< requested width + const int height; ///< requested height + const float size; ///< size factor for tex coords (mult) +} subpic_t; + // dynamic lights =========================================================== typedef struct dlight_s diff --git a/include/r_scrap.h b/include/r_scrap.h new file mode 100644 index 000000000..5539d7480 --- /dev/null +++ b/include/r_scrap.h @@ -0,0 +1,49 @@ +/* + r_scrap.h + + Renderer agnostic scrap management + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/1/12 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __r_scrap_h +#define __r_scrap_h + +typedef struct rscrap_s { + struct vrect_s *free_rects; ///< linked list of free areas + struct vrect_s *rects; ///< linked list of allocated rects + int width; ///< overall width of scrap + int height; ///< overall height of scrap +} rscrap_t; + +void R_ScrapInit (rscrap_t *scrap, int width, int height); +void R_ScrapDelete (rscrap_t *scrap); +struct vrect_s *R_ScrapAlloc (rscrap_t *scrap, int width, int height); +void R_ScrapFree (rscrap_t *scrap, struct vrect_s *rect); +void R_ScrapClear (rscrap_t *scrap); +size_t R_ScrapArea (rscrap_t *scrap) __attribute__((pure)); +void R_ScrapDump (rscrap_t *scrap); + +#endif//__r_scrap_h diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 3e5dd4f70..05740af60 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -37,6 +37,7 @@ libs_video_renderer_libQFrenderer_la_DEPENDENCIES= $(renderer_libs) libs_video_renderer_libQFrenderer_la_SOURCES=\ libs/video/renderer/r_cvar.c \ libs/video/renderer/r_init.c \ + libs/video/renderer/r_scrap.c \ libs/video/renderer/r_screen.c \ libs/video/renderer/r_progs.c diff --git a/libs/video/renderer/glsl/glsl_textures.c b/libs/video/renderer/glsl/glsl_textures.c index 8130dfdf5..1edd77b71 100644 --- a/libs/video/renderer/glsl/glsl_textures.c +++ b/libs/video/renderer/glsl/glsl_textures.c @@ -44,6 +44,7 @@ #include "QF/cmd.h" #include "QF/mathlib.h" #include "QF/model.h" +#include "QF/render.h" #include "QF/sys.h" #include "QF/vrect.h" @@ -51,15 +52,15 @@ #include "QF/GLSL/funcs.h" #include "QF/GLSL/qf_textures.h" +#include "r_scrap.h" + struct scrap_s { + rscrap_t rscrap; GLuint tnum; - int size; // in pixels, for now, always square, power of 2 int format; int bpp; byte *data; // local copy of the texture so updates can be batched vrect_t *batch; - vrect_t *free_rects; - vrect_t *rects; subpic_t *subpics; struct scrap_s *next; }; @@ -248,23 +249,22 @@ static void glsl_scraps_f (void) { scrap_t *scrap; - vrect_t *rect; int area; + int size; if (!scrap_list) { Sys_Printf ("No scraps\n"); return; } for (scrap = scrap_list; scrap; scrap = scrap->next) { - for (rect = scrap->free_rects, area = 0; rect; rect = rect->next) - area += rect->width * rect->height; + area = R_ScrapArea (&scrap->rscrap); + // always square + size = scrap->rscrap.width; Sys_Printf ("tnum=%u size=%d format=%04x bpp=%d free=%d%%\n", - scrap->tnum, scrap->size, scrap->format, scrap->bpp, - area * 100 / (scrap->size * scrap->size)); + scrap->tnum, size, scrap->format, scrap->bpp, + area * 100 / (size * size)); if (Cmd_Argc () > 1) { - for (rect = scrap->rects, area = 0; rect; rect = rect->next) - Sys_Printf ("%d %d %d %d\n", rect->x, rect->y, - rect->width, rect->height); + R_ScrapDump (&scrap->rscrap); } } } @@ -309,11 +309,9 @@ GLSL_CreateScrap (int size, int format, int linear) } scrap = malloc (sizeof (scrap_t)); qfeglGenTextures (1, &scrap->tnum); - scrap->size = size; + R_ScrapInit (&scrap->rscrap, size, size); scrap->format = format; scrap->bpp = bpp; - scrap->free_rects = VRect_New (0, 0, size, size); - scrap->rects = 0; scrap->subpics = 0; scrap->next = scrap_list; scrap_list = scrap; @@ -341,26 +339,13 @@ GLSL_CreateScrap (int size, int format, int linear) void GLSL_ScrapClear (scrap_t *scrap) { - vrect_t *t; subpic_t *sp; - - while (scrap->free_rects) { - t = scrap->free_rects; - scrap->free_rects = t->next; - VRect_Delete (t); - } - while (scrap->rects) { - t = scrap->rects; - scrap->rects = t->next; - VRect_Delete (t); - } while (scrap->subpics) { sp = scrap->subpics; scrap->subpics = (subpic_t *) sp->next; free (sp); } - - scrap->free_rects = VRect_New (0, 0, scrap->size, scrap->size); + R_ScrapClear (&scrap->rscrap); } void @@ -375,7 +360,7 @@ GLSL_DestroyScrap (scrap_t *scrap) } } GLSL_ScrapClear (scrap); - VRect_Delete (scrap->free_rects); + R_ScrapDelete (&scrap->rscrap); GLSL_ReleaseTexture (scrap->tnum); free (scrap->data); free (scrap); @@ -390,47 +375,13 @@ GLSL_ScrapTexture (scrap_t *scrap) subpic_t * GLSL_ScrapSubpic (scrap_t *scrap, int width, int height) { - int i, w, h; - vrect_t **t, **best; - vrect_t *old, *frags, *rect; + vrect_t *rect; subpic_t *subpic; - for (i = 0; i < 16; i++) - if (width <= (1 << i)) - break; - w = 1 << i; - for (i = 0; i < 16; i++) - if (height <= (1 << i)) - break; - h = 1 << i; - - best = 0; - for (t = &scrap->free_rects; *t; t = &(*t)->next) { - if ((*t)->width < w || (*t)->height < h) - continue; // won't fit - if (!best) { - best = t; - continue; - } - if ((*t)->width <= (*best)->width || (*t)->height <= (*best)->height) - best = t; + rect = R_ScrapAlloc (&scrap->rscrap, width, height); + if (!rect) { + return 0; } - if (!best) - return 0; // couldn't find a spot - old = *best; - *best = old->next; - rect = VRect_New (old->x, old->y, w, h); - frags = VRect_Difference (old, rect); - VRect_Delete (old); - if (frags) { - // old was bigger than the requested size - for (old = frags; old->next; old = old->next) - ; - old->next = scrap->free_rects; - scrap->free_rects = frags; - } - rect->next = scrap->rects; - scrap->rects = rect; subpic = malloc (sizeof (subpic_t)); *((subpic_t **) &subpic->next) = scrap->subpics; @@ -439,7 +390,7 @@ GLSL_ScrapSubpic (scrap_t *scrap, int width, int height) *((vrect_t **) &subpic->rect) = rect; *((int *) &subpic->width) = width; *((int *) &subpic->height) = height; - *((float *) &subpic->size) = 1.0 / scrap->size; + *((float *) &subpic->size) = 1.0 / scrap->rscrap.width; return subpic; } @@ -448,8 +399,6 @@ GLSL_SubpicDelete (subpic_t *subpic) { scrap_t *scrap = (scrap_t *) subpic->scrap; vrect_t *rect = (vrect_t *) subpic->rect; - vrect_t *old, *merge; - vrect_t **t; subpic_t **sp; for (sp = &scrap->subpics; *sp; sp = (subpic_t **) &(*sp)->next) @@ -459,29 +408,7 @@ GLSL_SubpicDelete (subpic_t *subpic) Sys_Error ("GLSL_ScrapDelSubpic: broken subpic"); *sp = (subpic_t *) subpic->next; free (subpic); - for (t = &scrap->rects; *t; t = &(*t)->next) - if (*t == rect) - break; - if (*t != rect) - Sys_Error ("GLSL_ScrapDelSubpic: broken subpic"); - *t = rect->next; - - do { - merge = 0; - for (t = &scrap->free_rects; *t; t = &(*t)->next) { - merge = VRect_Merge (*t, rect); - if (merge) { - old = *t; - *t = (*t)->next; - VRect_Delete (old); - VRect_Delete (rect); - rect = merge; - break; - } - } - } while (merge); - rect->next = scrap->free_rects; - scrap->free_rects = rect; + R_ScrapFree (&scrap->rscrap, rect); } void @@ -502,7 +429,7 @@ GLSL_SubpicUpdate (subpic_t *subpic, byte *data, int batch) scrap->batch = VRect_New (rect->x, rect->y, rect->width, rect->height); } - step = scrap->size * scrap->bpp; + step = scrap->rscrap.width * scrap->bpp; sbytes = subpic->width * scrap->bpp; dest = scrap->data + rect->y * step + rect->x * scrap->bpp; for (i = 0; i < subpic->height; i++, dest += step, data += sbytes) @@ -519,6 +446,7 @@ void GLSL_ScrapFlush (scrap_t *scrap) { vrect_t *rect = scrap->batch; + int size = scrap->rscrap.width; if (!rect) return; @@ -526,9 +454,9 @@ GLSL_ScrapFlush (scrap_t *scrap) //should update to not update the entire horizontal block qfeglBindTexture (GL_TEXTURE_2D, scrap->tnum); qfeglTexSubImage2D (GL_TEXTURE_2D, 0, 0, rect->y, - scrap->size, rect->height, scrap->format, + size, rect->height, scrap->format, GL_UNSIGNED_BYTE, - scrap->data + rect->y * scrap->size * scrap->bpp); + scrap->data + rect->y * size * scrap->bpp); VRect_Delete (rect); scrap->batch = 0; } diff --git a/libs/video/renderer/r_init.c b/libs/video/renderer/r_init.c index f298538ba..733004a21 100644 --- a/libs/video/renderer/r_init.c +++ b/libs/video/renderer/r_init.c @@ -46,6 +46,7 @@ #include "QF/plugin/general.h" #include "r_internal.h" +#include "r_scrap.h" #include "vid_internal.h" cvar_t *vidrend_plugin; @@ -61,6 +62,7 @@ vid_render_funcs_t *r_funcs; #define U __attribute__ ((used)) static U void (*const r_progs_init)(struct progs_s *) = R_Progs_Init; +static U void (*const r_scrapdelete)(rscrap_t *) = R_ScrapDelete; #undef U static void diff --git a/libs/video/renderer/r_scrap.c b/libs/video/renderer/r_scrap.c new file mode 100644 index 000000000..86a4ca0a6 --- /dev/null +++ b/libs/video/renderer/r_scrap.c @@ -0,0 +1,183 @@ +/* + r_scrap.c + + Renderer agnostic scrap management + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/1/12 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "QF/sys.h" +#include "QF/vrect.h" + +#include "compat.h" +#include "r_scrap.h" + +static unsigned +pow2rup (unsigned x) +{ + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + return x; +} + +VISIBLE void +R_ScrapInit (rscrap_t *scrap, int width, int height) +{ + width = pow2rup (width); + height = pow2rup (height); + scrap->width = width; + scrap->height = height; + scrap->rects = 0; + scrap->free_rects = VRect_New (0, 0, width, height); +} + +VISIBLE void +R_ScrapDelete (rscrap_t *scrap) +{ + R_ScrapClear (scrap); + VRect_Delete (scrap->free_rects); +} + +VISIBLE vrect_t * +R_ScrapAlloc (rscrap_t *scrap, int width, int height) +{ + int w, h; + vrect_t **t, **best; + vrect_t *old, *frags, *rect; + + w = pow2rup (width); + h = pow2rup (height); + + best = 0; + for (t = &scrap->free_rects; *t; t = &(*t)->next) { + if ((*t)->width < w || (*t)->height < h) + continue; // won't fit + if (!best) { + best = t; + continue; + } + if ((*t)->width <= (*best)->width || (*t)->height <= (*best)->height) + best = t; + } + if (!best) + return 0; // couldn't find a spot + old = *best; + *best = old->next; + rect = VRect_New (old->x, old->y, w, h); + frags = VRect_Difference (old, rect); + VRect_Delete (old); + if (frags) { + // old was bigger than the requested size + for (old = frags; old->next; old = old->next) + ; + old->next = scrap->free_rects; + scrap->free_rects = frags; + } + rect->next = scrap->rects; + scrap->rects = rect; + + return rect; +} + +VISIBLE void +R_ScrapFree (rscrap_t *scrap, vrect_t *rect) +{ + vrect_t *old, *merge; + vrect_t **t; + + for (t = &scrap->rects; *t; t = &(*t)->next) + if (*t == rect) + break; + if (*t != rect) + Sys_Error ("R_ScrapFree: broken rect"); + *t = rect->next; + + do { + merge = 0; + for (t = &scrap->free_rects; *t; t = &(*t)->next) { + merge = VRect_Merge (*t, rect); + if (merge) { + old = *t; + *t = (*t)->next; + VRect_Delete (old); + VRect_Delete (rect); + rect = merge; + break; + } + } + } while (merge); + rect->next = scrap->free_rects; + scrap->free_rects = rect; +} + +VISIBLE void +R_ScrapClear (rscrap_t *scrap) +{ + vrect_t *t; + + while (scrap->free_rects) { + t = scrap->free_rects; + scrap->free_rects = t->next; + VRect_Delete (t); + } + while (scrap->rects) { + t = scrap->rects; + scrap->rects = t->next; + VRect_Delete (t); + } + + scrap->free_rects = VRect_New (0, 0, scrap->width, scrap->height); +} + +VISIBLE size_t +R_ScrapArea (rscrap_t *scrap) +{ + vrect_t *rect; + size_t area; + + for (rect = scrap->free_rects, area = 0; rect; rect = rect->next) { + area += rect->width * rect->height; + } + return area; +} + +VISIBLE void +R_ScrapDump (rscrap_t *scrap) +{ + vrect_t *rect; + + for (rect = scrap->rects; rect; rect = rect->next) { + Sys_Printf ("%d %d %d %d\n", rect->x, rect->y, + rect->width, rect->height); + } +} From a7ac188d1d1808c34f58be980bf9804659f24e30 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 13 Jan 2021 10:43:23 +0900 Subject: [PATCH 225/435] [vulkan] Use a scrap texture for draw The scrap texture did very good things for the glsl renderer and the better control over data copying might help it do even better things for vulkan, especially with lots of little icons. --- include/QF/Vulkan/command.h | 6 + include/QF/Vulkan/staging.h | 2 + include/QF/Vulkan/texture.h | 43 ++++ libs/video/renderer/Makemodule.am | 1 + libs/video/renderer/vulkan/staging.c | 13 + libs/video/renderer/vulkan/texture.c | 299 +++++++++++++++++++++++ libs/video/renderer/vulkan/vulkan_draw.c | 90 ++----- 7 files changed, 390 insertions(+), 64 deletions(-) create mode 100644 include/QF/Vulkan/texture.h create mode 100644 libs/video/renderer/vulkan/texture.c diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index 046c8b2b3..925a63781 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -12,6 +12,12 @@ typedef struct qfv_semaphoreset_s typedef struct qfv_fenceset_s DARRAY_TYPE (VkFence) qfv_fenceset_t; +typedef struct qfv_bufferimagecopy_s + DARRAY_TYPE (VkBufferImageCopy) qfv_bufferimagecopy_t; + +#define QFV_AllocBufferImageCopy(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_bufferimagecopy_t, num, allocator) + struct qfv_queue_s; struct qfv_device_s; VkCommandPool QFV_CreateCommandPool (struct qfv_device_s *device, diff --git a/include/QF/Vulkan/staging.h b/include/QF/Vulkan/staging.h index d281f1854..9a90edd6e 100644 --- a/include/QF/Vulkan/staging.h +++ b/include/QF/Vulkan/staging.h @@ -6,6 +6,7 @@ typedef struct qfv_stagebuf_s { VkBuffer buffer; VkDeviceMemory memory; size_t size; + size_t offset; ///< for batching building void *data; } qfv_stagebuf_t; @@ -14,5 +15,6 @@ qfv_stagebuf_t *QFV_CreateStagingBuffer (struct qfv_device_s *device, size_t size); void QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage); void QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size); +void *QFV_ClaimStagingBuffer (qfv_stagebuf_t *stage, size_t size); #endif//__QF_Vulkan_staging_h diff --git a/include/QF/Vulkan/texture.h b/include/QF/Vulkan/texture.h new file mode 100644 index 000000000..6a55815f6 --- /dev/null +++ b/include/QF/Vulkan/texture.h @@ -0,0 +1,43 @@ +#ifndef __QF_Vulkan_texture_h +#define __QF_Vulkan_texture_h + +typedef enum { + QFV_LUMINANCE, + QFV_LUMINANCE_ALPHA, + QFV_RGB, + QFV_RGBA, +} QFVFormat; + +typedef struct scrap_s scrap_t; + +scrap_t *QFV_CreateScrap (struct qfv_device_s *device, int size, + QFVFormat format); +void QFV_ScrapClear (scrap_t *scrap); +void QFV_DestroyScrap (scrap_t *scrap); +VkImageView QFV_ScrapImageView (scrap_t *scrap) __attribute__((pure)); +subpic_t *QFV_ScrapSubpic (scrap_t *scrap, int width, int height); +void QFV_SubpicDelete (subpic_t *subpic); + +/** Add an update region to the batch queue. + * + * The region to be updated is recorded in the batch queue, space allocated + * in the staging buffer, and a pointer to the allocated space is returned. + * + * \note No data is stransfered. This facilitates writing generated data + * directly to the staging buffer. + */ +void *QFV_SubpicBatch (subpic_t *subpic, struct qfv_stagebuf_s *stage); + +/** Flush all batched subpic updates. + * + * The offset in the staging bufffer \a stage is reset to 0. The command + * buffer is populated with the appropriate image layout barriers and the + * necessary copy commands. + * + * \note The command buffer is neither begun nor ended, nor is it submitted + * to a queue. This is to maximize flexibility in command buffer usage. + */ +void QFV_ScrapFlush (scrap_t *scrap, struct qfv_stagebuf_s *stage, + VkCommandBuffer cmd); + +#endif//__QF_Vulkan_texture_h diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 05740af60..6f306ffe5 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -230,6 +230,7 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/shader.c \ libs/video/renderer/vulkan/staging.c \ libs/video/renderer/vulkan/swapchain.c \ + libs/video/renderer/vulkan/texture.c \ libs/video/renderer/vulkan/util.c \ libs/video/renderer/vulkan/util.h \ libs/video/renderer/vulkan/vkparse.c \ diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c index de791239c..04e3897db 100644 --- a/libs/video/renderer/vulkan/staging.c +++ b/libs/video/renderer/vulkan/staging.c @@ -59,6 +59,8 @@ QFV_CreateStagingBuffer (qfv_device_t *device, size_t size) qfv_devfuncs_t *dfunc = device->funcs; qfv_stagebuf_t *stage = malloc (sizeof (qfv_stagebuf_t)); + stage->size = size; + stage->offset = 0; stage->device = device; stage->buffer = QFV_CreateBuffer (device, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); @@ -94,3 +96,14 @@ QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size) }; dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); } + +void * +QFV_ClaimStagingBuffer (qfv_stagebuf_t *stage, size_t size) +{ + if (stage->offset + size > stage->size) { + return 0; + } + void *data = (byte *) stage->data + stage->offset; + stage->offset += (size + 3) & ~3; + return data; +} diff --git a/libs/video/renderer/vulkan/texture.c b/libs/video/renderer/vulkan/texture.c new file mode 100644 index 000000000..6529800b1 --- /dev/null +++ b/libs/video/renderer/vulkan/texture.c @@ -0,0 +1,299 @@ +/* + texuture.c + + Vulkan texuture manager + + Copyright (C) 2021 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/qfplist.h" +#include "QF/quakefs.h" +#include "QF/render.h" +#include "QF/sys.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/staging.h" +#include "QF/Vulkan/texture.h" + +#include "r_scrap.h" +#include "vid_vulkan.h" + +struct scrap_s { + rscrap_t rscrap; + VkImage image; + VkDeviceMemory memory; + VkImageView view; + size_t bpp; + vrect_t *batch; + vrect_t **batch_tail; + vrect_t *batch_free; + size_t batch_count; + subpic_t *subpics; + qfv_device_t *device; +}; + +scrap_t * +QFV_CreateScrap (qfv_device_t *device, int size, QFVFormat format) +{ + int bpp = 0; + VkFormat fmt = VK_FORMAT_UNDEFINED; + + switch (format) { + case QFV_LUMINANCE: + bpp = 1; + fmt = VK_FORMAT_R8_UNORM; + break; + case QFV_LUMINANCE_ALPHA: + bpp = 2; + fmt = VK_FORMAT_R8G8_UNORM; + break; + case QFV_RGB: + bpp = 3; + fmt = VK_FORMAT_R8G8B8_UNORM; + break; + case QFV_RGBA: + bpp = 4; + fmt = VK_FORMAT_R8G8B8A8_UNORM; + break; + } + + scrap_t *scrap = malloc (sizeof (scrap_t)); + + R_ScrapInit (&scrap->rscrap, size, size); + + // R_ScrapInit rounds sizes up to next power of 2 + size = scrap->rscrap.width; + VkExtent3D extent = { size, size, 1 }; + scrap->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, fmt, + extent, 1, 1, VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT); + scrap->memory = QFV_AllocImageMemory (device, scrap->image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, 0); + QFV_BindImageMemory (device, scrap->image, scrap->memory, 0); + scrap->view = QFV_CreateImageView (device, scrap->image, + VK_IMAGE_VIEW_TYPE_2D, fmt, + VK_IMAGE_ASPECT_COLOR_BIT); + scrap->bpp = bpp; + scrap->subpics = 0; + scrap->device = device; + scrap->batch = 0; + scrap->batch_tail = &scrap->batch; + scrap->batch_free = 0; + scrap->batch_count = 0; + return scrap; +} + +void +QFV_ScrapClear (scrap_t *scrap) +{ + subpic_t *sp; + while (scrap->subpics) { + sp = scrap->subpics; + scrap->subpics = (subpic_t *) sp->next; + free (sp); + } + R_ScrapClear (&scrap->rscrap); +} + +void +QFV_DestroyScrap (scrap_t *scrap) +{ + qfv_device_t *device = scrap->device; + qfv_devfuncs_t *dfunc = device->funcs; + + QFV_ScrapClear (scrap); + R_ScrapDelete (&scrap->rscrap); + dfunc->vkDestroyImageView (device->dev, scrap->view, 0); + dfunc->vkDestroyImage (device->dev, scrap->image, 0); + dfunc->vkFreeMemory (device->dev, scrap->memory, 0); + + while (scrap->batch_free) { + vrect_t *b = scrap->batch_free; + scrap->batch_free = b->next; + VRect_Delete (b); + } + free (scrap); +} + +VkImageView +QFV_ScrapImageView (scrap_t *scrap) +{ + return scrap->view; +} + +subpic_t * +QFV_ScrapSubpic (scrap_t *scrap, int width, int height) +{ + vrect_t *rect; + subpic_t *subpic; + + rect = R_ScrapAlloc (&scrap->rscrap, width, height); + if (!rect) { + return 0; + } + + subpic = malloc (sizeof (subpic_t)); + *((subpic_t **) &subpic->next) = scrap->subpics; + scrap->subpics = subpic; + *((scrap_t **) &subpic->scrap) = scrap; + *((vrect_t **) &subpic->rect) = rect; + *((int *) &subpic->width) = width; + *((int *) &subpic->height) = height; + *((float *) &subpic->size) = 1.0 / scrap->rscrap.width; + return subpic; +} + +void +QFV_SubpicDelete (subpic_t *subpic) +{ + scrap_t *scrap = (scrap_t *) subpic->scrap; + vrect_t *rect = (vrect_t *) subpic->rect; + subpic_t **sp; + + for (sp = &scrap->subpics; *sp; sp = (subpic_t **) &(*sp)->next) { + if (*sp == subpic) { + break; + } + } + if (*sp != subpic) { + Sys_Error ("QFV_SubpicDelete: broken subpic"); + } + *sp = (subpic_t *) subpic->next; + free (subpic); + R_ScrapFree (&scrap->rscrap, rect); +} + +void * +QFV_SubpicBatch (subpic_t *subpic, qfv_stagebuf_t *stage) +{ + scrap_t *scrap = (scrap_t *) subpic->scrap; + vrect_t *rect = (vrect_t *) subpic->rect; + vrect_t *batch; + byte *dest; + size_t size; + + size = subpic->width * subpic->height * scrap->bpp; + if (!(dest = QFV_ClaimStagingBuffer (stage, size))) { + return 0; + } + + if (scrap->batch_free) { + batch = scrap->batch_free; + scrap->batch_free = batch->next; + } else { + batch = VRect_New (rect->x, rect->y, subpic->width, subpic->height); + } + *scrap->batch_tail = batch; + scrap->batch_tail = &batch->next; + batch->next = 0; + scrap->batch_count++; + return dest; +} + +void +QFV_ScrapFlush (scrap_t *scrap, qfv_stagebuf_t *stage, VkCommandBuffer cmd) +{ + qfv_device_t *device = scrap->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (!scrap->batch_count) { + return; + } + + size_t i; + __auto_type copy = QFV_AllocBufferImageCopy (128, alloca); + memset (copy->a, 0, 128 * sizeof (copy->a[0])); + + for (i = 0; i < scrap->batch_count && i < 128; i++) { + copy->a[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copy->a[i].imageSubresource.layerCount = 1; + copy->a[i].imageExtent.depth = 1; + } + + QFV_FlushStagingBuffer (stage, 0, stage->offset); + + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.image = scrap->image; + dfunc->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, + 1, &barrier); + + size_t offset = 0, size; + vrect_t *batch = scrap->batch; + while (scrap->batch_count) { + for (i = 0; i < scrap->batch_count && i < 128; i++) { + size = batch->width * batch->height * scrap->bpp; + + copy->a[i].bufferOffset = offset; + copy->a[i].imageOffset.x = batch->x; + copy->a[i].imageOffset.y = batch->y; + copy->a[i].imageExtent.width = batch->width; + copy->a[i].imageExtent.height = batch->height; + + offset += (size + 3) & ~3; + batch = batch->next; + } + dfunc->vkCmdCopyBufferToImage (cmd, stage->buffer, scrap->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + i, copy->a); + scrap->batch_count -= i; + } + + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = scrap->image; + dfunc->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, + 1, &barrier); + + *scrap->batch_tail = scrap->batch_free; + scrap->batch_free = scrap->batch; + scrap->batch = 0; + scrap->batch_tail = &scrap->batch; + stage->offset = 0; +} diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 89ead5380..badc01332 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -46,6 +46,7 @@ #include "QF/dstring.h" #include "QF/hash.h" #include "QF/quakefs.h" +#include "QF/render.h" #include "QF/sys.h" #include "QF/vid.h" @@ -59,6 +60,7 @@ #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/staging.h" +#include "QF/Vulkan/texture.h" #include "r_internal.h" #include "vid_vulkan.h" @@ -75,10 +77,9 @@ typedef struct { #define INDS_PER_QUAD (5) // one per vert plus primitive reset //FIXME move into a context struct -VkImage conchars_image; -VkDeviceMemory conchars_memory; -VkImageView conchars_view; VkSampler conchars_sampler; +scrap_t *draw_scrap; +subpic_t *conchars; VkBuffer quad_vert_buffer; VkBuffer quad_ind_buffer; @@ -201,9 +202,7 @@ Vulkan_Draw_Shutdown (vulkan_ctx_t *ctx) destroy_quad_buffers (ctx); dfunc->vkDestroyPipeline (device->dev, twod_pipeline, 0); - dfunc->vkDestroyImageView (device->dev, conchars_view, 0); - dfunc->vkFreeMemory (device->dev, conchars_memory, 0); - dfunc->vkDestroyImage (device->dev, conchars_image, 0); + QFV_DestroyScrap (draw_scrap); } void @@ -214,37 +213,24 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) VkCommandBuffer cmd = ctx->cmdbuffer; create_quad_buffers (ctx); - - qpic_t *charspic = Draw_Font8x8Pic (); - VkExtent3D extent = { charspic->width, charspic->height, 1 }; - conchars_image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, - VK_FORMAT_A1R5G5B5_UNORM_PACK16, - extent, 1, 1, - VK_SAMPLE_COUNT_1_BIT, - VK_IMAGE_USAGE_TRANSFER_DST_BIT - | VK_IMAGE_USAGE_TRANSFER_SRC_BIT - | VK_IMAGE_USAGE_SAMPLED_BIT); - conchars_memory = QFV_AllocImageMemory (device, conchars_image, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - 0, 0); - QFV_BindImageMemory (device, conchars_image, conchars_memory, 0); - conchars_view = QFV_CreateImageView (device, conchars_image, - VK_IMAGE_VIEW_TYPE_2D, - VK_FORMAT_A1R5G5B5_UNORM_PACK16, - VK_IMAGE_ASPECT_COLOR_BIT); + draw_scrap = QFV_CreateScrap (device, 2048, QFV_RGBA); conchars_sampler = QFV_GetSampler (ctx, "quakepic"); - uint16_t *chars_data = ctx->staging[0]->data; + qpic_t *charspic = Draw_Font8x8Pic (); + + conchars = QFV_ScrapSubpic (draw_scrap, charspic->width, charspic->height); + + byte *chars_data = QFV_SubpicBatch (conchars, ctx->staging[0]); size_t size = charspic->width * charspic->height; for (size_t i = 0; i < size; i++) { - // convert 0xff = transparent, 0xfe = white to 0x0000 and 0xffff - // for a1r5g5b5 - uint16_t pix = (charspic->data[i] & 1) - 1; - chars_data[i] = pix; + byte pix = charspic->data[i]; + byte *col = vid.palette + pix * 3; + *chars_data++ = *col++; + *chars_data++ = *col++; + *chars_data++ = *col++; + *chars_data++ = (pix == 255) - 1; } - QFV_FlushStagingBuffer (ctx->staging[0], 0, size * sizeof (uint16_t)); - VkImageMemoryBarrier barrier; - qfv_pipelinestagepair_t stages; + dfunc->vkWaitForFences (device->dev, 1, &ctx->fence, VK_TRUE, ~0ull); dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferBeginInfo beginInfo = { @@ -252,33 +238,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0, }; dfunc->vkBeginCommandBuffer (cmd, &beginInfo); - - stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; - barrier=imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; - barrier.image = conchars_image; - dfunc->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, - 0, 0, - 0, 0, - 1, &barrier); - - VkBufferImageCopy region = { - 0, 0, 0, - { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }, - { 0, 0, 0 }, - { charspic->width, charspic->height, 1 }, - }; - dfunc->vkCmdCopyBufferToImage (cmd, - ctx->staging[0]->buffer, conchars_image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, ®ion); - - stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; - barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; - barrier.image = conchars_image; - dfunc->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, - 0, 0, - 0, 0, - 1, &barrier); + QFV_ScrapFlush (draw_scrap, ctx->staging[0], cmd); dfunc->vkEndCommandBuffer (cmd); VkSubmitInfo submitInfo = { @@ -305,7 +265,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) }; VkDescriptorImageInfo imageInfo = { conchars_sampler, - conchars_view, + QFV_ScrapImageView (draw_scrap), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; __auto_type cmdBuffers @@ -347,10 +307,12 @@ draw_pic (float x, float y, int w, int h, qpic_t *pic, drawvert_t *verts = quad_verts + num_quads * VERTS_PER_QUAD; num_quads += VERTS_PER_QUAD; - float sl = (srcx + 0.03125) / 128.0; - float sr = (srcx + srcw - 0.03125) / 128.0; - float st = (srcy + 0.03125) / 128.0; - float sb = (srcy + srch - 0.03125) / 128.0; + //FIXME extract subpic from pic + float size = conchars->size; + float sl = (srcx + 0.03125) * size; + float sr = (srcx + srcw - 0.03125) * size; + float st = (srcy + 0.03125) * size; + float sb = (srcy + srch - 0.03125) * size; verts[0].xy[0] = x; verts[0].xy[1] = y; From eebf3158facf24b268e07be68e764aa69290cd45 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 13 Jan 2021 15:24:50 +0900 Subject: [PATCH 226/435] [ruamoko] Check for null when allocating objects It's difficult for progs to check for errors when the engine crashes out from underneath them :P --- libs/ruamoko/rua_obj.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index 155124b9f..8612cd6f0 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1700,12 +1700,14 @@ class_create_instance (progs_t *pr, pr_class_t *class) { int size = (class->instance_size + 1) * sizeof (pr_type_t); pr_type_t *mem; - pr_id_t *id; + pr_id_t *id = 0; mem = PR_Zone_TagMalloc (pr, size, class->name); - memset (mem, 0, size); - id = (pr_id_t *) (mem + 1); - id->class_pointer = PR_SetPointer (pr, class); + if (mem) { + memset (mem, 0, size); + id = (pr_id_t *) (mem + 1); + id->class_pointer = PR_SetPointer (pr, class); + } return id; } @@ -1832,9 +1834,11 @@ rua_object_copy (progs_t *pr) pr_id_t *id; id = class_create_instance (pr, class); - memcpy (id, object, sizeof (pr_type_t) * class->instance_size); - // copy the retain count - ((pr_type_t *) id)[-1] = ((pr_type_t *) object)[-1]; + if (id) { + memcpy (id, object, sizeof (pr_type_t) * class->instance_size); + // copy the retain count + ((pr_type_t *) id)[-1] = ((pr_type_t *) object)[-1]; + } RETURN_POINTER (pr, id); } From 41b366186966ae986637f82b44c172c855954f4b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 13 Jan 2021 15:28:56 +0900 Subject: [PATCH 227/435] [vulkan] Use the scrap for draw Draw now has its own staging buffer to use with its scrap. Also, a few fixes were needed for the staging buffer and scrap flush routines. Other than some synchronization issues with draw scrap flushing (currently worked around with a fence-wait) things seem to be working nicely. --- libs/video/renderer/vulkan/staging.c | 3 + libs/video/renderer/vulkan/texture.c | 4 + libs/video/renderer/vulkan/vulkan_draw.c | 116 +++++++++++++++-------- 3 files changed, 82 insertions(+), 41 deletions(-) diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c index 04e3897db..be181d00b 100644 --- a/libs/video/renderer/vulkan/staging.c +++ b/libs/video/renderer/vulkan/staging.c @@ -90,6 +90,9 @@ QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size) qfv_device_t *device = stage->device; qfv_devfuncs_t *dfunc = device->funcs; + size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; + offset &= ~(atom - 1); + size = (size + atom - 1) & ~ (atom - 1); VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, stage->memory, offset, size diff --git a/libs/video/renderer/vulkan/texture.c b/libs/video/renderer/vulkan/texture.c index 6529800b1..12fba3932 100644 --- a/libs/video/renderer/vulkan/texture.c +++ b/libs/video/renderer/vulkan/texture.c @@ -223,6 +223,10 @@ QFV_SubpicBatch (subpic_t *subpic, qfv_stagebuf_t *stage) if (scrap->batch_free) { batch = scrap->batch_free; scrap->batch_free = batch->next; + batch->x = rect->x; + batch->y = rect->y; + batch->width = subpic->width; + batch->height = subpic->height; } else { batch = VRect_New (rect->x, rect->y, subpic->width, subpic->height); } diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index badc01332..ba2d7c24c 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -79,7 +79,8 @@ typedef struct { //FIXME move into a context struct VkSampler conchars_sampler; scrap_t *draw_scrap; -subpic_t *conchars; +qfv_stagebuf_t *draw_stage; +qpic_t *conchars; VkBuffer quad_vert_buffer; VkBuffer quad_ind_buffer; @@ -146,15 +147,58 @@ destroy_quad_buffers (vulkan_ctx_t *ctx) dfunc->vkDestroyBuffer (device->dev, quad_ind_buffer, 0); } +static void +flush_draw_scrap (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + VkCommandBuffer cmd = ctx->cmdbuffer; + + dfunc->vkWaitForFences (device->dev, 1, &ctx->fence, VK_TRUE, ~0ull); + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + QFV_ScrapFlush (draw_scrap, draw_stage, cmd); + dfunc->vkEndCommandBuffer (cmd); + + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, + 0, 0, 0, + 1, &cmd, + 0, 0, + }; + dfunc->vkResetFences (device->dev, 1, &ctx->fence); + dfunc->vkQueueSubmit (device->queue.queue, 1, &submitInfo, ctx->fence); + dfunc->vkWaitForFences (device->dev, 1, &ctx->fence, VK_TRUE, ~0ull);//FIXME +} + static qpic_t * -pic_data (const char *name, int w, int h, const byte *data) +pic_data (const char *name, int w, int h, const byte *data, vulkan_ctx_t *ctx) { qpic_t *pic; + subpic_t *subpic; + byte *picdata; - pic = malloc (field_offset (qpic_t, data[w * h])); + pic = malloc (field_offset (qpic_t, data[sizeof (subpic_t)])); pic->width = w; pic->height = h; - memcpy (pic->data, data, pic->width * pic->height); + + subpic = QFV_ScrapSubpic (draw_scrap, w, h); + *(subpic_t **) pic->data = subpic; + + picdata = QFV_SubpicBatch (subpic, draw_stage); + size_t size = w * h; + for (size_t i = 0; i < size; i++) { + byte pix = *data++; + byte *col = vid.palette + pix * 3; + *picdata++ = *col++; + *picdata++ = *col++; + *picdata++ = *col++; + *picdata++ = (pix == 255) - 1; + } return pic; } @@ -162,7 +206,7 @@ qpic_t * Vulkan_Draw_MakePic (int width, int height, const byte *data, vulkan_ctx_t *ctx) { - return pic_data (0, width, height, data); + return pic_data (0, width, height, data, ctx); } void @@ -173,13 +217,18 @@ Vulkan_Draw_DestroyPic (qpic_t *pic, vulkan_ctx_t *ctx) qpic_t * Vulkan_Draw_PicFromWad (const char *name, vulkan_ctx_t *ctx) { - return pic_data (0, 1, 1, (const byte *)""); + qpic_t *wadpic = W_GetLumpName (name); + + if (!wadpic) { + return 0; + } + return pic_data (name, wadpic->width, wadpic->height, wadpic->data, ctx); } qpic_t * Vulkan_Draw_CachePic (const char *path, qboolean alpha, vulkan_ctx_t *ctx) { - return pic_data (0, 1, 1, (const byte *)""); + return pic_data (0, 1, 1, (const byte *)"", ctx); } void @@ -203,6 +252,7 @@ Vulkan_Draw_Shutdown (vulkan_ctx_t *ctx) dfunc->vkDestroyPipeline (device->dev, twod_pipeline, 0); QFV_DestroyScrap (draw_scrap); + QFV_DestroyStagingBuffer (draw_stage); } void @@ -210,45 +260,17 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - VkCommandBuffer cmd = ctx->cmdbuffer; create_quad_buffers (ctx); draw_scrap = QFV_CreateScrap (device, 2048, QFV_RGBA); + draw_stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024); conchars_sampler = QFV_GetSampler (ctx, "quakepic"); qpic_t *charspic = Draw_Font8x8Pic (); - conchars = QFV_ScrapSubpic (draw_scrap, charspic->width, charspic->height); + conchars = pic_data (0, charspic->width, charspic->height, charspic->data, ctx); - byte *chars_data = QFV_SubpicBatch (conchars, ctx->staging[0]); - size_t size = charspic->width * charspic->height; - for (size_t i = 0; i < size; i++) { - byte pix = charspic->data[i]; - byte *col = vid.palette + pix * 3; - *chars_data++ = *col++; - *chars_data++ = *col++; - *chars_data++ = *col++; - *chars_data++ = (pix == 255) - 1; - } - - dfunc->vkWaitForFences (device->dev, 1, &ctx->fence, VK_TRUE, ~0ull); - dfunc->vkResetCommandBuffer (cmd, 0); - VkCommandBufferBeginInfo beginInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0, - }; - dfunc->vkBeginCommandBuffer (cmd, &beginInfo); - QFV_ScrapFlush (draw_scrap, ctx->staging[0], cmd); - dfunc->vkEndCommandBuffer (cmd); - - VkSubmitInfo submitInfo = { - VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, - 0, 0, 0, - 1, &cmd, - 0, 0, - }; - dfunc->vkResetFences (device->dev, 1, &ctx->fence); - dfunc->vkQueueSubmit (device->queue.queue, 1, &submitInfo, ctx->fence); + flush_draw_scrap (ctx); twod_pipeline = Vulkan_CreatePipeline (ctx, "twod"); @@ -307,8 +329,11 @@ draw_pic (float x, float y, int w, int h, qpic_t *pic, drawvert_t *verts = quad_verts + num_quads * VERTS_PER_QUAD; num_quads += VERTS_PER_QUAD; - //FIXME extract subpic from pic - float size = conchars->size; + subpic_t *subpic = *(subpic_t **) pic->data; + srcx += subpic->rect->x; + srcy += subpic->rect->y; + + float size = subpic->size; float sl = (srcx + 0.03125) * size; float sr = (srcx + srcw - 0.03125) * size; float st = (srcy + 0.03125) * size; @@ -347,7 +372,7 @@ queue_character (int x, int y, byte chr, vulkan_ctx_t *ctx) cx = chr % 16; cy = chr / 16; - draw_pic (x, y, 8, 8, 0/*FIXME*/, cx * 8, cy * 8, 8, 8, color); + draw_pic (x, y, 8, 8, conchars, cx * 8, cy * 8, 8, 8, color); } void @@ -437,11 +462,17 @@ Vulkan_Draw_Crosshair (vulkan_ctx_t *ctx) void Vulkan_Draw_Pic (int x, int y, qpic_t *pic, vulkan_ctx_t *ctx) { + static quat_t color = { 1, 1, 1, 1}; + draw_pic (x, y, pic->width, pic->height, pic, + 0, 0, pic->width, pic->height, color); } void Vulkan_Draw_Picf (float x, float y, qpic_t *pic, vulkan_ctx_t *ctx) { + static quat_t color = { 1, 1, 1, 1}; + draw_pic (x, y, pic->width, pic->height, pic, + 0, 0, pic->width, pic->height, color); } void @@ -494,6 +525,9 @@ Vulkan_DrawReset (vulkan_ctx_t *ctx) void Vulkan_FlushText (vulkan_ctx_t *ctx) { + if (draw_stage->offset) { + flush_draw_scrap (ctx); + } qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; __auto_type frame = &ctx->framebuffers.a[ctx->curFrame]; From 1205c935d00329ae5ae4f3f1e6373a74eaea8ce0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 13 Jan 2021 16:47:49 +0900 Subject: [PATCH 228/435] [qfcc] Add failing test for static init The function local static init is being treated as a non-static init (ie, initialized each call). --- tools/qfcc/test/Makemodule.am | 11 +++++++++++ tools/qfcc/test/static-init.r | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tools/qfcc/test/static-init.r diff --git a/tools/qfcc/test/Makemodule.am b/tools/qfcc/test/Makemodule.am index 3eb33892b..f328fcb6e 100644 --- a/tools/qfcc/test/Makemodule.am +++ b/tools/qfcc/test/Makemodule.am @@ -36,6 +36,7 @@ test_progs_dat=\ tools/qfcc/test/return-ivar.dat \ tools/qfcc/test/sendv.dat \ tools/qfcc/test/state.dat \ + tools/qfcc/test/static-init.dat \ tools/qfcc/test/struct-init-param.dat \ tools/qfcc/test/struct-nil-init.dat \ tools/qfcc/test/structarray.dat \ @@ -411,6 +412,16 @@ tools/qfcc/test/state.run: $(qfcc_test_run_deps) include $(state_dep) # am--include-marker r_depfiles_remade += $(state_dep) +tools_qfcc_test_static_init_dat_SOURCES=tools/qfcc/test/static-init.r +static_init_obj=$(tools_qfcc_test_static_init_dat_SOURCES:.r=.o) +static_init_dep=$(call qcautodep,$(tools_qfcc_test_static_init_dat_SOURCES)) +tools/qfcc/test/static-init.dat$(EXEEXT): $(static_init_obj) $(QFCC_DEP) + $(V_QFCCLD)$(QLINK) -o $@ $(static_init_obj) +tools/qfcc/test/static-init.run: $(qfcc_test_run_deps) + @$(top_srcdir)/tools/qfcc/test/build-run $@ +include $(static_init_dep) # am--include-marker +r_depfiles_remade += $(static_init_dep) + tools_qfcc_test_struct_init_param_dat_SOURCES=tools/qfcc/test/struct-init-param.r struct_init_param_obj=$(tools_qfcc_test_struct_init_param_dat_SOURCES:.r=.o) struct_init_param_dep=$(call qcautodep,$(tools_qfcc_test_struct_init_param_dat_SOURCES)) diff --git a/tools/qfcc/test/static-init.r b/tools/qfcc/test/static-init.r new file mode 100644 index 000000000..bbbe3f9a7 --- /dev/null +++ b/tools/qfcc/test/static-init.r @@ -0,0 +1,19 @@ +#include "test-harness.h" + +int count_down () +{ + static int count = 2; + count--; + return count > 0; +} + +int main() +{ + int ret = 0; + count_down (); + if (count_down ()) { + printf ("did not reach 0\n"); + ret |= 1; + } + return ret; +} From c7da999b6a956c24b3df8173c2fc4c8b974be6ad Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 13 Jan 2021 18:08:30 +0900 Subject: [PATCH 229/435] [qfcc] Use local_expr only for local variables ie, not function-scope static variables. --- tools/qfcc/source/def.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 1fb204a67..d3299a0ab 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -597,7 +597,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, error (init, "type mismatch in initializer"); return; } - if (local_expr) { + if (storage == sc_local && local_expr) { sym->s.def->initialized = 1; init = assign_expr (new_symbol_expr (sym), init); // fold_constants takes care of int/float conversions From cef81741ebd1d0d3be9997d41998ba5c08fcf3b2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 14 Jan 2021 00:44:34 +0900 Subject: [PATCH 230/435] [vulkan] Implement most of the 2D renderer The console background is missing, and scaled vs unscaled (currently always scaled) 2d, but otherwise everything seems to work. Lots of places to clean up, though. --- libs/video/renderer/vulkan/qfpipeline.plist | 10 +-- libs/video/renderer/vulkan/twod.frag | 2 - libs/video/renderer/vulkan/vulkan_draw.c | 85 ++++++++++++++++++++- 3 files changed, 89 insertions(+), 8 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index a291ddf09..385713c80 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -168,19 +168,19 @@ depthStencil = { depthTestEnable = true; depthWriteEnable = true; - depthCompareOp = less; + depthCompareOp = less_or_equal; depthBoundsTestEnable = false; stencilTestEnable = false; }; colorBlend = { logicOpEnable = false; attachments = ({ - blendEnable = false; - srcColorBlendFactor = src_color; - dstColorBlendFactor = zero; + blendEnable = true; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; colorBlendOp = add; srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = zero; + dstAlphaBlendFactor = one_minus_src_alpha; alphaBlendOp = add; colorWriteMask = r|g|b|a; }); diff --git a/libs/video/renderer/vulkan/twod.frag b/libs/video/renderer/vulkan/twod.frag index 83bda0874..a6a40212d 100644 --- a/libs/video/renderer/vulkan/twod.frag +++ b/libs/video/renderer/vulkan/twod.frag @@ -13,7 +13,5 @@ main (void) vec4 pix; pix = texture (Texture, st); - if (pix.a < 0.5) - discard; frag_color = pix * color; } diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index ba2d7c24c..0262e1802 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -72,6 +72,12 @@ typedef struct { float color[4]; } drawvert_t; +typedef struct cachepic_s { + struct cachepic_s *next; + char *name; + qpic_t *pic; +} cachepic_t; + #define MAX_QUADS (65536) #define VERTS_PER_QUAD (4) #define INDS_PER_QUAD (5) // one per vert plus primitive reset @@ -81,6 +87,8 @@ VkSampler conchars_sampler; scrap_t *draw_scrap; qfv_stagebuf_t *draw_stage; qpic_t *conchars; +qpic_t *white_pic; +static hashtab_t *pic_cache; VkBuffer quad_vert_buffer; VkBuffer quad_ind_buffer; @@ -175,6 +183,41 @@ flush_draw_scrap (vulkan_ctx_t *ctx) dfunc->vkWaitForFences (device->dev, 1, &ctx->fence, VK_TRUE, ~0ull);//FIXME } +static void +pic_free (qpic_t *pic) +{ + subpic_t *subpic = *(subpic_t **) pic->data; + QFV_SubpicDelete (subpic); + free (pic); +} + +//FIXME use cmem? +static cachepic_t * +new_cachepic (const char *name, qpic_t *pic) +{ + cachepic_t *cp; + + cp = malloc (sizeof (cachepic_t)); + cp->name = strdup (name); + cp->pic = pic; + return cp; +} + +static void +cachepic_free (void *_cp, void *unused) +{ + cachepic_t *cp = (cachepic_t *) _cp; + pic_free (cp->pic); + free (cp->name); + free (cp); +} + +static const char * +cachepic_getkey (const void *_cp, void *unused) +{ + return ((cachepic_t *) _cp)->name; +} + static qpic_t * pic_data (const char *name, int w, int h, const byte *data, vulkan_ctx_t *ctx) { @@ -228,12 +271,29 @@ Vulkan_Draw_PicFromWad (const char *name, vulkan_ctx_t *ctx) qpic_t * Vulkan_Draw_CachePic (const char *path, qboolean alpha, vulkan_ctx_t *ctx) { - return pic_data (0, 1, 1, (const byte *)"", ctx); + qpic_t *p; + qpic_t *pic; + cachepic_t *cpic; + + if ((cpic = Hash_Find (pic_cache, path))) { + return cpic->pic; + } + if (strlen (path) < 4 || strcmp (path + strlen (path) - 4, ".lmp") + || !(p = (qpic_t *) QFS_LoadFile (QFS_FOpenFile (path), 0))) { + return 0; + } + + pic = pic_data (path, p->width, p->height, p->data, ctx); + free (p); + cpic = new_cachepic (path, pic); + Hash_Add (pic_cache, cpic); + return pic; } void Vulkan_Draw_UncachePic (const char *path, vulkan_ctx_t *ctx) { + Hash_Free (pic_cache, Hash_Del (pic_cache, path)); } void @@ -261,6 +321,9 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + //FIXME move into struct + pic_cache = Hash_NewTable (127, cachepic_getkey, cachepic_free, 0, 0); + create_quad_buffers (ctx); draw_scrap = QFV_CreateScrap (device, 2048, QFV_RGBA); draw_stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024); @@ -269,6 +332,8 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) qpic_t *charspic = Draw_Font8x8Pic (); conchars = pic_data (0, charspic->width, charspic->height, charspic->data, ctx); + byte white_block = 0xfe; + white_pic = pic_data (0, 1, 1, &white_block, ctx); flush_draw_scrap (ctx); @@ -480,6 +545,8 @@ Vulkan_Draw_SubPic (int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height, vulkan_ctx_t *ctx) { + static quat_t color = { 1, 1, 1, 1}; + draw_pic (x, y, width, height, pic, srcx, srcy, width, height, color); } void @@ -495,11 +562,24 @@ Vulkan_Draw_TileClear (int x, int y, int w, int h, vulkan_ctx_t *ctx) void Vulkan_Draw_Fill (int x, int y, int w, int h, int c, vulkan_ctx_t *ctx) { + quat_t color; + + VectorScale (vid.palette + c * 3, 1.0f/255.0f, color); + color[3] = 1; + draw_pic (x, y, w, h, white_pic, 0, 0, 1, 1, color); +} + +static inline void +draw_blendscreen (quat_t color) +{ + draw_pic (0, 0, vid.conwidth, vid.conheight, white_pic, 0, 0, 1, 1, color); } void Vulkan_Draw_FadeScreen (vulkan_ctx_t *ctx) { + static quat_t color = { 0, 0, 0, 0.7 }; + draw_blendscreen (color); } void @@ -577,4 +657,7 @@ Vulkan_FlushText (vulkan_ctx_t *ctx) void Vulkan_Draw_BlendScreen (quat_t color, vulkan_ctx_t *ctx) { + if (color[3]) { + draw_blendscreen (color); + } } From ad9c3193faa5230c665ac4e215f6d3e58af6eced Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 15 Jan 2021 22:45:49 +0900 Subject: [PATCH 231/435] [vulkan] Use darray size to control cmd buffer count This allows the array in which the command buffers are allocated to be allocated on the stack using alloca and thus remove the need to malloc/free of relatively small chunks. --- include/QF/Vulkan/command.h | 11 ++++++++--- libs/video/renderer/vid_render_vulkan.c | 7 +++---- libs/video/renderer/vulkan/command.c | 12 +++++------- libs/video/renderer/vulkan/vulkan_draw.c | 9 ++++----- libs/video/renderer/vulkan/vulkan_vid_common.c | 7 +++---- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index 925a63781..47418db1a 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -6,6 +6,9 @@ typedef struct qfv_cmdbufferset_s DARRAY_TYPE (VkCommandBuffer) qfv_cmdbufferset_t; +#define QFV_AllocCommandBufferSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_cmdbufferset_t, num, allocator) + typedef struct qfv_semaphoreset_s DARRAY_TYPE (VkSemaphore) qfv_semaphoreset_t; @@ -23,9 +26,11 @@ struct qfv_device_s; VkCommandPool QFV_CreateCommandPool (struct qfv_device_s *device, uint32_t queueFamily, int transient, int reset); -qfv_cmdbufferset_t *QFV_AllocateCommandBuffers (struct qfv_device_s *device, - VkCommandPool pool, - int secondary, int count); +/** Allocate bufferset->size command buffers + */ +int QFV_AllocateCommandBuffers (struct qfv_device_s *device, + VkCommandPool pool, int secondary, + qfv_cmdbufferset_t *bufferset); VkSemaphore QFV_CreateSemaphore (struct qfv_device_s *device); VkFence QFV_CreateFence (struct qfv_device_s *device, int signaled); diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 995763baf..f68e8c182 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -389,11 +389,10 @@ vulkan_vid_render_choose_visual (void) vulkan_ctx->cmdpool = QFV_CreateCommandPool (vulkan_ctx->device, vulkan_ctx->device->queue.queueFamily, 0, 1); - __auto_type cmdset = QFV_AllocateCommandBuffers (vulkan_ctx->device, - vulkan_ctx->cmdpool, - 0, 1); + __auto_type cmdset = QFV_AllocCommandBufferSet (1, alloca); + QFV_AllocateCommandBuffers (vulkan_ctx->device, vulkan_ctx->cmdpool, 0, + cmdset); vulkan_ctx->cmdbuffer = cmdset->a[0]; - free (cmdset); vulkan_ctx->fence = QFV_CreateFence (vulkan_ctx->device, 1); Sys_Printf ("vk choose visual %p %p %d %p\n", vulkan_ctx->device->dev, vulkan_ctx->device->queue.queue, diff --git a/libs/video/renderer/vulkan/command.c b/libs/video/renderer/vulkan/command.c index 8ba60ab32..10f0cc559 100644 --- a/libs/video/renderer/vulkan/command.c +++ b/libs/video/renderer/vulkan/command.c @@ -87,9 +87,9 @@ QFV_CreateCommandPool (qfv_device_t *device, uint32_t queueFamily, return pool; } -qfv_cmdbufferset_t * +int QFV_AllocateCommandBuffers (qfv_device_t *device, VkCommandPool pool, - int secondary, int count) + int secondary, qfv_cmdbufferset_t *bufferset) { VkDevice dev = device->dev; qfv_devfuncs_t *dfunc = device->funcs; @@ -99,12 +99,10 @@ QFV_AllocateCommandBuffers (qfv_device_t *device, VkCommandPool pool, } VkCommandBufferAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, - pool, level, count + pool, level, bufferset->size }; - qfv_cmdbufferset_t *cmdbufferset; - cmdbufferset = DARRAY_ALLOCFIXED (*cmdbufferset, count, malloc); - dfunc->vkAllocateCommandBuffers (dev, &allocInfo, cmdbufferset->a); - return cmdbufferset; + int ret = dfunc->vkAllocateCommandBuffers (dev, &allocInfo, bufferset->a); + return ret == VK_SUCCESS; } VkSemaphore diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 0262e1802..61b85d3e1 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -355,12 +355,12 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) QFV_ScrapImageView (draw_scrap), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; - __auto_type cmdBuffers - = QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, - ctx->framebuffers.size); + size_t frames = ctx->framebuffers.size; + __auto_type cmdBuffers = QFV_AllocCommandBufferSet (frames, alloca); + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); __auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); - for (size_t i = 0; i < ctx->framebuffers.size; i++) { + for (size_t i = 0; i < frames; i++) { __auto_type frame = &ctx->framebuffers.a[i]; frame->twodDescriptors = sets->a[i]; @@ -379,7 +379,6 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) DARRAY_APPEND (frame->subCommand, cmdBuffers->a[i]); } free (sets); - free (cmdBuffers); } static inline void diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 126d602fd..16e60e5c1 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -402,9 +402,9 @@ Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) attachments->a[0] = ctx->renderpass.colorImage->view; attachments->a[1] = ctx->renderpass.depthImage->view; - __auto_type cmdBuffers - = QFV_AllocateCommandBuffers (device, cmdpool, 0, - ctx->framebuffers.size); + __auto_type cmdBuffers = QFV_AllocCommandBufferSet (ctx->framebuffers.size, + alloca); + QFV_AllocateCommandBuffers (device, cmdpool, 0, cmdBuffers); for (size_t i = 0; i < ctx->framebuffers.size; i++) { attachments->a[2] = sc->imageViews->a[i]; @@ -420,7 +420,6 @@ Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) frame->subCommand = malloc (sizeof (qfv_cmdbufferset_t)); DARRAY_INIT (frame->subCommand, 4); } - free (cmdBuffers); } void From 92afe9f265ef74243138cb12508bf3317c9487cf Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 15 Jan 2021 22:50:04 +0900 Subject: [PATCH 232/435] [vulkan] Convert stagebuf to a ring buffer I should have known this would be necessary, but it fixes the corruption when updating the scrap. --- include/QF/Vulkan/funclist.h | 1 + include/QF/Vulkan/staging.h | 24 +- include/QF/Vulkan/texture.h | 20 +- libs/video/renderer/Makemodule.am | 1 + libs/video/renderer/vulkan/staging.c | 180 ++++++- libs/video/renderer/vulkan/test/Makemodule.am | 19 + .../video/renderer/vulkan/test/test-staging.c | 438 ++++++++++++++++++ libs/video/renderer/vulkan/texture.c | 39 +- libs/video/renderer/vulkan/vulkan_draw.c | 32 +- .../video/renderer/vulkan/vulkan_vid_common.c | 6 +- 10 files changed, 688 insertions(+), 72 deletions(-) create mode 100644 libs/video/renderer/vulkan/test/Makemodule.am create mode 100644 libs/video/renderer/vulkan/test/test-staging.c diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 534097b5d..63c5bde29 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -101,6 +101,7 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateSemaphore) DEVICE_LEVEL_VULKAN_FUNCTION (vkCreateFence) DEVICE_LEVEL_VULKAN_FUNCTION (vkWaitForFences) DEVICE_LEVEL_VULKAN_FUNCTION (vkResetFences) +DEVICE_LEVEL_VULKAN_FUNCTION (vkGetFenceStatus) DEVICE_LEVEL_VULKAN_FUNCTION (vkQueueSubmit) DEVICE_LEVEL_VULKAN_FUNCTION (vkQueueWaitIdle) DEVICE_LEVEL_VULKAN_FUNCTION (vkDeviceWaitIdle) diff --git a/include/QF/Vulkan/staging.h b/include/QF/Vulkan/staging.h index 9a90edd6e..aaac5d749 100644 --- a/include/QF/Vulkan/staging.h +++ b/include/QF/Vulkan/staging.h @@ -1,20 +1,36 @@ #ifndef __QF_Vulkan_staging_h #define __QF_Vulkan_staging_h +typedef struct qfv_packet_s { + struct qfv_stagebuf_s *stage; ///< staging buffer that owns this packet + VkCommandBuffer cmd; + VkFence fence; + size_t offset; + size_t length; +} qfv_packet_t; + typedef struct qfv_stagebuf_s { struct qfv_device_s *device; VkBuffer buffer; VkDeviceMemory memory; - size_t size; - size_t offset; ///< for batching building + qfv_packet_t *packet; ///< array of packets for controlling access + size_t num_packets;///< number of packets in array + size_t next_packet;///< index of the next packet to be used + size_t size; ///< actual size of the buffer + size_t end; ///< effective end of the buffer due to early wrap + size_t head; + size_t tail; void *data; } qfv_stagebuf_t; qfv_stagebuf_t *QFV_CreateStagingBuffer (struct qfv_device_s *device, - size_t size); + size_t size, int num_packets, + VkCommandPool cmdPool); void QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage); void QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size); -void *QFV_ClaimStagingBuffer (qfv_stagebuf_t *stage, size_t size); +qfv_packet_t *QFV_PacketAcquire (qfv_stagebuf_t *stage); +void *QFV_PacketExtend (qfv_packet_t *packet, size_t size); +void QFV_PacketSubmit (qfv_packet_t *packet); #endif//__QF_Vulkan_staging_h diff --git a/include/QF/Vulkan/texture.h b/include/QF/Vulkan/texture.h index 6a55815f6..e24fa0eb1 100644 --- a/include/QF/Vulkan/texture.h +++ b/include/QF/Vulkan/texture.h @@ -18,26 +18,8 @@ VkImageView QFV_ScrapImageView (scrap_t *scrap) __attribute__((pure)); subpic_t *QFV_ScrapSubpic (scrap_t *scrap, int width, int height); void QFV_SubpicDelete (subpic_t *subpic); -/** Add an update region to the batch queue. - * - * The region to be updated is recorded in the batch queue, space allocated - * in the staging buffer, and a pointer to the allocated space is returned. - * - * \note No data is stransfered. This facilitates writing generated data - * directly to the staging buffer. - */ void *QFV_SubpicBatch (subpic_t *subpic, struct qfv_stagebuf_s *stage); -/** Flush all batched subpic updates. - * - * The offset in the staging bufffer \a stage is reset to 0. The command - * buffer is populated with the appropriate image layout barriers and the - * necessary copy commands. - * - * \note The command buffer is neither begun nor ended, nor is it submitted - * to a queue. This is to maximize flexibility in command buffer usage. - */ -void QFV_ScrapFlush (scrap_t *scrap, struct qfv_stagebuf_s *stage, - VkCommandBuffer cmd); +void QFV_ScrapFlush (scrap_t *scrap); #endif//__QF_Vulkan_texture_h diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 6f306ffe5..7a323f118 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -1,3 +1,4 @@ +include libs/video/renderer/vulkan/test/Makemodule.am include libs/video/renderer/vulkan/vkgen/Makemodule.am #lib_LTLIBRARIES += @VID_REND_TARGETS@ diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c index be181d00b..40ad459a6 100644 --- a/libs/video/renderer/vulkan/staging.c +++ b/libs/video/renderer/vulkan/staging.c @@ -47,6 +47,7 @@ #include "QF/sys.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/staging.h" @@ -54,21 +55,39 @@ #include "vid_vulkan.h" qfv_stagebuf_t * -QFV_CreateStagingBuffer (qfv_device_t *device, size_t size) +QFV_CreateStagingBuffer (qfv_device_t *device, size_t size, int num_packets, + VkCommandPool cmdPool) { qfv_devfuncs_t *dfunc = device->funcs; - qfv_stagebuf_t *stage = malloc (sizeof (qfv_stagebuf_t)); - stage->size = size; - stage->offset = 0; + qfv_stagebuf_t *stage = malloc (sizeof (qfv_stagebuf_t) + + num_packets * sizeof (qfv_packet_t)); stage->device = device; stage->buffer = QFV_CreateBuffer (device, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); stage->memory = QFV_AllocBufferMemory (device, stage->buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, size, 0); - QFV_BindBufferMemory (device, stage->buffer, stage->memory, 0); + stage->packet = (qfv_packet_t *) (stage + 1); + stage->num_packets = num_packets; + stage->next_packet = 0; + stage->size = size; + stage->end = size; + stage->head = 0; + stage->tail = 0; + dfunc->vkMapMemory (device->dev, stage->memory, 0, size, 0, &stage->data); + QFV_BindBufferMemory (device, stage->buffer, stage->memory, 0); + + __auto_type bufferset = QFV_AllocCommandBufferSet (num_packets, alloca); + QFV_AllocateCommandBuffers (device, cmdPool, 0, bufferset); + for (int i = 0; i < num_packets; i++) { + stage->packet[i].stage = stage; + stage->packet[i].cmd = bufferset->a[i]; + stage->packet[i].fence = QFV_CreateFence (device, 1); + stage->packet[i].offset = 0; + stage->packet[i].length = 0; + } return stage; } @@ -78,6 +97,10 @@ QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage) qfv_device_t *device = stage->device; qfv_devfuncs_t *dfunc = device->funcs; + for (size_t i = 0; i < stage->num_packets; i++) { + dfunc->vkDestroyFence (device->dev, stage->packet[i].fence, 0); + } + dfunc->vkUnmapMemory (device->dev, stage->memory); dfunc->vkFreeMemory (device->dev, stage->memory, 0); dfunc->vkDestroyBuffer (device->dev, stage->buffer, 0); @@ -100,13 +123,150 @@ QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size) dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); } -void * -QFV_ClaimStagingBuffer (qfv_stagebuf_t *stage, size_t size) +static void +advance_tail (qfv_stagebuf_t *stage, qfv_packet_t *packet) { - if (stage->offset + size > stage->size) { + qfv_device_t *device = stage->device; + qfv_devfuncs_t *dfunc = device->funcs; + + qfv_packet_t *start = packet; + + while (1) { + if ((size_t) (++packet - stage->packet) >= stage->num_packets) { + packet = stage->packet; + } + if (packet != start + && (dfunc->vkGetFenceStatus (device->dev, packet->fence) + == VK_SUCCESS)) { + if (packet->length == 0) { + continue; + } + if ((stage->tail == stage->end && packet->offset == 0) + || stage->tail == packet->offset) { + stage->tail = packet->offset + packet->length; + packet->length = 0; + if (stage->tail >= stage->end) { + stage->end = stage->size; + stage->tail = stage->size; + } + } + continue; + } + // Packets are always aquired in sequence and thus the first busy + // packet after the start packet marks the end of available space. + // Alternatively, there is only one packet and we've looped around + // back to the start packet. Must ensure the tail is updated + if (stage->tail >= stage->end && packet->offset == 0) { + stage->end = stage->size; + stage->tail = packet->offset; + } + break; + } +} + +qfv_packet_t * +QFV_PacketAcquire (qfv_stagebuf_t *stage) +{ + qfv_device_t *device = stage->device; + qfv_devfuncs_t *dfunc = device->funcs; + qfv_packet_t *packet = &stage->packet[stage->next_packet++]; + stage->next_packet %= stage->num_packets; + + dfunc->vkWaitForFences (device->dev, 1, &packet->fence, VK_TRUE, ~0ull); + + advance_tail (stage, packet); + if (stage->head == stage->size) { + stage->head = 0; + } + packet->offset = stage->head; + packet->length = 0; + + dfunc->vkResetFences (device->dev, 1, &packet->fence); + dfunc->vkResetCommandBuffer (packet->cmd, 0); + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0, + }; + dfunc->vkBeginCommandBuffer (packet->cmd, &beginInfo); + + return packet; +} + +void * +QFV_PacketExtend (qfv_packet_t *packet, size_t size) +{ + qfv_stagebuf_t *stage = packet->stage; + if (!size || size > stage->size) { return 0; } - void *data = (byte *) stage->data + stage->offset; - stage->offset += (size + 3) & ~3; + + //FIXME extra logic may be needed to wait wait for space to become + //available when the requested size should fit but can't due to in-flight + //packets + advance_tail (stage, packet); + + size_t head = stage->head; + size_t end = stage->end; + if (head + size > stage->end) { + if (packet->length) { + // packets cannot wrap around the buffer (must use separate + // packets) + return 0; + } + if (stage->tail == 0) { + // the beginning of the the staging buffer is occupied + return 0; + } + packet->offset = 0; + head = 0; + end = stage->head; + } + if (head < stage->tail && head + size > stage->tail) { + // not enough room for the sub-packet + return 0; + } + void *data = (byte *) stage->data + head; + stage->end = end; + stage->head = head + size; + packet->length += size; return data; } + +void +QFV_PacketSubmit (qfv_packet_t *packet) +{ + qfv_stagebuf_t *stage = packet->stage; + qfv_device_t *device = stage->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (!packet->length) { + // XXX at this stage, this looks the same as below, I think a queue + // completing is the only way to set a fence (other than creation), + // so submit the (hopefully) empty command buffer so the fence becomes + // set, but without waiting on or triggering any semaphores. + dfunc->vkEndCommandBuffer (packet->cmd); + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, + 0, 0, 0, + 1, &packet->cmd, + 0, 0, + }; + dfunc->vkQueueSubmit (device->queue.queue, 1, &submitInfo, + packet->fence); + return; + } + + QFV_FlushStagingBuffer (stage, packet->offset, packet->length); + + dfunc->vkEndCommandBuffer (packet->cmd); + //XXX it may become necessary to pass in semaphores etc (maybe add to + //packet?) + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, + 0, 0, 0, + 1, &packet->cmd, + 0, 0, + }; + // The fence was reset when the packet was acquired + dfunc->vkQueueSubmit (device->queue.queue, 1, &submitInfo, packet->fence); +} diff --git a/libs/video/renderer/vulkan/test/Makemodule.am b/libs/video/renderer/vulkan/test/Makemodule.am new file mode 100644 index 000000000..cacb206f3 --- /dev/null +++ b/libs/video/renderer/vulkan/test/Makemodule.am @@ -0,0 +1,19 @@ +libs_video_renderer_vulkan_tests = \ + libs/video/renderer/vulkan/test/test-staging \ + $e + +TESTS += $(libs_video_renderer_vulkan_tests) + +check_PROGRAMS += $(libs_video_renderer_vulkan_tests) + +libs_video_renderer_vulkan_test_libs= \ + libs/video/renderer/vid_render_vulkan.la \ + libs/util/libQFutil.la + +libs_video_renderer_vulkan_test_test_staging_SOURCES= \ + libs/video/renderer/vulkan/test/test-staging.c \ + $e +libs_video_renderer_vulkan_test_test_staging_LDADD= \ + $(libs_video_renderer_vulkan_test_libs) +libs_video_renderer_vulkan_test_test_staging_DEPENDENCIES= \ + $(libs_video_renderer_vulkan_test_libs) diff --git a/libs/video/renderer/vulkan/test/test-staging.c b/libs/video/renderer/vulkan/test/test-staging.c new file mode 100644 index 000000000..bb5361cec --- /dev/null +++ b/libs/video/renderer/vulkan/test/test-staging.c @@ -0,0 +1,438 @@ +#include +#include +#include +#include + +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/staging.h" + +void *stage_memory; + +static VkResult +vkMapMemory (VkDevice device, VkDeviceMemory memory, + VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, + void **data) +{ + char *buf = calloc (1, size); + stage_memory = buf; + *data = buf; + return VK_SUCCESS; +} + +static VkResult +vkBindBufferMemory (VkDevice device, VkBuffer buffer, VkDeviceMemory memory, + VkDeviceSize offset) +{ + return VK_SUCCESS; +} + +static VkResult +vkCreateBuffer (VkDevice device, const VkBufferCreateInfo *cinfo, + const VkAllocationCallbacks *allocator, VkBuffer *buffer) +{ + *buffer = 0; + return VK_SUCCESS; +} + +static void +vkGetBufferMemoryRequirements (VkDevice device, VkBuffer buffer, + VkMemoryRequirements *requirements) +{ + memset (requirements, 0, sizeof (*requirements)); +} + +static VkResult +vkAllocateCommandBuffers (VkDevice device, + const VkCommandBufferAllocateInfo *info, + VkCommandBuffer *buffers) +{ + static size_t cmdBuffer = 0; + + for (uint32_t i = 0; i < info->commandBufferCount; i++) { + buffers[i] = (VkCommandBuffer) ++cmdBuffer; + } + return VK_SUCCESS; +} + +static VkResult +vkCreateFence (VkDevice device, const VkFenceCreateInfo *info, + const VkAllocationCallbacks *allocator, VkFence *fence) +{ + int *f = malloc (sizeof (int)); + *f = info->flags & VK_FENCE_CREATE_SIGNALED_BIT ? 1 : 0; + *(int **)fence = f; + return VK_SUCCESS; +} + +static VkResult +vkWaitForFences (VkDevice device, uint32_t fenceCount, const VkFence *fences, + VkBool32 waitAll, uint64_t timeout) +{ + for (uint32_t i = 0; i < fenceCount; i++) { + int *f = (int *)fences[i]; + *f = 0; + } + return VK_SUCCESS; +} + +static VkResult +vkResetFences (VkDevice device, uint32_t fenceCount, const VkFence *fences) +{ + for (uint32_t i = 0; i < fenceCount; i++) { + int *f = (int *)fences[i]; + *f = 0; + } + return VK_SUCCESS; +} + +static VkResult +vkGetFenceStatus (VkDevice device, VkFence fence) +{ + int *f = (int *)fence; + return *f ? VK_SUCCESS : VK_NOT_READY; +} + +static VkResult +vkResetCommandBuffer (VkCommandBuffer buffer, VkCommandBufferResetFlags flags) +{ + return VK_SUCCESS; +} + +static VkResult +vkBeginCommandBuffer (VkCommandBuffer buffer, + const VkCommandBufferBeginInfo *info) +{ + return VK_SUCCESS; +} + +static VkResult +vkEndCommandBuffer (VkCommandBuffer buffer) +{ + return VK_SUCCESS; +} + +static VkResult +vkFlushMappedMemoryRanges (VkDevice device, uint32_t count, + const VkMappedMemoryRange *ranges) +{ + return VK_SUCCESS; +} + +static VkResult +vkQueueSubmit (VkQueue queue, uint32_t count, const VkSubmitInfo *submits, + VkFence fence) +{ + int *f = (int *)fence; + *f = 1; + return VK_SUCCESS; +} + +qfv_devfuncs_t dfuncs = { + vkCreateBuffer:vkCreateBuffer, + vkGetBufferMemoryRequirements:vkGetBufferMemoryRequirements, + vkMapMemory:vkMapMemory, + vkBindBufferMemory:vkBindBufferMemory, + vkAllocateCommandBuffers:vkAllocateCommandBuffers, + vkCreateFence:vkCreateFence, + vkWaitForFences:vkWaitForFences, + vkResetFences:vkResetFences, + vkGetFenceStatus:vkGetFenceStatus, + vkResetCommandBuffer:vkResetCommandBuffer, + vkBeginCommandBuffer:vkBeginCommandBuffer, + vkEndCommandBuffer:vkEndCommandBuffer, + vkFlushMappedMemoryRanges:vkFlushMappedMemoryRanges, + vkQueueSubmit:vkQueueSubmit, +}; +qfv_physdev_t physDev; +qfv_device_t device = { + physDev:&physDev, + funcs:&dfuncs, +}; + +static void __attribute__ ((format (printf, 2, 3), noreturn)) +_error (int line, const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + fprintf (stderr, "%d: ", line); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); + va_end (args); + exit(1); +} +#define error(fmt...) _error(__LINE__, fmt) + +int +main (void) +{ + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (&device, 1024, 4, 0); + + if (stage->num_packets != 4) { + error ("stage has incorrect packet count: %zd\n", stage->num_packets); + } + if (stage->next_packet != 0) { + error ("stage has incorrect next_packet: %zd\n", stage->next_packet); + } + if (stage->size != 1024) { + error ("stage has incorrect size: %zd\n", stage->size); + } + if (stage->end != stage->size) { + error ("stage has incorrect end: %zd\n", stage->end); + } + if (stage->head || stage->tail != stage->head) { + error ("stage ring buffer not initialized: h:%zd t:%zd\n", + stage->head, stage->tail); + } + if (!stage->data || stage->data != stage_memory) { + error ("stage memory not mapped: d:%p, m:%p\n", + stage->data, stage_memory); + } + + for (size_t i = 0; i < stage->num_packets; i++) { + qfv_packet_t *p = &stage->packet[i]; + if (p->stage != stage) { + error ("packet[%zd] stage not set: ps:%p s:%p\n", i, + p->stage, stage); + } + if (!p->cmd) { + error ("packet[%zd] has no command buffer\n", i); + } + if (!p->fence) { + error ("packet[%zd] has no fence\n", i); + } + for (size_t j = 0; j < i; j++) { + qfv_packet_t *q = &stage->packet[j]; + if (q->cmd == p->cmd || q->fence == p->fence) { + error ("packet[%zd] has dup fence or cmd buf\n", i); + } + } + if (vkGetFenceStatus (device.dev, p->fence) != VK_SUCCESS) { + error ("packet[%zd].fence is not signaled\n", i); + } + if (p->offset || p->length) { + error ("packet[%zd] size/length not initialized: o:%zd l:%zd\n", + i, p->offset, p->length); + } + } + + qfv_packet_t *packet = QFV_PacketAcquire (stage); + if (vkGetFenceStatus (device.dev, packet->fence) != VK_NOT_READY) { + error ("packet.fence is signaled\n"); + } + + void *data; + size_t old_head, old_tail; + + old_head = stage->head; + old_tail = stage->tail; + data = QFV_PacketExtend (packet, 0); + if (data) { + error ("0 byte extend did not return null\n"); + } + if (stage->head != old_head || stage->tail != old_tail) { + error ("0 byte extend moved head or tail\n"); + } + + data = QFV_PacketExtend (packet, 2048); + if (data) { + error ("2048 byte extend did not return null\n"); + } + if (stage->head != old_head || stage->tail != old_tail) { + error ("2048 byte extend moved head or tail\n"); + } + + data = QFV_PacketExtend (packet, 1024); + if (!data) { + error ("1024 byte extend failed\n"); + } + if (stage->head == old_head) { + error ("1024 byte extend did not move head\n"); + } + if (stage->tail != old_tail) { + error ("1024 byte extend moved tail\n"); + } + if (stage->head > stage->size) { + error ("stage head out of bounds: %zd\n", stage->head); + } + if (packet->offset != old_head || packet->length != 1024) { + error ("packet offset/size incorrect: p:%zd,%zd h:%zd\n", + packet->offset, packet->length, old_head); + } + if (stage->head < packet->offset + packet->length) { + error ("stage head before end of packet: %zd, pe:%zd\n", + stage->head, packet->offset + packet->length); + } + + old_head = stage->head; + old_tail = stage->tail; + data = QFV_PacketExtend (packet, 16); + if (data) { + error ("16 byte extend in full stage did not return null\n"); + } + if (stage->head != old_head || stage->tail != old_tail) { + error ("16 byte extend moved head or tail\n"); + } + QFV_PacketSubmit (packet); + if (vkGetFenceStatus (device.dev, packet->fence) != VK_SUCCESS) { + error ("packet.fence is not signaled\n"); + } + + if (stage->head != 1024 || stage->tail != 0) { + error ("stage head or tail not as expected: h: %zd t:%zd\n", + stage->head, stage->tail); + } + + qfv_packet_t *packet2 = QFV_PacketAcquire (stage); + if (!packet2 || packet2 == packet) { + error ("did not get new packet: n:%p o:%p\n", packet2, packet); + } + packet = packet2; + if (packet->offset != 0 || stage->head != 0 || stage->tail != 0) { + error ("new packet did not wrap: p:%zd h:%zd t:%zd\n", + packet2->offset, stage->head, stage->tail); + } + + old_head = stage->head; + old_tail = stage->tail; + data = QFV_PacketExtend (packet, 768); + if (!data) { + error ("768 byte extend failed\n"); + } + if (stage->head == old_head) { + error ("768 byte extend did not move head\n"); + } + if (stage->tail != 0) { + error ("768 byte extend dit not wrap tail: %zd\n", stage->tail); + } + if (stage->head > stage->size) { + error ("stage head out of bounds: %zd\n", stage->head); + } + if (packet->offset != old_head || packet->length != 768) { + error ("packet offset/size incorrect: p:%zd,%zd h:%zd\n", + packet->offset, packet->length, old_head); + } + if (stage->head < packet->offset + packet->length) { + error ("stage head before end of packet: %zd, pe:%zd\n", + stage->head, packet->offset + packet->length); + } + + // test attempting to wrap the packet (without needed space) + old_head = stage->head; + old_tail = stage->tail; + data = QFV_PacketExtend (packet, 512); + if (data) { + error ("512 byte extend in partially full stage succeeded\n"); + } + if (stage->head != old_head || stage->tail != old_tail) { + error ("512 byte extend moved head or tail\n"); + } + QFV_PacketSubmit (packet); + + if (stage->head != 768 || stage->tail != 0) { + error ("stage head or tail not as expected: h: %zd t:%zd\n", + stage->head, stage->tail); + } + + packet = QFV_PacketAcquire (stage); + + // test wrapping a new packet + data = QFV_PacketExtend (packet, 512); + if (!data) { + error ("512 byte extend failed\n"); + } + if (packet->offset != 0 || packet->length != 512) { + error ("packet offset/size incorrect: p:%zd,%zd\n", + packet->offset, packet->length); + } + if (stage->head != 512 || stage->tail != stage->end || stage->end !=768) { + error ("stage head or tail not as expected: h: %zd t:%zd\n", + stage->head, stage->tail); + } + data = QFV_PacketExtend (packet, 512); + if (!data) { + error ("second 512 byte extend failed\n"); + } + if (packet->offset != 0 || packet->length != 1024) { + error ("packet offset/size incorrect: p:%zd,%zd\n", + packet->offset, packet->length); + } + if (stage->head != 1024 || stage->tail != 0 || stage->end != 1024) { + error ("stage head or tail not as expected: h: %zd t:%zd\n", + stage->head, stage->tail); + } + QFV_PacketSubmit (packet); + + packet = QFV_PacketAcquire (stage); + data = QFV_PacketExtend (packet, 512); + if (!data) { + error ("512 byte extend failed\n"); + } + if (packet->offset != 0 || packet->length != 512) { + error ("packet offset/size incorrect: p:%zd,%zd\n", + packet->offset, packet->length); + } + QFV_PacketSubmit (packet); + + if (stage->head != 512 || stage->tail != 0 || stage->end != 1024) { + error ("stage head or tail not as expected: h: %zd t:%zd\n", + stage->head, stage->tail); + } + + packet = QFV_PacketAcquire (stage); + data = QFV_PacketExtend (packet, 256); + if (!data) { + error ("256 byte extend failed\n"); + } + if (packet->offset != 512 || packet->length != 256) { + error ("packet offset/size incorrect: p:%zd,%zd\n", + packet->offset, packet->length); + } + if (stage->head != 768 || stage->tail != 512 || stage->end != 1024) { + error ("stage head or tail not as expected: h: %zd t:%zd\n", + stage->head, stage->tail); + } + // don't submit yet. Normally, it would be an error, but the test harness + // needs to keep the packet on hand for the following tests to work + packet2 = QFV_PacketAcquire (stage); + old_head = stage->head; + old_tail = stage->tail; + data = QFV_PacketExtend (packet2, 768); + if (data) { + error ("768 byte extend did not return null\n"); + } + if (stage->head != old_head || stage->tail != old_tail) { + error ("768 byte extend moved head or tail\n"); + } + + //should wrap + data = QFV_PacketExtend (packet2, 512); + if (!data) { + error ("512 byte extend failed\n"); + } + if (packet2->offset != 0 || packet2->length != 512) { + error ("packet offset/size incorrect: p:%zd,%zd\n", + packet2->offset, packet2->length); + } + if (stage->head != 512 || stage->tail != 512 || stage->end != 768) { + error ("stage head or tail not as expected: h: %zd t:%zd\n", + stage->head, stage->tail); + } + + //submit the first packet + QFV_PacketSubmit (packet); + + packet = QFV_PacketAcquire (stage); + old_head = stage->head; + old_tail = stage->tail; + data = QFV_PacketExtend (packet, 768); + if (data) { + error ("768 byte extend did not return null\n"); + } + if (stage->head != old_head || stage->tail != old_tail) { + error ("768 byte extend moved head or tail\n"); + } + return 0; +} diff --git a/libs/video/renderer/vulkan/texture.c b/libs/video/renderer/vulkan/texture.c index 12fba3932..f23e1297a 100644 --- a/libs/video/renderer/vulkan/texture.c +++ b/libs/video/renderer/vulkan/texture.c @@ -65,6 +65,7 @@ struct scrap_s { VkDeviceMemory memory; VkImageView view; size_t bpp; + qfv_packet_t *packet; vrect_t *batch; vrect_t **batch_tail; vrect_t *batch_free; @@ -119,6 +120,7 @@ QFV_CreateScrap (qfv_device_t *device, int size, QFVFormat format) scrap->bpp = bpp; scrap->subpics = 0; scrap->device = device; + scrap->packet = 0; scrap->batch = 0; scrap->batch_tail = &scrap->batch; scrap->batch_free = 0; @@ -215,9 +217,21 @@ QFV_SubpicBatch (subpic_t *subpic, qfv_stagebuf_t *stage) byte *dest; size_t size; - size = subpic->width * subpic->height * scrap->bpp; - if (!(dest = QFV_ClaimStagingBuffer (stage, size))) { - return 0; + if (!scrap->packet) { + scrap->packet = QFV_PacketAcquire (stage); + } + size = (subpic->width * subpic->height * scrap->bpp + 3) & ~3; + if (!(dest = QFV_PacketExtend (scrap->packet, size))) { + if (scrap->packet->length) { + QFV_ScrapFlush (scrap); + + scrap->packet = QFV_PacketAcquire (stage); + dest = QFV_PacketExtend (scrap->packet, size); + } + if (!dest) { + printf ("could not get space for update\n"); + return 0; + } } if (scrap->batch_free) { @@ -238,7 +252,7 @@ QFV_SubpicBatch (subpic_t *subpic, qfv_stagebuf_t *stage) } void -QFV_ScrapFlush (scrap_t *scrap, qfv_stagebuf_t *stage, VkCommandBuffer cmd) +QFV_ScrapFlush (scrap_t *scrap) { qfv_device_t *device = scrap->device; qfv_devfuncs_t *dfunc = device->funcs; @@ -247,6 +261,8 @@ QFV_ScrapFlush (scrap_t *scrap, qfv_stagebuf_t *stage, VkCommandBuffer cmd) return; } + qfv_packet_t *packet = scrap->packet; + qfv_stagebuf_t *stage = packet->stage; size_t i; __auto_type copy = QFV_AllocBufferImageCopy (128, alloca); memset (copy->a, 0, 128 * sizeof (copy->a[0])); @@ -257,7 +273,6 @@ QFV_ScrapFlush (scrap_t *scrap, qfv_stagebuf_t *stage, VkCommandBuffer cmd) copy->a[i].imageExtent.depth = 1; } - QFV_FlushStagingBuffer (stage, 0, stage->offset); VkImageMemoryBarrier barrier; qfv_pipelinestagepair_t stages; @@ -265,10 +280,11 @@ QFV_ScrapFlush (scrap_t *scrap, qfv_stagebuf_t *stage, VkCommandBuffer cmd) stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; barrier.image = scrap->image; - dfunc->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, 1, &barrier); - size_t offset = 0, size; + size_t offset = packet->offset, size; vrect_t *batch = scrap->batch; while (scrap->batch_count) { for (i = 0; i < scrap->batch_count && i < 128; i++) { @@ -283,7 +299,7 @@ QFV_ScrapFlush (scrap_t *scrap, qfv_stagebuf_t *stage, VkCommandBuffer cmd) offset += (size + 3) & ~3; batch = batch->next; } - dfunc->vkCmdCopyBufferToImage (cmd, stage->buffer, scrap->image, + dfunc->vkCmdCopyBufferToImage (packet->cmd, stage->buffer, scrap->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, i, copy->a); scrap->batch_count -= i; @@ -292,12 +308,15 @@ QFV_ScrapFlush (scrap_t *scrap, qfv_stagebuf_t *stage, VkCommandBuffer cmd) stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; barrier.image = scrap->image; - dfunc->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, 1, &barrier); *scrap->batch_tail = scrap->batch_free; scrap->batch_free = scrap->batch; scrap->batch = 0; scrap->batch_tail = &scrap->batch; - stage->offset = 0; + + QFV_PacketSubmit (scrap->packet); + scrap->packet = 0; } diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 61b85d3e1..24202a8c3 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -158,29 +158,7 @@ destroy_quad_buffers (vulkan_ctx_t *ctx) static void flush_draw_scrap (vulkan_ctx_t *ctx) { - qfv_device_t *device = ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; - VkCommandBuffer cmd = ctx->cmdbuffer; - - dfunc->vkWaitForFences (device->dev, 1, &ctx->fence, VK_TRUE, ~0ull); - dfunc->vkResetCommandBuffer (cmd, 0); - VkCommandBufferBeginInfo beginInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0, - }; - dfunc->vkBeginCommandBuffer (cmd, &beginInfo); - QFV_ScrapFlush (draw_scrap, draw_stage, cmd); - dfunc->vkEndCommandBuffer (cmd); - - VkSubmitInfo submitInfo = { - VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, - 0, 0, 0, - 1, &cmd, - 0, 0, - }; - dfunc->vkResetFences (device->dev, 1, &ctx->fence); - dfunc->vkQueueSubmit (device->queue.queue, 1, &submitInfo, ctx->fence); - dfunc->vkWaitForFences (device->dev, 1, &ctx->fence, VK_TRUE, ~0ull);//FIXME + QFV_ScrapFlush (draw_scrap); } static void @@ -326,7 +304,8 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) create_quad_buffers (ctx); draw_scrap = QFV_CreateScrap (device, 2048, QFV_RGBA); - draw_stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024); + draw_stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024, 4, + ctx->cmdpool); conchars_sampler = QFV_GetSampler (ctx, "quakepic"); qpic_t *charspic = Draw_Font8x8Pic (); @@ -604,9 +583,8 @@ Vulkan_DrawReset (vulkan_ctx_t *ctx) void Vulkan_FlushText (vulkan_ctx_t *ctx) { - if (draw_stage->offset) { - flush_draw_scrap (ctx); - } + flush_draw_scrap (ctx); + qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; __auto_type frame = &ctx->framebuffers.a[ctx->curFrame]; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 16e60e5c1..02b9a0c07 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -203,8 +203,10 @@ Vulkan_CreateDevice (vulkan_ctx_t *ctx) void Vulkan_CreateStagingBuffers (vulkan_ctx_t *ctx) { - ctx->staging[0] = QFV_CreateStagingBuffer (ctx->device, 1024*1024); - ctx->staging[1] = QFV_CreateStagingBuffer (ctx->device, 1024*1024); + ctx->staging[0] = QFV_CreateStagingBuffer (ctx->device, 1024*1024, 1, + ctx->cmdpool); + ctx->staging[1] = QFV_CreateStagingBuffer (ctx->device, 1024*1024, 1, + ctx->cmdpool); } void From 904a91c0b759757e0d388464afa1d8cfd743e691 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 16 Jan 2021 14:37:16 +0900 Subject: [PATCH 233/435] [vulkan] Use only one global staging buffer I think I did two as a bit of a ring buffer, but the new ring buffer system used inside a staging buffer makes it less necessary. Also, the staging buffer is now a fair bit bigger (4M is probably not really enough) --- include/vid_vulkan.h | 2 +- libs/video/renderer/vulkan/vulkan_vid_common.c | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 784c74312..223412999 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -68,7 +68,7 @@ typedef struct vulkan_ctx_s { VkCommandBuffer cmdbuffer; VkFence fence; // for ctx->cmdbuffer only vulkan_renderpass_t renderpass; - struct qfv_stagebuf_s *staging[2]; + struct qfv_stagebuf_s *staging; VkPipeline pipeline; size_t curFrame; vulkan_framebufferset_t framebuffers; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 02b9a0c07..a40e38c52 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -174,8 +174,7 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) if (ctx->swapchain) { QFV_DestroySwapchain (ctx->swapchain); } - QFV_DestroyStagingBuffer (ctx->staging[0]); - QFV_DestroyStagingBuffer (ctx->staging[1]); + QFV_DestroyStagingBuffer (ctx->staging); Vulkan_DestroyMatrices (ctx); ctx->instance->funcs->vkDestroySurfaceKHR (ctx->instance->instance, ctx->surface, 0); @@ -203,10 +202,8 @@ Vulkan_CreateDevice (vulkan_ctx_t *ctx) void Vulkan_CreateStagingBuffers (vulkan_ctx_t *ctx) { - ctx->staging[0] = QFV_CreateStagingBuffer (ctx->device, 1024*1024, 1, - ctx->cmdpool); - ctx->staging[1] = QFV_CreateStagingBuffer (ctx->device, 1024*1024, 1, - ctx->cmdpool); + ctx->staging = QFV_CreateStagingBuffer (ctx->device, 4*1024*1024, 1, + ctx->cmdpool); } void From 5186d3ae49cb60ec8f8268ccc67d80455eeadce2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 16 Jan 2021 14:42:25 +0900 Subject: [PATCH 234/435] [vulkan] Rework draw to use a context struct Cleans up global space and makes it usable in multiple contexts. Also, max quads dropped to 32k as each frame now has its own vertex buffer to avoid issues with vertex overwrites (which I have seen). However, all vertex buffers are in the one memory/buffer object (using offsets) and the index buffer has been moved into a device-local memory object. --- include/vid_vulkan.h | 4 +- libs/video/renderer/vulkan/vulkan_draw.c | 282 ++++++++++++++--------- 2 files changed, 178 insertions(+), 108 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 223412999..c8d318a99 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -22,8 +22,6 @@ typedef struct vulkan_framebuffer_s { VkCommandBuffer cmdBuffer; struct qfv_cmdbufferset_s *subCommand; - - VkDescriptorSet twodDescriptors; } vulkan_framebuffer_t; typedef struct vulkan_matrices_s { @@ -64,6 +62,8 @@ typedef struct vulkan_ctx_s { struct hashtab_s *descriptorPools; struct hashtab_s *samplers; + struct drawctx_s *draw_context; + VkCommandPool cmdpool; VkCommandBuffer cmdbuffer; VkFence fence; // for ctx->cmdbuffer only diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 24202a8c3..43068ae52 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -78,57 +78,89 @@ typedef struct cachepic_s { qpic_t *pic; } cachepic_t; -#define MAX_QUADS (65536) +typedef struct drawframe_s { + size_t vert_offset; + drawvert_t *verts; + uint32_t num_quads; + VkCommandBuffer cmd; + VkDescriptorSet descriptors; +} drawframe_t; + +typedef struct drawframeset_s + DARRAY_TYPE (drawframe_t) drawframeset_t; + +typedef struct drawctx_s { + VkSampler sampler; + scrap_t *scrap; + qfv_stagebuf_t *stage; + qpic_t *conchars; + qpic_t *conback; + qpic_t *white_pic; + hashtab_t *pic_cache; + VkBuffer vert_buffer; + VkDeviceMemory vert_memory; + VkBuffer ind_buffer; + VkDeviceMemory ind_memory; + VkPipeline pipeline; + VkPipelineLayout layout; + drawframeset_t frames; +} drawctx_t; + +// enough for a full screen of 8x8 chars at 1920x1080 plus some extras (368) +#define MAX_QUADS (32768) #define VERTS_PER_QUAD (4) #define INDS_PER_QUAD (5) // one per vert plus primitive reset -//FIXME move into a context struct -VkSampler conchars_sampler; -scrap_t *draw_scrap; -qfv_stagebuf_t *draw_stage; -qpic_t *conchars; -qpic_t *white_pic; -static hashtab_t *pic_cache; - -VkBuffer quad_vert_buffer; -VkBuffer quad_ind_buffer; -VkDeviceMemory quad_memory; -drawvert_t *quad_verts; -uint32_t *quad_inds; -uint32_t num_quads; - -VkPipeline twod_pipeline; -VkPipelineLayout twod_layout; -size_t draw_cmdBuffer; - static void create_quad_buffers (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - //FIXME quad_inds can be a completely separate buffer that is - //pre-initialized to draw 2-tri triangle strips as the actual indices will - //never change - size_t vert_size = MAX_QUADS * VERTS_PER_QUAD * sizeof (drawvert_t); - size_t ind_size = MAX_QUADS * INDS_PER_QUAD * sizeof (uint32_t); + drawctx_t *dctx = ctx->draw_context; + + size_t vert_size; + size_t ind_size; + size_t frames = ctx->framebuffers.size; + VkBuffer vbuf, ibuf; + VkDeviceMemory vmem, imem; + + vert_size = frames * MAX_QUADS * VERTS_PER_QUAD * sizeof (drawvert_t); + ind_size = MAX_QUADS * INDS_PER_QUAD * sizeof (uint32_t); + + vbuf = QFV_CreateBuffer (device, vert_size, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + ibuf = QFV_CreateBuffer (device, ind_size, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + vmem = QFV_AllocBufferMemory (device, vbuf, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + vert_size, 0); + imem = QFV_AllocBufferMemory (device, ibuf, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + ind_size, 0); + QFV_BindBufferMemory (device, vbuf, vmem, 0); + QFV_BindBufferMemory (device, ibuf, imem, 0); + + dctx->vert_buffer = vbuf; + dctx->vert_memory = vmem; + dctx->ind_buffer = ibuf; + dctx->ind_memory = imem; - quad_vert_buffer = QFV_CreateBuffer (device, vert_size, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - quad_ind_buffer = QFV_CreateBuffer (device, ind_size, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT); - quad_memory = QFV_AllocBufferMemory (device, quad_vert_buffer, - VK_MEMORY_PROPERTY_HOST_CACHED_BIT, - vert_size + ind_size, 0); - QFV_BindBufferMemory (device, quad_vert_buffer, quad_memory, 0); - QFV_BindBufferMemory (device, quad_ind_buffer, quad_memory, vert_size); void *data; - dfunc->vkMapMemory (device->dev, quad_memory, 0, vert_size + ind_size, - 0, &data); - quad_verts = data; - quad_inds = (uint32_t *) (quad_verts + MAX_QUADS * VERTS_PER_QUAD); - // pre-initialize quad_inds as the indices will never change - uint32_t *ind = quad_inds; + dfunc->vkMapMemory (device->dev, vmem, 0, vert_size, 0, &data); + drawvert_t *vert_data = data; + + for (size_t f = 0; f < frames; f++) { + drawframe_t *frame = &dctx->frames.a[f]; + size_t ind = f * MAX_QUADS * VERTS_PER_QUAD; + frame->vert_offset = ind * sizeof (drawvert_t); + frame->verts = vert_data + ind; + frame->num_quads = 0; + } + + // The indices will never change so pre-generate and stash them + qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); + uint32_t *ind = QFV_PacketExtend (packet, ind_size); for (int i = 0; i < MAX_QUADS; i++) { for (int j = 0; j < VERTS_PER_QUAD; j++) { *ind++ = i * VERTS_PER_QUAD + j; @@ -136,11 +168,10 @@ create_quad_buffers (vulkan_ctx_t *ctx) // mark end of primitive *ind++ = -1; } - VkMappedMemoryRange range = { - VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, - quad_memory, vert_size, ind_size, - }; - dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); + VkBufferCopy copy_region = { packet->offset, 0, ind_size }; + dfunc->vkCmdCopyBuffer (packet->cmd, ctx->staging->buffer, ibuf, + 1, ©_region); + QFV_PacketSubmit (packet); } static void @@ -148,17 +179,19 @@ destroy_quad_buffers (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + drawctx_t *dctx = ctx->draw_context; - dfunc->vkUnmapMemory (device->dev, quad_memory); - dfunc->vkFreeMemory (device->dev, quad_memory, 0); - dfunc->vkDestroyBuffer (device->dev, quad_vert_buffer, 0); - dfunc->vkDestroyBuffer (device->dev, quad_ind_buffer, 0); + dfunc->vkUnmapMemory (device->dev, dctx->vert_memory); + dfunc->vkFreeMemory (device->dev, dctx->vert_memory, 0); + dfunc->vkFreeMemory (device->dev, dctx->ind_memory, 0); + dfunc->vkDestroyBuffer (device->dev, dctx->vert_buffer, 0); + dfunc->vkDestroyBuffer (device->dev, dctx->ind_buffer, 0); } static void flush_draw_scrap (vulkan_ctx_t *ctx) { - QFV_ScrapFlush (draw_scrap); + QFV_ScrapFlush (ctx->draw_context->scrap); } static void @@ -197,7 +230,7 @@ cachepic_getkey (const void *_cp, void *unused) } static qpic_t * -pic_data (const char *name, int w, int h, const byte *data, vulkan_ctx_t *ctx) +pic_data (const char *name, int w, int h, const byte *data, drawctx_t *dctx) { qpic_t *pic; subpic_t *subpic; @@ -207,10 +240,10 @@ pic_data (const char *name, int w, int h, const byte *data, vulkan_ctx_t *ctx) pic->width = w; pic->height = h; - subpic = QFV_ScrapSubpic (draw_scrap, w, h); + subpic = QFV_ScrapSubpic (dctx->scrap, w, h); *(subpic_t **) pic->data = subpic; - picdata = QFV_SubpicBatch (subpic, draw_stage); + picdata = QFV_SubpicBatch (subpic, dctx->stage); size_t size = w * h; for (size_t i = 0; i < size; i++) { byte pix = *data++; @@ -227,7 +260,7 @@ qpic_t * Vulkan_Draw_MakePic (int width, int height, const byte *data, vulkan_ctx_t *ctx) { - return pic_data (0, width, height, data, ctx); + return pic_data (0, width, height, data, ctx->draw_context); } void @@ -243,7 +276,7 @@ Vulkan_Draw_PicFromWad (const char *name, vulkan_ctx_t *ctx) if (!wadpic) { return 0; } - return pic_data (name, wadpic->width, wadpic->height, wadpic->data, ctx); + return pic_data (name, wadpic->width, wadpic->height, wadpic->data, ctx->draw_context); } qpic_t * @@ -252,8 +285,9 @@ Vulkan_Draw_CachePic (const char *path, qboolean alpha, vulkan_ctx_t *ctx) qpic_t *p; qpic_t *pic; cachepic_t *cpic; + drawctx_t *dctx = ctx->draw_context; - if ((cpic = Hash_Find (pic_cache, path))) { + if ((cpic = Hash_Find (dctx->pic_cache, path))) { return cpic->pic; } if (strlen (path) < 4 || strcmp (path + strlen (path) - 4, ".lmp") @@ -261,17 +295,18 @@ Vulkan_Draw_CachePic (const char *path, qboolean alpha, vulkan_ctx_t *ctx) return 0; } - pic = pic_data (path, p->width, p->height, p->data, ctx); + pic = pic_data (path, p->width, p->height, p->data, dctx); free (p); cpic = new_cachepic (path, pic); - Hash_Add (pic_cache, cpic); + Hash_Add (dctx->pic_cache, cpic); return pic; } void Vulkan_Draw_UncachePic (const char *path, vulkan_ctx_t *ctx) { - Hash_Free (pic_cache, Hash_Del (pic_cache, path)); + drawctx_t *dctx = ctx->draw_context; + Hash_Free (dctx->pic_cache, Hash_Del (dctx->pic_cache, path)); } void @@ -285,12 +320,13 @@ Vulkan_Draw_Shutdown (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + drawctx_t *dctx = ctx->draw_context; destroy_quad_buffers (ctx); - dfunc->vkDestroyPipeline (device->dev, twod_pipeline, 0); - QFV_DestroyScrap (draw_scrap); - QFV_DestroyStagingBuffer (draw_stage); + dfunc->vkDestroyPipeline (device->dev, dctx->pipeline, 0); + QFV_DestroyScrap (dctx->scrap); + QFV_DestroyStagingBuffer (dctx->stage); } void @@ -299,26 +335,35 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - //FIXME move into struct - pic_cache = Hash_NewTable (127, cachepic_getkey, cachepic_free, 0, 0); + drawctx_t *dctx = calloc (1, sizeof (drawctx_t)); + ctx->draw_context = dctx; + + size_t frames = ctx->framebuffers.size; + DARRAY_INIT (&dctx->frames, frames); + DARRAY_RESIZE (&dctx->frames, frames); + dctx->frames.grow = 0; + + dctx->pic_cache = Hash_NewTable (127, cachepic_getkey, cachepic_free, + 0, 0); create_quad_buffers (ctx); - draw_scrap = QFV_CreateScrap (device, 2048, QFV_RGBA); - draw_stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024, 4, - ctx->cmdpool); - conchars_sampler = QFV_GetSampler (ctx, "quakepic"); + dctx->scrap = QFV_CreateScrap (device, 2048, QFV_RGBA); + dctx->stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024, 4, + ctx->cmdpool); + dctx->sampler = QFV_GetSampler (ctx, "quakepic"); qpic_t *charspic = Draw_Font8x8Pic (); - conchars = pic_data (0, charspic->width, charspic->height, charspic->data, ctx); + dctx->conchars = pic_data ("conchars", charspic->width, charspic->height, + charspic->data, dctx); byte white_block = 0xfe; - white_pic = pic_data (0, 1, 1, &white_block, ctx); + dctx->white_pic = pic_data ("white", 1, 1, &white_block, dctx); flush_draw_scrap (ctx); - twod_pipeline = Vulkan_CreatePipeline (ctx, "twod"); + dctx->pipeline = Vulkan_CreatePipeline (ctx, "twod"); - twod_layout = QFV_GetPipelineLayout (ctx, "twod"); + dctx->layout = QFV_GetPipelineLayout (ctx, "twod"); __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (ctx->framebuffers.size, alloca); for (size_t i = 0; i < layouts->size; i++) { @@ -330,32 +375,32 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) ctx->matrices.buffer_2d, 0, VK_WHOLE_SIZE }; VkDescriptorImageInfo imageInfo = { - conchars_sampler, - QFV_ScrapImageView (draw_scrap), + dctx->sampler, + QFV_ScrapImageView (dctx->scrap), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; - size_t frames = ctx->framebuffers.size; __auto_type cmdBuffers = QFV_AllocCommandBufferSet (frames, alloca); QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); __auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); for (size_t i = 0; i < frames; i++) { - __auto_type frame = &ctx->framebuffers.a[i]; - frame->twodDescriptors = sets->a[i]; + __auto_type cframe = &ctx->framebuffers.a[i]; + __auto_type dframe = &dctx->frames.a[i]; + dframe->descriptors = sets->a[i]; VkWriteDescriptorSet write[] = { { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, - frame->twodDescriptors, 0, 0, 1, + dframe->descriptors, 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &bufferInfo, 0 }, { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, - frame->twodDescriptors, 1, 0, 1, + dframe->descriptors, 1, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageInfo, 0, 0 }, }; dfunc->vkUpdateDescriptorSets (device->dev, 2, write, 0, 0); - draw_cmdBuffer = frame->subCommand->size; - DARRAY_APPEND (frame->subCommand, cmdBuffers->a[i]); + dframe->cmd = cmdBuffers->a[i]; + DARRAY_APPEND (cframe->subCommand, cmdBuffers->a[i]); } free (sets); } @@ -363,14 +408,14 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) static inline void draw_pic (float x, float y, int w, int h, qpic_t *pic, int srcx, int srcy, int srcw, int srch, - float *color) + float *color, drawframe_t *frame) { - if (num_quads + VERTS_PER_QUAD > MAX_QUADS) { + if (frame->num_quads + VERTS_PER_QUAD > MAX_QUADS) { return; } - drawvert_t *verts = quad_verts + num_quads * VERTS_PER_QUAD; - num_quads += VERTS_PER_QUAD; + drawvert_t *verts = frame->verts + frame->num_quads * VERTS_PER_QUAD; + frame->num_quads += VERTS_PER_QUAD; subpic_t *subpic = *(subpic_t **) pic->data; srcx += subpic->rect->x; @@ -410,12 +455,15 @@ draw_pic (float x, float y, int w, int h, qpic_t *pic, static inline void queue_character (int x, int y, byte chr, vulkan_ctx_t *ctx) { + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + quat_t color = {1, 1, 1, 1}; int cx, cy; cx = chr % 16; cy = chr / 16; - draw_pic (x, y, 8, 8, conchars, cx * 8, cy * 8, 8, 8, color); + draw_pic (x, y, 8, 8, dctx->conchars, cx * 8, cy * 8, 8, 8, color, frame); } void @@ -505,17 +553,23 @@ Vulkan_Draw_Crosshair (vulkan_ctx_t *ctx) void Vulkan_Draw_Pic (int x, int y, qpic_t *pic, vulkan_ctx_t *ctx) { + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + static quat_t color = { 1, 1, 1, 1}; draw_pic (x, y, pic->width, pic->height, pic, - 0, 0, pic->width, pic->height, color); + 0, 0, pic->width, pic->height, color, frame); } void Vulkan_Draw_Picf (float x, float y, qpic_t *pic, vulkan_ctx_t *ctx) { + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + static quat_t color = { 1, 1, 1, 1}; draw_pic (x, y, pic->width, pic->height, pic, - 0, 0, pic->width, pic->height, color); + 0, 0, pic->width, pic->height, color, frame); } void @@ -523,8 +577,12 @@ Vulkan_Draw_SubPic (int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height, vulkan_ctx_t *ctx) { + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + static quat_t color = { 1, 1, 1, 1}; - draw_pic (x, y, width, height, pic, srcx, srcy, width, height, color); + draw_pic (x, y, width, height, pic, srcx, srcy, width, height, + color, frame); } void @@ -540,24 +598,31 @@ Vulkan_Draw_TileClear (int x, int y, int w, int h, vulkan_ctx_t *ctx) void Vulkan_Draw_Fill (int x, int y, int w, int h, int c, vulkan_ctx_t *ctx) { + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + quat_t color; VectorScale (vid.palette + c * 3, 1.0f/255.0f, color); color[3] = 1; - draw_pic (x, y, w, h, white_pic, 0, 0, 1, 1, color); + draw_pic (x, y, w, h, dctx->white_pic, 0, 0, 1, 1, color, frame); } static inline void -draw_blendscreen (quat_t color) +draw_blendscreen (quat_t color, vulkan_ctx_t *ctx) { - draw_pic (0, 0, vid.conwidth, vid.conheight, white_pic, 0, 0, 1, 1, color); + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + + draw_pic (0, 0, vid.conwidth, vid.conheight, dctx->white_pic, 0, 0, 1, 1, + color, frame); } void Vulkan_Draw_FadeScreen (vulkan_ctx_t *ctx) { static quat_t color = { 0, 0, 0, 0.7 }; - draw_blendscreen (color); + draw_blendscreen (color, ctx); } void @@ -587,12 +652,16 @@ Vulkan_FlushText (vulkan_ctx_t *ctx) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - __auto_type frame = &ctx->framebuffers.a[ctx->curFrame]; - VkCommandBuffer cmd = frame->subCommand->a[draw_cmdBuffer]; + __auto_type cframe = &ctx->framebuffers.a[ctx->curFrame]; + drawctx_t *dctx = ctx->draw_context; + drawframe_t *dframe = &dctx->frames.a[ctx->curFrame]; + + VkCommandBuffer cmd = dframe->cmd; VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, - quad_memory, 0, num_quads * VERTS_PER_QUAD * sizeof (drawvert_t), + dctx->vert_memory, dframe->vert_offset, + dframe->num_quads * VERTS_PER_QUAD * sizeof (drawvert_t), }; dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); @@ -600,7 +669,7 @@ Vulkan_FlushText (vulkan_ctx_t *ctx) VkCommandBufferInheritanceInfo inherit = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, ctx->renderpass.renderpass, 0, - frame->framebuffer, + cframe->framebuffer, 0, 0, 0 }; VkCommandBufferBeginInfo beginInfo = { @@ -611,30 +680,31 @@ Vulkan_FlushText (vulkan_ctx_t *ctx) dfunc->vkBeginCommandBuffer (cmd, &beginInfo); dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - twod_pipeline); + dctx->pipeline); VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); - VkDeviceSize offsets[] = {0}; - dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &quad_vert_buffer, offsets); - dfunc->vkCmdBindIndexBuffer (cmd, quad_ind_buffer, 0, + VkDeviceSize offsets[] = {dframe->vert_offset}; + dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &dctx->vert_buffer, offsets); + dfunc->vkCmdBindIndexBuffer (cmd, dctx->ind_buffer, 0, VK_INDEX_TYPE_UINT32); - VkDescriptorSet set = frame->twodDescriptors; - VkPipelineLayout layout = twod_layout; + VkDescriptorSet set = dframe->descriptors; + VkPipelineLayout layout = dctx->layout; dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 1, &set, 0, 0); - dfunc->vkCmdDrawIndexed (cmd, num_quads * INDS_PER_QUAD, 1, 0, 0, 0); + dfunc->vkCmdDrawIndexed (cmd, dframe->num_quads * INDS_PER_QUAD, + 1, 0, 0, 0); dfunc->vkEndCommandBuffer (cmd); - num_quads = 0; + dframe->num_quads = 0; } void Vulkan_Draw_BlendScreen (quat_t color, vulkan_ctx_t *ctx) { if (color[3]) { - draw_blendscreen (color); + draw_blendscreen (color, ctx); } } From 0150fc0487c93a26a901d2cce6cdfac36ba09002 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 16 Jan 2021 15:09:39 +0900 Subject: [PATCH 235/435] [vulkan] Use pipeline barriers for index buffer And set the usage correctly. --- libs/video/renderer/vulkan/vulkan_draw.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 43068ae52..2b9642554 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -131,7 +131,8 @@ create_quad_buffers (vulkan_ctx_t *ctx) vbuf = QFV_CreateBuffer (device, vert_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); ibuf = QFV_CreateBuffer (device, ind_size, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + VK_BUFFER_USAGE_INDEX_BUFFER_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT); vmem = QFV_AllocBufferMemory (device, vbuf, VK_MEMORY_PROPERTY_HOST_CACHED_BIT, vert_size, 0); @@ -168,9 +169,28 @@ create_quad_buffers (vulkan_ctx_t *ctx) // mark end of primitive *ind++ = -1; } + + VkBufferMemoryBarrier wr_barrier = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, ibuf, 0, ind_size + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 1, &wr_barrier, 0, 0); VkBufferCopy copy_region = { packet->offset, 0, ind_size }; dfunc->vkCmdCopyBuffer (packet->cmd, ctx->staging->buffer, ibuf, 1, ©_region); + VkBufferMemoryBarrier rd_barrier = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, ibuf, 0, ind_size + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + 0, 0, 0, 1, &rd_barrier, 0, 0); QFV_PacketSubmit (packet); } From fa6ff04c5ae5cc7b611abd69ffae15a62ecdd2ce Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 16 Jan 2021 15:39:16 +0900 Subject: [PATCH 236/435] [image] Use an enum for tex_t formats --- include/QF/image.h | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/include/QF/image.h b/include/QF/image.h index 106379bb7..396547f42 100644 --- a/include/QF/image.h +++ b/include/QF/image.h @@ -29,23 +29,26 @@ #ifndef __QF_image_h #define __QF_image_h -#include "QF/quakeio.h" +#include "QF/qtypes.h" + +typedef enum QFFormat { + tex_palette = 0, + tex_l = 0x1909, //GL_LUMINANCE + tex_a = 0x1906, //GL_ALPHA + tex_la = 2, + tex_rgb = 3, + tex_rgba = 4, +} QFFormat; // could not use texture_t as that is used for models. typedef struct tex_s { - int width; - int height; - int format; - unsigned char *palette; // 0 = 32 bit, otherwise 8 - unsigned char data[4]; // variable length + int width; + int height; + QFFormat format; + byte *palette; // 0 = 32 bit, otherwise 8 + byte data[4]; // variable length } tex_t; -#define tex_palette 0 -#define tex_l 0x1909 //GL_LUMINANCE -#define tex_a 0x1906 //GL_ALPHA -#define tex_la 2 -#define tex_rgb 3 -#define tex_rgba 4 tex_t *LoadImage (const char *imageFile); From f3695ec3dd93e446b70040a9fa44b4d03c28ca67 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 16 Jan 2021 15:39:36 +0900 Subject: [PATCH 237/435] [vulkan] Use the previously existing tex_t formats I'd forgotten we had these (though direct GL_* was used). --- include/QF/Vulkan/texture.h | 9 ++------- libs/video/renderer/vulkan/texture.c | 13 ++++++++----- libs/video/renderer/vulkan/vulkan_draw.c | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/include/QF/Vulkan/texture.h b/include/QF/Vulkan/texture.h index e24fa0eb1..39f5b07f2 100644 --- a/include/QF/Vulkan/texture.h +++ b/include/QF/Vulkan/texture.h @@ -1,17 +1,12 @@ #ifndef __QF_Vulkan_texture_h #define __QF_Vulkan_texture_h -typedef enum { - QFV_LUMINANCE, - QFV_LUMINANCE_ALPHA, - QFV_RGB, - QFV_RGBA, -} QFVFormat; +#include "QF/image.h" typedef struct scrap_s scrap_t; scrap_t *QFV_CreateScrap (struct qfv_device_s *device, int size, - QFVFormat format); + QFFormat format); void QFV_ScrapClear (scrap_t *scrap); void QFV_DestroyScrap (scrap_t *scrap); VkImageView QFV_ScrapImageView (scrap_t *scrap) __attribute__((pure)); diff --git a/libs/video/renderer/vulkan/texture.c b/libs/video/renderer/vulkan/texture.c index f23e1297a..b4eacf0e6 100644 --- a/libs/video/renderer/vulkan/texture.c +++ b/libs/video/renderer/vulkan/texture.c @@ -42,6 +42,7 @@ #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/hash.h" +#include "QF/image.h" #include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/render.h" @@ -75,25 +76,27 @@ struct scrap_s { }; scrap_t * -QFV_CreateScrap (qfv_device_t *device, int size, QFVFormat format) +QFV_CreateScrap (qfv_device_t *device, int size, QFFormat format) { int bpp = 0; VkFormat fmt = VK_FORMAT_UNDEFINED; switch (format) { - case QFV_LUMINANCE: + case tex_l: + case tex_a: + case tex_palette: bpp = 1; fmt = VK_FORMAT_R8_UNORM; break; - case QFV_LUMINANCE_ALPHA: + case tex_la: bpp = 2; fmt = VK_FORMAT_R8G8_UNORM; break; - case QFV_RGB: + case tex_rgb: bpp = 3; fmt = VK_FORMAT_R8G8B8_UNORM; break; - case QFV_RGBA: + case tex_rgba: bpp = 4; fmt = VK_FORMAT_R8G8B8A8_UNORM; break; diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 2b9642554..e94f971f0 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -367,7 +367,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) 0, 0); create_quad_buffers (ctx); - dctx->scrap = QFV_CreateScrap (device, 2048, QFV_RGBA); + dctx->scrap = QFV_CreateScrap (device, 2048, tex_rgba); dctx->stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024, 4, ctx->cmdpool); dctx->sampler = QFV_GetSampler (ctx, "quakepic"); From 7282d2addea795de15a81b5d762e39735cd4a219 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 16 Jan 2021 20:27:48 +0900 Subject: [PATCH 238/435] [vulkan] Make renderpass dependencies more explicit Doesn't seem to adversely affect anything and is more correct from what I can tell reading some other documentation. --- libs/video/renderer/vulkan/qfpipeline.plist | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 385713c80..2f3ef7445 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -254,12 +254,21 @@ { srcSubpass = VK_SUBPASS_EXTERNAL; dstSubpass = 0; - srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - srcAccessMask = 0; - dstAccessMask = "VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT"; - dependencyFlags = 0; - } + srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + }, + { + srcSubpass = 0; + dstSubpass = VK_SUBPASS_EXTERNAL; + srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + }, ); }; } From fd8521da76d2d32dcef064297747c3da8b9f78c8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 16 Jan 2021 21:03:36 +0900 Subject: [PATCH 239/435] [vulkan] Make frame-buffer count available to It turns out I made a bit of a mistake in tying the frame-buffer count to the number of swapchain images. This is the first step in sorting that out. --- libs/video/renderer/vulkan/vkparse.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index cd5e98502..0fc00b835 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -535,6 +535,21 @@ exprtype_t qfv_swapchain_t_type = { &qfv_swapchain_t_symtab, }; +static exprsym_t vulkan_framebufferset_t_symbols[] = { + {"size", &cexpr_size_t, (void *)field_offset (vulkan_framebufferset_t, size)}, + { } +}; +static exprtab_t vulkan_framebufferset_t_symtab = { + vulkan_framebufferset_t_symbols, +}; +exprtype_t vulkan_framebufferset_t_type = { + "framebufferset", + sizeof (vulkan_framebufferset_t *), + cexpr_struct_binops, + 0, + &vulkan_framebufferset_t_symtab, +}; + typedef struct qfv_renderpass_s { qfv_attachmentdescription_t *attachments; qfv_subpassparametersset_t *subpasses; @@ -588,6 +603,7 @@ QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *pipelinedef) plitem_t *messages = PL_NewArray (); exprsym_t var_syms[] = { {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, + {"framebuffers", &vulkan_framebufferset_t_type, &ctx->framebuffers}, {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, {} }; @@ -645,6 +661,7 @@ QFV_InitParse (vulkan_ctx_t *ctx) context.hashlinks = &ctx->hashlinks; vkgen_init_symtabs (&context); cexpr_init_symtab (&qfv_swapchain_t_symtab, &context); + cexpr_init_symtab (&vulkan_framebufferset_t_symtab, &context); cexpr_init_symtab (&imageset_symtab, &context); } @@ -663,6 +680,7 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) VkRenderPass renderpass; exprsym_t var_syms[] = { {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, + {"framebuffers", &vulkan_framebufferset_t_type, &ctx->framebuffers}, {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, {} }; From 8078e10ea18e3326a5fb79f5f79086cd794d9fcd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 16 Jan 2021 21:24:42 +0900 Subject: [PATCH 240/435] [vulkan] Make frame-buffers independent of swapchain This is more correct as the environment (X11 etc) might provide more swapchain images than we want: 3 frames in flight is generally considered a good balance between saturating the hardware and latency. --- libs/video/renderer/vid_render_vulkan.c | 19 +++++++++++++++++-- libs/video/renderer/vulkan/qfpipeline.plist | 6 +++--- .../video/renderer/vulkan/vulkan_vid_common.c | 14 ++------------ 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index f68e8c182..646a3b740 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -45,6 +45,7 @@ #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" +#include "QF/Vulkan/renderpass.h" #include "QF/Vulkan/swapchain.h" #include "mod_internal.h" @@ -62,8 +63,8 @@ vulkan_R_Init (void) Vulkan_CreateStagingBuffers (vulkan_ctx); Vulkan_CreateMatrices (vulkan_ctx); Vulkan_CreateSwapchain (vulkan_ctx); - Vulkan_CreateRenderPass (vulkan_ctx); Vulkan_CreateFramebuffers (vulkan_ctx); + Vulkan_CreateRenderPass (vulkan_ctx); // FIXME this should be staged so screen updates can begin while pipelines // are being built vulkan_ctx->pipeline = Vulkan_CreatePipeline (vulkan_ctx, "pipeline"); @@ -100,13 +101,27 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) = &vulkan_ctx->framebuffers.a[vulkan_ctx->curFrame]; dfunc->vkWaitForFences (dev, 1, &framebuffer->fence, VK_TRUE, 2000000000); + if (framebuffer->framebuffer) { + dfunc->vkDestroyFramebuffer (dev, framebuffer->framebuffer, 0); + } QFV_AcquireNextImage (vulkan_ctx->swapchain, framebuffer->imageAvailableSemaphore, 0, &imageIndex); + __auto_type attachments = DARRAY_ALLOCFIXED (qfv_imageviewset_t, 3, + alloca); + qfv_swapchain_t *sc = vulkan_ctx->swapchain; + attachments->a[0] = vulkan_ctx->renderpass.colorImage->view; + attachments->a[1] = vulkan_ctx->renderpass.depthImage->view; + attachments->a[2] = sc->imageViews->a[imageIndex]; + + VkRenderPass renderpass = vulkan_ctx->renderpass.renderpass; + framebuffer->framebuffer = QFV_CreateFramebuffer (device, renderpass, + attachments, + sc->extent, 1); + Vulkan_FlushText (vulkan_ctx); - qfv_swapchain_t *sc = vulkan_ctx->swapchain; VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; VkClearValue clearValues[2] = { diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 2f3ef7445..4bc6017e9 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -32,15 +32,15 @@ descriptorPools = { twod = { flags = 0; - maxSets = $swapchain.images.size; + maxSets = $framebuffers.size; bindings = ( { type = uniform_buffer; - descriptorCount = $swapchain.images.size; + descriptorCount = $framebuffers.size; }, { type = combined_image_sampler; - descriptorCount = $swapchain.images.size; + descriptorCount = $framebuffers.size; }, ); }; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index a40e38c52..3d317f52c 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -387,30 +387,20 @@ Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; VkCommandPool cmdpool = ctx->cmdpool; - qfv_swapchain_t *sc = ctx->swapchain; - VkRenderPass renderpass = ctx->renderpass.renderpass; if (!ctx->framebuffers.grow) { DARRAY_INIT (&ctx->framebuffers, 4); } - DARRAY_RESIZE (&ctx->framebuffers, sc->numImages); - - __auto_type attachments = DARRAY_ALLOCFIXED (qfv_imageviewset_t, 3, - alloca); - attachments->a[0] = ctx->renderpass.colorImage->view; - attachments->a[1] = ctx->renderpass.depthImage->view; + DARRAY_RESIZE (&ctx->framebuffers, 3);//FIXME cvar __auto_type cmdBuffers = QFV_AllocCommandBufferSet (ctx->framebuffers.size, alloca); QFV_AllocateCommandBuffers (device, cmdpool, 0, cmdBuffers); for (size_t i = 0; i < ctx->framebuffers.size; i++) { - attachments->a[2] = sc->imageViews->a[i]; __auto_type frame = &ctx->framebuffers.a[i]; - frame->framebuffer = QFV_CreateFramebuffer (device, renderpass, - attachments, - sc->extent, 1); + frame->framebuffer = 0; frame->fence = QFV_CreateFence (device, 1); frame->imageAvailableSemaphore = QFV_CreateSemaphore (device); frame->renderDoneSemaphore = QFV_CreateSemaphore (device); From debaffcb97f8bd968bb716b531d791faf87517e4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 17 Jan 2021 22:26:48 +0900 Subject: [PATCH 241/435] [vulkan] Retain handle_keys item Ugh, need to come up with valgrind for ruamoko :P --- libs/video/renderer/vulkan/vkgen/vkgen.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r index 01637c54a..a336a861c 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.r +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -204,7 +204,7 @@ main(int argc, string *argv) } } - PLItem *handle_keys = [handles allKeys]; + PLItem *handle_keys = [[handles allKeys] retain]; for (int i = [handle_keys count]; i-- > 0; ) { string search_name = [[handle_keys getObjectAtIndex:i] string]; id obj = (id) Hash_Find (available_types, search_name); From 1e163fd2d73beca39f3729a95dcef51c3dab13e7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 18 Jan 2021 02:08:55 +0900 Subject: [PATCH 242/435] [vulkan] Correct QFV_CreateImage samples type Not sure why I though FlagBits was correct instead of Flags. --- include/QF/Vulkan/image.h | 2 +- libs/video/renderer/vulkan/image.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index edb5e025e..501a5025e 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -36,7 +36,7 @@ VkImage QFV_CreateImage (struct qfv_device_s *device, int cubemap, VkExtent3D size, uint32_t num_mipmaps, uint32_t num_layers, - VkSampleCountFlagBits samples, + VkSampleCountFlags samples, VkImageUsageFlags usage_scenarios); VkDeviceMemory QFV_AllocImageMemory (struct qfv_device_s *device, diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index 68decb94a..bd71cc162 100644 --- a/libs/video/renderer/vulkan/image.c +++ b/libs/video/renderer/vulkan/image.c @@ -68,7 +68,7 @@ QFV_CreateImage (qfv_device_t *device, int cubemap, VkExtent3D size, uint32_t num_mipmaps, uint32_t num_layers, - VkSampleCountFlagBits samples, + VkSampleCountFlags samples, VkImageUsageFlags usage_scenarios) { VkDevice dev = device->dev; From aa7ff9d6188b579c5169380c6b9afcf1d686eb25 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 18 Jan 2021 02:10:10 +0900 Subject: [PATCH 243/435] [vulkan] Implement console background drawing That went better than expected after deciding to put the conback in the scrap. --- libs/video/renderer/vulkan/vulkan_draw.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index e94f971f0..7aadd6692 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -608,6 +608,15 @@ Vulkan_Draw_SubPic (int x, int y, qpic_t *pic, void Vulkan_Draw_ConsoleBackground (int lines, byte alpha, vulkan_ctx_t *ctx) { + drawctx_t *dctx = ctx->draw_context; + drawframe_t *frame = &dctx->frames.a[ctx->curFrame]; + + quat_t color = { 1, 1, 1, bound (0, alpha, 255) / 255.0}; + qpic_t *cpic; + cpic = Vulkan_Draw_CachePic ("gfx/conback.lmp", false, ctx); + int ofs = max (0, cpic->height - lines); + draw_pic (0, 0, vid.conwidth, lines, cpic, + 0, ofs, cpic->width, lines, color, frame); } void From abd3b900044ba9863978a524a355e8223908fa35 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 18 Jan 2021 02:10:56 +0900 Subject: [PATCH 244/435] [vulkan] Implement basic quake texture loading It optionally generates mipmaps, and supports the main texture types (especially for texture packs), including palettes, but is otherwise rather unsophisticated code. Needs a lot of work, but testing first. --- include/QF/Vulkan/funclist.h | 1 + include/QF/Vulkan/qf_texture.h | 13 + libs/video/renderer/Makemodule.am | 1 + libs/video/renderer/vulkan/vulkan_texture.c | 249 ++++++++++++++++++++ 4 files changed, 264 insertions(+) create mode 100644 include/QF/Vulkan/qf_texture.h create mode 100644 libs/video/renderer/vulkan/vulkan_texture.c diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 63c5bde29..209ee0561 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -162,6 +162,7 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPipelineBarrier) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBuffer) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyBufferToImage) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdCopyImageToBuffer) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBlitImage) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBeginRenderPass) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdNextSubpass) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdEndRenderPass) diff --git a/include/QF/Vulkan/qf_texture.h b/include/QF/Vulkan/qf_texture.h new file mode 100644 index 000000000..a1750682d --- /dev/null +++ b/include/QF/Vulkan/qf_texture.h @@ -0,0 +1,13 @@ +#ifndef __QF_Vulkan_qf_texture_h +#define __QF_Vulkan_qf_texture_h + +#include "QF/image.h" + +typedef struct qfv_tex_s qfv_tex_t; +struct vulkan_ctx_s; + +qfv_tex_t *Vulkan_LoadTex (struct vulkan_ctx_s *ctx, tex_t *tex, int mip); +VkImageView Vulkan_TexImageView (qfv_tex_t *tex) __attribute__((pure)); +void Vulkan_UnloadTex (struct vulkan_ctx_s *ctx, qfv_tex_t *tex); + +#endif//__QF_Vulkan_qf_texture_h diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 7a323f118..d44139a22 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -237,6 +237,7 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/vkparse.c \ libs/video/renderer/vulkan/vulkan_draw.c \ libs/video/renderer/vulkan/vulkan_matrices.c \ + libs/video/renderer/vulkan/vulkan_texture.c \ libs/video/renderer/vulkan/vulkan_vid_common.c libs/video/renderer/vulkan/vkparse.lo: libs/video/renderer/vulkan/vkparse.c $(vkparse_src) diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c new file mode 100644 index 000000000..0b2c2e102 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -0,0 +1,249 @@ +/* + vulkan_texuture.c + + Quake specific Vulkan texuture manager + + Copyright (C) 2021 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/image.h" +#include "QF/mathlib.h" +#include "QF/qfplist.h" +#include "QF/quakefs.h" +#include "QF/render.h" +#include "QF/sys.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/staging.h" +#include "QF/Vulkan/texture.h" + +#include "r_scrap.h" +#include "vid_vulkan.h" + +struct qfv_tex_s { // qfv_tex_t + VkDeviceMemory memory; + size_t offset; + VkImage image; + VkImageView view; +}; + +static int +ilog2 (unsigned x) +{ + if (x > 0x7fffffff) { + // avoid overflow + return 31; + } + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + int y = 0; + y |= ((x & 0xffff0000) != 0) << 4; + y |= ((x & 0xff00ff00) != 0) << 3; + y |= ((x & 0xf0f0f0f0) != 0) << 2; + y |= ((x & 0xcccccccc) != 0) << 1; + y |= ((x & 0xaaaaaaaa) != 0) << 0; + return y; +} + +qfv_tex_t * +Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + int bpp = 0; + VkFormat format = VK_FORMAT_UNDEFINED; + + switch (tex->format) { + case tex_l: + case tex_a: + format = VK_FORMAT_R8_UNORM; + bpp = 1; + break; + case tex_la: + format = VK_FORMAT_R8G8_UNORM; + bpp = 2; + break; + case tex_palette: + if (!tex->palette) { + return 0; + } + format = VK_FORMAT_R8G8B8_UNORM; + bpp = 3; + break; + case tex_rgb: + format = VK_FORMAT_R8G8B8_UNORM; + bpp = 3; + break; + case tex_rgba: + format = VK_FORMAT_R8G8B8A8_UNORM; + bpp = 4; + break; + } + if (format == VK_FORMAT_UNDEFINED) { + return 0; + } + + if (mip) { + mip = ilog2 (max (tex->width, tex->height)) + 1; + } else { + mip = 1; + } + + //qfv_devfuncs_t *dfunc = device->funcs; + //FIXME this whole thing is ineffiecient, especially for small textures + qfv_tex_t *qtex = malloc (sizeof (qfv_tex_t)); + + VkExtent3D extent = { tex->width, tex->height, 1 }; + qtex->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, format, extent, + mip, 1, VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT); + qtex->memory = QFV_AllocImageMemory (device, qtex->image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, 0); + QFV_BindImageMemory (device, qtex->image, qtex->memory, 0); + + size_t bytes = bpp * tex->width * tex->height; + qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); + byte *tex_data = QFV_PacketExtend (packet, bytes); + + if (tex->format == tex_palette) { + byte *data = tex->data; + for (size_t count = tex->width * tex->height; count-- > 0; ) { + byte pix = *data++; + byte *col = tex->palette + pix; + *tex_data++ = *col++; + *tex_data++ = *col++; + *tex_data++ = *col++; + } + } else { + memcpy (tex_data, tex->data, bytes); + } + + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.image = qtex->image; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + VkBufferImageCopy copy = { + packet->offset, 0, 0, + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, + {0, 0, 0}, {tex->width, tex->height, 1}, + }; + dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer, + qtex->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ©); + barrier.subresourceRange.baseMipLevel = 0; + stages.src = VK_PIPELINE_STAGE_TRANSFER_BIT; + stages.dst = VK_PIPELINE_STAGE_TRANSFER_BIT; + VkImageBlit blit = { + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, + {{0, 0, 0}, {tex->width, tex->height, 1}}, + {VK_IMAGE_ASPECT_COLOR_BIT, 1, 0, 1}, + {{0, 0, 0}, {(tex->width + 1) >> 1, (tex->height + 1) >> 1, 1}}, + }; + while (--mip > 0) { + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, + 0, 0, 0, 0, + 1, &barrier); + + dfunc->vkCmdBlitImage (packet->cmd, + qtex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + qtex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &blit, VK_FILTER_LINEAR); + + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, + 0, 0, 0, 0, + 1, &barrier); + + blit.srcSubresource.mipLevel++; + blit.srcOffsets[1].x = blit.dstOffsets[1].x; + blit.srcOffsets[1].y = blit.dstOffsets[1].y; + blit.dstSubresource.mipLevel++; + blit.dstOffsets[1].x = (blit.dstOffsets[1].x + 1) >> 1; + blit.dstOffsets[1].y = (blit.dstOffsets[1].y + 1) >> 1; + barrier.subresourceRange.baseMipLevel++; + } + QFV_PacketSubmit (packet); + return 0; +} + +VkImageView +Vulkan_TexImageView (qfv_tex_t *tex) +{ + return tex->view; +} + +void +Vulkan_UnloadTex (vulkan_ctx_t *ctx, qfv_tex_t *tex) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyImageView (device->dev, tex->view, 0); + dfunc->vkDestroyImage (device->dev, tex->image, 0); + dfunc->vkFreeMemory (device->dev, tex->memory, 0); + free (tex); +} From dacda501300b0b72a1b3a2a3d719916ba9b88384 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 18 Jan 2021 12:46:06 +0900 Subject: [PATCH 245/435] [renderer] Stub out all the vulkan functions nq-x11 now gets through all three demos without crashing (but without rendering anything useful, though). --- include/QF/Vulkan/qf_particles.h | 15 + include/r_dynamic.h | 6 - include/r_internal.h | 1 + libs/models/alias/gl_model_alias.c | 2 +- libs/video/renderer/Makemodule.am | 1 + libs/video/renderer/gl/gl_dyn_part.c | 42 +-- libs/video/renderer/glsl/glsl_particles.c | 42 +-- libs/video/renderer/r_efrag.c | 2 +- libs/video/renderer/sw/sw_rpart.c | 92 +++--- libs/video/renderer/sw32/sw32_rpart.c | 94 +++--- libs/video/renderer/vid_render_vulkan.c | 201 +++++++++++-- libs/video/renderer/vulkan/vulkan_particles.c | 268 ++++++++++++++++++ 12 files changed, 596 insertions(+), 170 deletions(-) create mode 100644 include/QF/Vulkan/qf_particles.h create mode 100644 libs/video/renderer/vulkan/vulkan_particles.c diff --git a/include/QF/Vulkan/qf_particles.h b/include/QF/Vulkan/qf_particles.h new file mode 100644 index 000000000..3ac71ac71 --- /dev/null +++ b/include/QF/Vulkan/qf_particles.h @@ -0,0 +1,15 @@ +#ifndef __QF_Vulkan_qf_particles_h +#define __QF_Vulkan_qf_particles_h + +#include "QF/image.h" + +struct cvar_s; +struct vulkan_ctx_s;; + +void Vulkan_R_ClearParticles (struct vulkan_ctx_s *ctx); +void Vulkan_R_InitParticles (struct vulkan_ctx_s *ctx); +void Vulkan_r_easter_eggs_f (struct cvar_s *var, struct vulkan_ctx_s *ctx); +void Vulkan_r_particles_style_f (struct cvar_s *var, struct vulkan_ctx_s *ctx); +void Vulkan_Particles_Init (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_particles_h diff --git a/include/r_dynamic.h b/include/r_dynamic.h index 1dd54fc11..8968cfa1c 100644 --- a/include/r_dynamic.h +++ b/include/r_dynamic.h @@ -49,12 +49,6 @@ void R_PushDlights (const vec3_t entorigin); struct cvar_s; void R_MaxDlightsCheck (struct cvar_s *var); void R_Particles_Init_Cvars (void); -void R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, - float ramp); -void R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, - int org_fuzz, float scale, int vel_fuzz, float die, - int color, float alpha, float ramp); void R_InitBubble (void); void R_InitParticles (void); diff --git a/include/r_internal.h b/include/r_internal.h index de11978fa..b38f1706c 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -16,6 +16,7 @@ extern vid_render_funcs_t gl_vid_render_funcs; extern vid_render_funcs_t glsl_vid_render_funcs; extern vid_render_funcs_t sw_vid_render_funcs; extern vid_render_funcs_t sw32_vid_render_funcs; +extern vid_render_funcs_t vulkan_vid_render_funcs; extern vid_render_funcs_t *vid_render_funcs; #define vr_data vid_render_data diff --git a/libs/models/alias/gl_model_alias.c b/libs/models/alias/gl_model_alias.c index 63618451e..5d09f93b7 100644 --- a/libs/models/alias/gl_model_alias.c +++ b/libs/models/alias/gl_model_alias.c @@ -53,7 +53,7 @@ #include "compat.h" void * -gl_Mod_LoadSkin (byte * skin, int skinsize, int snum, int gnum, qboolean group, +gl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc) { byte *pskin; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index d44139a22..b58aaf3af 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -237,6 +237,7 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/vkparse.c \ libs/video/renderer/vulkan/vulkan_draw.c \ libs/video/renderer/vulkan/vulkan_matrices.c \ + libs/video/renderer/vulkan/vulkan_particles.c \ libs/video/renderer/vulkan/vulkan_texture.c \ libs/video/renderer/vulkan/vulkan_vid_common.c diff --git a/libs/video/renderer/gl/gl_dyn_part.c b/libs/video/renderer/gl/gl_dyn_part.c index 5b7f1a63a..0572efec0 100644 --- a/libs/video/renderer/gl/gl_dyn_part.c +++ b/libs/video/renderer/gl/gl_dyn_part.c @@ -1591,6 +1591,27 @@ gl_R_DrawParticles (void) qfglDepthMask (GL_TRUE); } +static void +gl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, + const vec3_t vel, float die, int color, float alpha, + float ramp) +{ + if (numparticles >= r_maxparticles) + return; + particle_new (type, texnum, org, scale, vel, die, color, alpha, ramp); +} + +static void +gl_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, + int org_fuzz, float scale, int vel_fuzz, float die, + int color, float alpha, float ramp) +{ + if (numparticles >= r_maxparticles) + return; + particle_new_random (type, texnum, org, org_fuzz, scale, vel_fuzz, die, + color, alpha, ramp); +} + static vid_particle_funcs_t particles_QF = { R_RocketTrail_QF, R_GrenadeTrail_QF, @@ -1775,24 +1796,3 @@ gl_R_Particles_Init_Cvars (void) "0 for Id, 1 for QF."); R_ParticleFunctionInit (); } - -void -gl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, - float ramp) -{ - if (numparticles >= r_maxparticles) - return; - particle_new (type, texnum, org, scale, vel, die, color, alpha, ramp); -} - -void -gl_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, - int org_fuzz, float scale, int vel_fuzz, float die, - int color, float alpha, float ramp) -{ - if (numparticles >= r_maxparticles) - return; - particle_new_random (type, texnum, org, org_fuzz, scale, vel_fuzz, die, - color, alpha, ramp); -} diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index b1461f208..cb956188c 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -1800,6 +1800,27 @@ glsl_R_DrawParticles (void) } } +static void +glsl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, + const vec3_t vel, float die, int color, float alpha, + float ramp) +{ + if (numparticles >= r_maxparticles) + return; + particle_new (type, texnum, org, scale, vel, die, color, alpha, ramp); +} + +static void +glsl_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, + int org_fuzz, float scale, int vel_fuzz, float die, + int color, float alpha, float ramp) +{ + if (numparticles >= r_maxparticles) + return; + particle_new_random (type, texnum, org, org_fuzz, scale, vel_fuzz, die, + color, alpha, ramp); +} + static vid_particle_funcs_t particles_QF = { R_RocketTrail_QF, R_GrenadeTrail_QF, @@ -1984,24 +2005,3 @@ glsl_R_Particles_Init_Cvars (void) "0 for Id, 1 for QF."); R_ParticleFunctionInit (); } - -void -glsl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, - float ramp) -{ - if (numparticles >= r_maxparticles) - return; - particle_new (type, texnum, org, scale, vel, die, color, alpha, ramp); -} - -void -glsl_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, - int org_fuzz, float scale, int vel_fuzz, float die, - int color, float alpha, float ramp) -{ - if (numparticles >= r_maxparticles) - return; - particle_new_random (type, texnum, org, org_fuzz, scale, vel_fuzz, die, - color, alpha, ramp); -} diff --git a/libs/video/renderer/r_efrag.c b/libs/video/renderer/r_efrag.c index 870c01fc1..ae5e1fd8a 100644 --- a/libs/video/renderer/r_efrag.c +++ b/libs/video/renderer/r_efrag.c @@ -199,7 +199,7 @@ R_AddEfrags (entity_t *ent) { model_t *entmodel; - if (!ent->model) + if (!ent->model || !r_worldentity.model) return; if (ent == &r_worldentity) diff --git a/libs/video/renderer/sw/sw_rpart.c b/libs/video/renderer/sw/sw_rpart.c index 601a003c9..d7039504f 100644 --- a/libs/video/renderer/sw/sw_rpart.c +++ b/libs/video/renderer/sw/sw_rpart.c @@ -801,6 +801,52 @@ r_particles_style_f (cvar_t *var) { } +static void +R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, + const vec3_t vel, float die, int color, float alpha, float ramp) +{ + particle_t *p; + + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + VectorCopy (org, p->org); + p->color = color; + p->tex = texnum; + p->scale = scale; + p->alpha = alpha; + VectorCopy (vel, p->vel); + p->type = type; + p->phys = R_ParticlePhysics (p->type); + p->die = die; + p->ramp = ramp; +} + +static void +R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, int org_fuzz, + float scale, int vel_fuzz, float die, int color, + float alpha, float ramp) +{ + float o_fuzz = org_fuzz, v_fuzz = vel_fuzz; + int rnd; + vec3_t porg, pvel; + + rnd = mtwist_rand (&mt); + porg[0] = o_fuzz * ((rnd & 63) - 31.5) / 63.0 + org[0]; + porg[1] = o_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0 + org[1]; + porg[2] = o_fuzz * (((rnd >> 10) & 63) - 31.5) / 63.0 + org[2]; + rnd = mtwist_rand (&mt); + pvel[0] = v_fuzz * ((rnd & 63) - 31.5) / 63.0; + pvel[1] = v_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0; + pvel[2] = v_fuzz * (((rnd >> 10) & 63) - 31.5) / 63.0; + + R_Particle_New (type, texnum, porg, scale, pvel, die, color, alpha, ramp); +} + static vid_particle_funcs_t particles_QF = { R_RocketTrail_QF, R_GrenadeTrail_QF, @@ -874,49 +920,3 @@ R_Particles_Init_Cvars (void) "0 for Id, 1 for QF."); R_ParticleFunctionInit (); } - -void -R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, float ramp) -{ - particle_t *p; - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - VectorCopy (org, p->org); - p->color = color; - p->tex = texnum; - p->scale = scale; - p->alpha = alpha; - VectorCopy (vel, p->vel); - p->type = type; - p->phys = R_ParticlePhysics (p->type); - p->die = die; - p->ramp = ramp; -} - -void -R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, int org_fuzz, - float scale, int vel_fuzz, float die, int color, - float alpha, float ramp) -{ - float o_fuzz = org_fuzz, v_fuzz = vel_fuzz; - int rnd; - vec3_t porg, pvel; - - rnd = mtwist_rand (&mt); - porg[0] = o_fuzz * ((rnd & 63) - 31.5) / 63.0 + org[0]; - porg[1] = o_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0 + org[1]; - porg[2] = o_fuzz * (((rnd >> 10) & 63) - 31.5) / 63.0 + org[2]; - rnd = mtwist_rand (&mt); - pvel[0] = v_fuzz * ((rnd & 63) - 31.5) / 63.0; - pvel[1] = v_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0; - pvel[2] = v_fuzz * (((rnd >> 10) & 63) - 31.5) / 63.0; - - R_Particle_New (type, texnum, porg, scale, pvel, die, color, alpha, ramp); -} diff --git a/libs/video/renderer/sw32/sw32_rpart.c b/libs/video/renderer/sw32/sw32_rpart.c index 7b910005d..fe2e39601 100644 --- a/libs/video/renderer/sw32/sw32_rpart.c +++ b/libs/video/renderer/sw32/sw32_rpart.c @@ -814,6 +814,53 @@ sw32_r_particles_style_f (cvar_t *var) { } +static void +sw32_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, + const vec3_t vel, float die, int color, float alpha, + float ramp) +{ + particle_t *p; + + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + VectorCopy (org, p->org); + p->color = color; + p->tex = texnum; + p->scale = scale; + p->alpha = alpha; + VectorCopy (vel, p->vel); + p->type = type; + p->phys = R_ParticlePhysics (p->type); + p->die = die; + p->ramp = ramp; +} + +static void +sw32_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, + int org_fuzz, float scale, int vel_fuzz, float die, + int color, float alpha, float ramp) +{ + float o_fuzz = org_fuzz, v_fuzz = vel_fuzz; + int rnd; + vec3_t porg, pvel; + + rnd = mtwist_rand (&mt); + porg[0] = o_fuzz * ((rnd & 63) - 31.5) / 63.0 + org[0]; + porg[1] = o_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0 + org[1]; + porg[2] = o_fuzz * (((rnd >> 12) & 63) - 31.5) / 63.0 + org[2]; + rnd = mtwist_rand (&mt); + pvel[0] = v_fuzz * ((rnd & 63) - 31.5) / 63.0; + pvel[1] = v_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0; + pvel[2] = v_fuzz * (((rnd >> 12) & 63) - 31.5) / 63.0; + + sw32_R_Particle_New (type, texnum, porg, scale, pvel, die, color, alpha, ramp); +} + static vid_particle_funcs_t particles_QF = { R_RocketTrail_QF, R_GrenadeTrail_QF, @@ -887,50 +934,3 @@ sw32_R_Particles_Init_Cvars (void) "0 for Id, 1 for QF."); R_ParticleFunctionInit (); } - -void -sw32_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, - float ramp) -{ - particle_t *p; - - if (!free_particles) - return; - p = free_particles; - free_particles = p->next; - p->next = active_particles; - active_particles = p; - - VectorCopy (org, p->org); - p->color = color; - p->tex = texnum; - p->scale = scale; - p->alpha = alpha; - VectorCopy (vel, p->vel); - p->type = type; - p->phys = R_ParticlePhysics (p->type); - p->die = die; - p->ramp = ramp; -} - -void -sw32_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, - int org_fuzz, float scale, int vel_fuzz, float die, - int color, float alpha, float ramp) -{ - float o_fuzz = org_fuzz, v_fuzz = vel_fuzz; - int rnd; - vec3_t porg, pvel; - - rnd = mtwist_rand (&mt); - porg[0] = o_fuzz * ((rnd & 63) - 31.5) / 63.0 + org[0]; - porg[1] = o_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0 + org[1]; - porg[2] = o_fuzz * (((rnd >> 12) & 63) - 31.5) / 63.0 + org[2]; - rnd = mtwist_rand (&mt); - pvel[0] = v_fuzz * ((rnd & 63) - 31.5) / 63.0; - pvel[1] = v_fuzz * (((rnd >> 6) & 63) - 31.5) / 63.0; - pvel[2] = v_fuzz * (((rnd >> 12) & 63) - 31.5) / 63.0; - - sw32_R_Particle_New (type, texnum, porg, scale, pvel, die, color, alpha, ramp); -} diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 646a3b740..80ccf0127 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -40,6 +40,7 @@ #include "QF/plugin/vid_render.h" #include "QF/Vulkan/qf_draw.h" +#include "QF/Vulkan/qf_particles.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" @@ -57,6 +58,29 @@ static vulkan_ctx_t *vulkan_ctx; +static tex_t * +vulkan_SCR_CaptureBGR (void) +{ + return 0; +} + +static tex_t * +vulkan_SCR_ScreenShot (int width, int height) +{ + return 0; +} + +static void +vulkan_Fog_Update (float density, float red, float green, float blue, + float time) +{ +} + +static void +vulkan_Fog_ParseWorldspawn (struct plitem_s *worldspawn) +{ +} + static void vulkan_R_Init (void) { @@ -69,6 +93,7 @@ vulkan_R_Init (void) // are being built vulkan_ctx->pipeline = Vulkan_CreatePipeline (vulkan_ctx, "pipeline"); Vulkan_Draw_Init (vulkan_ctx); + Vulkan_Particles_Init (vulkan_ctx); Sys_Printf ("R_Init %p %d", vulkan_ctx->swapchain->swapchain, vulkan_ctx->swapchain->numImages); @@ -180,6 +205,31 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) } } +static void +vulkan_R_ClearState (void) +{ +} + +static void +vulkan_R_LoadSkys (const char *skyname) +{ +} + +static void +vulkan_R_NewMap (model_t *worldmodel, model_t **models, int num_models) +{ +} + +static void +vulkan_R_LineGraph (int x, int y, int *h_vals, int count) +{ +} + +static void +vulkan_R_RenderView (void) +{ +} + static void vulkan_Draw_Character (int x, int y, unsigned ch) { @@ -306,30 +356,127 @@ vulkan_R_ViewChanged (float aspect) Vulkan_CalcProjectionMatrices (vulkan_ctx, aspect); } +static void +vulkan_R_ClearParticles (void) +{ + Vulkan_R_ClearParticles (vulkan_ctx); +} + +static void +vulkan_R_InitParticles (void) +{ + Vulkan_R_InitParticles (vulkan_ctx); +} + +static void +vulkan_SCR_ScreenShot_f (void) +{ +} + +static void +vulkan_r_easter_eggs_f (struct cvar_s *var) +{ + Vulkan_r_easter_eggs_f (var, vulkan_ctx); +} + +static void +vulkan_r_particles_style_f (struct cvar_s *var) +{ + Vulkan_r_particles_style_f (var, vulkan_ctx); +} + +static void +vulkan_Mod_LoadExternalTextures (model_t *mod) +{ +} + +static void +vulkan_Mod_LoadLighting (bsp_t *bsp) +{ +} + +static void +vulkan_Mod_SubdivideSurface (msurface_t *fa) +{ +} + +static void +vulkan_Mod_ProcessTexture (texture_t *tx) +{ +} + +static void +vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, + void *_m, int _s, int extra) +{ +} + +static void * +vulkan_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, + qboolean group, maliasskindesc_t *skindesc) +{ + return skin + skinsize; +} + +static void +vulkan_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr) +{ +} + +static void +vulkan_Mod_LoadExternalSkins (model_t *mod) +{ +} + +static void +vulkan_Mod_IQMFinish (model_t *mod) +{ +} + +static void +vulkan_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum) +{ +} + +static void +vulkan_Skin_SetupSkin (struct skin_s *skin, int cmap) +{ +} + +static void +vulkan_Skin_ProcessTranslation (int cmap, const byte *translation) +{ +} + +static void +vulkan_Skin_InitTranslations (void) +{ +} + static vid_model_funcs_t model_funcs = { - 0,//vulkan_Mod_LoadExternalTextures, - 0,//vulkan_Mod_LoadLighting, - 0,//vulkan_Mod_SubdivideSurface, - 0,//vulkan_Mod_ProcessTexture, + vulkan_Mod_LoadExternalTextures, + vulkan_Mod_LoadLighting, + vulkan_Mod_SubdivideSurface, + vulkan_Mod_ProcessTexture, Mod_LoadIQM, Mod_LoadAliasModel, Mod_LoadSpriteModel, - 0,//vulkan_Mod_MakeAliasModelDisplayLists, - 0,//vulkan_Mod_LoadSkin, - 0,//vulkan_Mod_FinalizeAliasModel, - 0,//vulkan_Mod_LoadExternalSkins, - 0,//vulkan_Mod_IQMFinish, + vulkan_Mod_MakeAliasModelDisplayLists, + vulkan_Mod_LoadSkin, + vulkan_Mod_FinalizeAliasModel, + vulkan_Mod_LoadExternalSkins, + vulkan_Mod_IQMFinish, 0, - 0,//vulkan_Mod_SpriteLoadTexture, + vulkan_Mod_SpriteLoadTexture, Skin_SetColormap, Skin_SetSkin, - 0,//vulkan_Skin_SetupSkin, + vulkan_Skin_SetupSkin, Skin_SetTranslation, - 0,//vulkan_Skin_ProcessTranslation, - 0,//vulkan_Skin_InitTranslations, + vulkan_Skin_ProcessTranslation, + vulkan_Skin_InitTranslations, }; vid_render_funcs_t vulkan_vid_render_funcs = { @@ -357,33 +504,33 @@ vid_render_funcs_t vulkan_vid_render_funcs = { SCR_DrawRam, SCR_DrawTurtle, SCR_DrawPause, - 0,//vulkan_SCR_CaptureBGR, - 0,//vulkan_SCR_ScreenShot, + vulkan_SCR_CaptureBGR, + vulkan_SCR_ScreenShot, SCR_DrawStringToSnap, - 0,//vulkan_Fog_Update, - 0,//vulkan_Fog_ParseWorldspawn, + vulkan_Fog_Update, + vulkan_Fog_ParseWorldspawn, vulkan_R_Init, vulkan_R_RenderFrame, - 0,//vulkan_R_ClearState, - 0,//vulkan_R_LoadSkys, - 0,//vulkan_R_NewMap, + vulkan_R_ClearState, + vulkan_R_LoadSkys, + vulkan_R_NewMap, R_AddEfrags, R_RemoveEfrags, R_EnqueueEntity, - 0,//vulkan_R_LineGraph, + vulkan_R_LineGraph, R_AllocDlight, R_AllocEntity, R_MaxDlightsCheck, - 0,//vulkan_R_RenderView, + vulkan_R_RenderView, R_DecayLights, vulkan_R_ViewChanged, - 0,//vulkan_R_ClearParticles, - 0,//vulkan_R_InitParticles, - 0,//vulkan_SCR_ScreenShot_f, - 0,//vulkan_r_easter_eggs_f, - 0,//vulkan_r_particles_style_f, + vulkan_R_ClearParticles, + vulkan_R_InitParticles, + vulkan_SCR_ScreenShot_f, + vulkan_r_easter_eggs_f, + vulkan_r_particles_style_f, 0, &model_funcs }; diff --git a/libs/video/renderer/vulkan/vulkan_particles.c b/libs/video/renderer/vulkan/vulkan_particles.c new file mode 100644 index 000000000..282bfaf8a --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_particles.c @@ -0,0 +1,268 @@ +/* + vulkan_particles.c + + Quake specific Vulkan particle manager + + Copyright (C) 2021 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/render.h" +#include "QF/plugin/vid_render.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/qf_particles.h" + +#include "r_internal.h" +#include "vid_vulkan.h" + +void +Vulkan_R_ClearParticles (struct vulkan_ctx_s *ctx) +{ +} + +void +Vulkan_R_InitParticles (struct vulkan_ctx_s *ctx) +{ +} + +static void +R_RocketTrail_QF (const entity_t *ent) +{ +} + +static void +R_GrenadeTrail_QF (const entity_t *ent) +{ +} + +static void +R_BloodTrail_QF (const entity_t *ent) +{ +} + +static void +R_SlightBloodTrail_QF (const entity_t *ent) +{ +} + +static void +R_WizTrail_QF (const entity_t *ent) +{ +} + +static void +R_FlameTrail_QF (const entity_t *ent) +{ +} + +static void +R_VoorTrail_QF (const entity_t *ent) +{ +} + +static void +R_GlowTrail_QF (const entity_t *ent, int glow_color) +{ +} + +static void +R_RunParticleEffect_QF (const vec3_t org, const vec3_t dir, int color, + int count) +{ +} + +static void +R_BloodPuffEffect_QF (const vec3_t org, int count) +{ +} + +static void +R_GunshotEffect_QF (const vec3_t org, int count) +{ +} + +static void +R_LightningBloodEffect_QF (const vec3_t org) +{ +} + +static void +R_SpikeEffect_QF (const vec3_t org) +{ +} + +static void +R_KnightSpikeEffect_QF (const vec3_t org) +{ +} + +static void +R_SuperSpikeEffect_QF (const vec3_t org) +{ +} + +static void +R_WizSpikeEffect_QF (const vec3_t org) +{ +} + +static void +R_BlobExplosion_QF (const vec3_t org) +{ +} + +static void +R_ParticleExplosion_QF (const vec3_t org) +{ +} + +static void +R_ParticleExplosion2_QF (const vec3_t org, int colorStart, int colorLength) +{ +} + +static void +R_LavaSplash_QF (const vec3_t org) +{ +} + +static void +R_TeleportSplash_QF (const vec3_t org) +{ +} + +static void +R_DarkFieldParticles_ID (const entity_t *ent) +{ +} + +static void +R_EntityParticles_ID (const entity_t *ent) +{ +} + +static void +R_Particle_New (ptype_t type, int texnum, const vec3_t org, + float scale, const vec3_t vel, float die, + int color, float alpha, float ramp) +{ +} + +static void +R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, + int org_fuzz, float scale, int vel_fuzz, + float die, int color, float alpha, + float ramp) +{ +} + +static vid_particle_funcs_t vulkan_particles_QF = { + R_RocketTrail_QF, + R_GrenadeTrail_QF, + R_BloodTrail_QF, + R_SlightBloodTrail_QF, + R_WizTrail_QF, + R_FlameTrail_QF, + R_VoorTrail_QF, + R_GlowTrail_QF, + R_RunParticleEffect_QF, + R_BloodPuffEffect_QF, + R_GunshotEffect_QF, + R_LightningBloodEffect_QF, + R_SpikeEffect_QF, + R_KnightSpikeEffect_QF, + R_SuperSpikeEffect_QF, + R_WizSpikeEffect_QF, + R_BlobExplosion_QF, + R_ParticleExplosion_QF, + R_ParticleExplosion2_QF, + R_LavaSplash_QF, + R_TeleportSplash_QF, + R_DarkFieldParticles_ID, + R_EntityParticles_ID, + R_Particle_New, + R_Particle_NewRandom, +}; + +void +Vulkan_r_easter_eggs_f (cvar_t *var, struct vulkan_ctx_s *ctx) +{ + if (!easter_eggs || !r_particles_style) { + return; + } + if (easter_eggs->int_val) { + if (r_particles_style->int_val) { + //vulkan_vid_render_funcs.particles = &vulkan_particles_QF_egg; + } else { + //vulkan_vid_render_funcs.particles = &vulkan_particles_ID_egg; + } + } else { + if (r_particles_style->int_val) { + //vulkan_vid_render_funcs.particles = &vulkan_particles_QF; + } else { + //vulkan_vid_render_funcs.particles = &vulkan_particles_ID; + } + } + vulkan_vid_render_funcs.particles = &vulkan_particles_QF; +} + +void +Vulkan_r_particles_style_f (cvar_t *var, struct vulkan_ctx_s *ctx) +{ + Vulkan_r_particles_style_f (var, ctx); +} + +void +Vulkan_Particles_Init (struct vulkan_ctx_s *ctx) +{ + /* + easter_eggs = Cvar_Get ("easter_eggs", "0", CVAR_NONE, r_easter_eggs_f, + "Enables easter eggs."); + r_particles = Cvar_Get ("r_particles", "1", CVAR_ARCHIVE, r_particles_f, + "Toggles drawing of particles."); + r_particles_max = Cvar_Get ("r_particles_max", "2048", CVAR_ARCHIVE, + r_particles_max_f, "Maximum amount of " + "particles to display. No maximum, minimum " + "is 0."); + r_particles_nearclip = Cvar_Get ("r_particles_nearclip", "32", + CVAR_ARCHIVE, r_particles_nearclip_f, + "Distance of the particle near clipping " + "plane from the player."); + r_particles_style = Cvar_Get ("r_particles_style", "1", CVAR_ARCHIVE, + r_particles_style_f, "Sets particle style. " + "0 for Id, 1 for QF."); + */ + vulkan_vid_render_funcs.particles = &vulkan_particles_QF; +} From c7b2843c0e6fc6ed88345268def633ee491dd0a6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 18 Jan 2021 17:13:52 +0900 Subject: [PATCH 246/435] [vulkan] Create shanders for brush models The fragment shader is a bit of a mini mega-shader, but I do want to try out specializations. --- include/vid_vulkan.h | 1 + libs/video/renderer/Makemodule.am | 10 ++ libs/video/renderer/vulkan/quakebsp.frag | 122 +++++++++++++++++++ libs/video/renderer/vulkan/quakebsp.vert | 28 +++++ libs/video/renderer/vulkan/shader.c | 6 + libs/video/renderer/vulkan/vulkan_matrices.c | 3 +- 6 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 libs/video/renderer/vulkan/quakebsp.frag create mode 100644 libs/video/renderer/vulkan/quakebsp.vert diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index c8d318a99..90d4908f2 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -31,6 +31,7 @@ typedef struct vulkan_matrices_s { float *projection_2d; float *projection_3d; float *view_3d; + float *sky_3d; } vulkan_matrices_t; typedef struct vulkan_framebufferset_s diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index b58aaf3af..bfe8cb5e3 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -261,6 +261,10 @@ twodv_src = libs/video/renderer/vulkan/twod.vert twodv_c = libs/video/renderer/vulkan/twod.vert.spvc twodf_src = libs/video/renderer/vulkan/twod.frag twodf_c = libs/video/renderer/vulkan/twod.frag.spvc +quakebspv_src = libs/video/renderer/vulkan/quakebsp.vert +quakebspv_c = libs/video/renderer/vulkan/quakebsp.vert.spvc +quakebspf_src = libs/video/renderer/vulkan/quakebsp.frag +quakebspf_c = libs/video/renderer/vulkan/quakebsp.frag.spvc passthrough_src = libs/video/renderer/vulkan/passthrough.vert passthrough_c = libs/video/renderer/vulkan/passthrough.vert.spvc pushcolor_src = libs/video/renderer/vulkan/pushcolor.frag @@ -270,6 +274,10 @@ $(twodv_c): $(twodv_src) $(twodf_c): $(twodf_src) +$(quakebspv_c): $(quakebspv_src) + +$(quakebspf_c): $(quakebspf_src) + $(passthrough_c): $(passthrough_src) $(pushcolor_c): $(pushcolor_src) @@ -277,6 +285,8 @@ $(pushcolor_c): $(pushcolor_src) vkshader_c = \ $(twodv_c) \ $(twodf_c) \ + $(quakebspv_c) \ + $(quakebspf_c) \ $(passthrough_c) \ $(pushcolor_c) diff --git a/libs/video/renderer/vulkan/quakebsp.frag b/libs/video/renderer/vulkan/quakebsp.frag new file mode 100644 index 000000000..151243249 --- /dev/null +++ b/libs/video/renderer/vulkan/quakebsp.frag @@ -0,0 +1,122 @@ +#version 450 + +layout (set = 0, binding = 1) uniform sampler2D Texture; +layout (set = 0, binding = 2) uniform sampler2D Glowmap; +layout (set = 0, binding = 3) uniform sampler2D Lightmap; +layout (set = 0, binding = 4) uniform samplerCube SkyCube; +layout (set = 0, binding = 5) uniform sampler2DArray SkySheet; + +layout (push_constant) uniform PushConstants { + float time; + vec4 fog; +}; + +layout (location = 0) in vec4 tl_st; +layout (location = 1) in vec4 color; +layout (location = 2) out vec3 direction; + +layout (location = 0) out vec4 frag_color; + +layout (constant_id = 0) const bool doWarp = false; +layout (constant_id = 1) const bool doLight = true; +layout (constant_id = 2) const bool doSkyCube = false; +layout (constant_id = 3) const bool doSkySheet = false; + +const float PI = 3.14159265; +const float SPEED = 20.0; +const float CYCLE = 128.0; +const float FACTOR = PI * 2.0 / CYCLE; +const vec2 BIAS = vec2 (1.0, 1.0); +const float SCALE = 8.0; + +vec2 +warp_st (vec2 st, float time) +{ + vec2 angle = st.ts * CYCLE / 2.0; + vec2 phase = vec2 (time, time) * SPEED; + return st + (sin ((angle + phase) * FACTOR) + BIAS) / SCALE; +} + +vec4 +fogBlend (vec4 color) +{ + float az = fog.a * gl_FragCoord.z / gl_FragCoord.w; + vec3 fog_color = fog.rgb; + float fog_factor = exp (-az * az); + + return vec4 (mix (fog_color.rgb, color.rgb, fog_factor), color.a); +} + +vec4 +sky_sheet (vec3 dir, float time) +{ + float len; + vec2 flow = vec2 (1.0, 1.0); + vec2 base; + vec3 st1, st2; + vec4 c1, c2, c; + + dir.z *= 3.0; + len = dot (dir, dir); + len = SCALE * inversesqrt (len); + base = dir.yx * vec2(1.0, -1.0) * len; + + st1 = vec3 (base + flow * time / 8.0, 0); + st2 = vec3 (base + flow * time / 16.0, 1); + + c1 = texture (SkySheet, st1); + c2 = texture (SkySheet, st2); + + c = vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + + return c; +} + +vec4 +sky_cube (vec3 dir, float time) +{ + // NOTE: quake's world is right-handed with Z up and X forward, but + // Vulkan's cube maps are left-handed with Y up and Z forward. The + // rotation to X foward is done by the Sky matrix so all that's left + // to do here is swizzle the Y and Z coordinates + return texture (SkyCube, dir.xzy); +} + +vec4 +sky_color (vec3 dir, float time) +{ + if (!doSkySheet) { + return sky_cube (dir, time); + } if (!doSkyCube) { + return sky_sheet (dir, time); + } else { + // can see through the sheet (may look funny when looking down) + // maybe have 4 sheet layers instead of 2? + vec4 c1 = sky_sheet (dir, time); + vec4 c2 = sky_cube (dir, time); + return vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + } +} + +void +main (void) +{ + vec4 c; + vec2 t_st = tl_st.xy; + vec2 l_st = tl_st.zw; + + if (doWarp) { + t_st = warp_st (t_st, time); + } + if (doSkyCube || doSkySheet) { + c = sky_color (direction, time); + } else { + c = texture (Texture, t_st) * color; + } + if (doLight) { + c *= texture (Lightmap, l_st); + } + c += texture (Glowmap, t_st); + + frag_color = fogBlend (c); +} diff --git a/libs/video/renderer/vulkan/quakebsp.vert b/libs/video/renderer/vulkan/quakebsp.vert new file mode 100644 index 000000000..11ae0c90a --- /dev/null +++ b/libs/video/renderer/vulkan/quakebsp.vert @@ -0,0 +1,28 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + +layout (push_constant) uniform PushConstants { + mat4 Model; +}; + +layout (location = 0) in vec4 vertex; +layout (location = 1) in vec4 tl_uv; +layout (location = 2) in vec4 vcolor; + +layout (location = 0) out vec4 tl_st; +layout (location = 1) out vec4 color; +layout (location = 2) out vec3 direction; + +void +main (void) +{ + gl_Position = Projection * (View * (Model * vertex)); + direction = (Sky * vertex).xyz; + tl_st = tl_uv; + color = vcolor; +} diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index 25e1049ea..4b0fed532 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -59,6 +59,10 @@ static static #include "libs/video/renderer/vulkan/twod.frag.spvc" static +#include "libs/video/renderer/vulkan/quakebsp.vert.spvc" +static +#include "libs/video/renderer/vulkan/quakebsp.frag.spvc" +static #include "libs/video/renderer/vulkan/passthrough.vert.spvc" static #include "libs/video/renderer/vulkan/pushcolor.frag.spvc" @@ -72,6 +76,8 @@ typedef struct shaderdata_s { static shaderdata_t builtin_shaders[] = { { "twod.vert", twod_vert, sizeof (twod_vert) }, { "twod.frag", twod_frag, sizeof (twod_frag) }, + { "quakebsp.vert", quakebsp_vert, sizeof (quakebsp_vert) }, + { "quakebsp.frag", quakebsp_frag, sizeof (quakebsp_frag) }, { "passthrough.vert", passthrough_vert, sizeof (passthrough_vert) }, { "pushcolor.frag", pushcolor_frag, sizeof (pushcolor_frag) }, {} diff --git a/libs/video/renderer/vulkan/vulkan_matrices.c b/libs/video/renderer/vulkan/vulkan_matrices.c index c734f82d0..62eb16c1d 100644 --- a/libs/video/renderer/vulkan/vulkan_matrices.c +++ b/libs/video/renderer/vulkan/vulkan_matrices.c @@ -134,7 +134,7 @@ Vulkan_CreateMatrices (vulkan_ctx_t *ctx) __auto_type mat = &ctx->matrices; mat->buffer_2d = QFV_CreateBuffer (device, 1 * MAT_SIZE, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); - mat->buffer_3d = QFV_CreateBuffer (device, 2 * MAT_SIZE, + mat->buffer_3d = QFV_CreateBuffer (device, 3 * MAT_SIZE, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); size_t size = 0; @@ -159,6 +159,7 @@ Vulkan_CreateMatrices (vulkan_ctx_t *ctx) mat->projection_2d = data; mat->projection_3d = mat->projection_2d + offset / sizeof (float); mat->view_3d = mat->projection_3d + 16; + mat->sky_3d = mat->view_3d + 16; } void From 9b53d7d4e288e2a4763c808754ba405c0222b477 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 19 Jan 2021 08:26:53 +0900 Subject: [PATCH 247/435] [model] Remove empty brush model functions It seems better to check for a null pointer and just not call. --- libs/models/brush/glsl_model_brush.c | 10 ---------- libs/models/brush/model_brush.c | 11 +++++++---- libs/models/brush/sw_model_brush.c | 16 ---------------- libs/models/null_model.c | 15 --------------- libs/video/renderer/vid_render_glsl.c | 4 ++-- libs/video/renderer/vid_render_sw.c | 6 +++--- libs/video/renderer/vid_render_sw32.c | 6 +++--- 7 files changed, 15 insertions(+), 53 deletions(-) diff --git a/libs/models/brush/glsl_model_brush.c b/libs/models/brush/glsl_model_brush.c index 8827844da..e840e0b29 100644 --- a/libs/models/brush/glsl_model_brush.c +++ b/libs/models/brush/glsl_model_brush.c @@ -132,11 +132,6 @@ glsl_Mod_ProcessTexture (texture_t *tx) } } -void -glsl_Mod_LoadExternalTextures (model_t *mod) -{ -} - void glsl_Mod_LoadLighting (bsp_t *bsp) { @@ -150,8 +145,3 @@ glsl_Mod_LoadLighting (bsp_t *bsp) loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize, loadname); memcpy (loadmodel->lightdata, bsp->lightdata, bsp->lightdatasize); } - -void -glsl_Mod_SubdivideSurface (msurface_t *fa) -{ -} diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index c81fbabe9..19d28a8c6 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -204,7 +204,7 @@ Mod_LoadTextures (bsp_t *bsp) if (!strncmp (mt->name, "sky", 3)) loadmodel->skytexture = tx; - if (mod_funcs) + if (mod_funcs && mod_funcs->Mod_ProcessTexture) mod_funcs->Mod_ProcessTexture (tx); } @@ -539,7 +539,7 @@ Mod_LoadFaces (bsp_t *bsp) if (!strncmp (out->texinfo->texture->name, "sky", 3)) { // sky out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); if (gl_sky_divide && gl_sky_divide->int_val) - if (mod_funcs) + if (mod_funcs && mod_funcs->Mod_SubdivideSurface) mod_funcs->Mod_SubdivideSurface (out); continue; } @@ -552,8 +552,10 @@ Mod_LoadFaces (bsp_t *bsp) out->extents[i] = 16384; out->texturemins[i] = -8192; } - if (mod_funcs) // cut up polygon for warps + if (mod_funcs && mod_funcs->Mod_SubdivideSurface) { + // cut up polygon for warps mod_funcs->Mod_SubdivideSurface (out); + } continue; } } @@ -915,8 +917,9 @@ Mod_LoadBrushModel (model_t *mod, void *buffer) Mod_LoadEdges (bsp); Mod_LoadSurfedges (bsp); Mod_LoadTextures (bsp); - if (mod_funcs) + if (mod_funcs && mod_funcs->Mod_LoadLighting) { mod_funcs->Mod_LoadLighting (bsp); + } Mod_LoadPlanes (bsp); Mod_LoadTexinfo (bsp); Mod_LoadFaces (bsp); diff --git a/libs/models/brush/sw_model_brush.c b/libs/models/brush/sw_model_brush.c index c78cd12b4..1f179bab2 100644 --- a/libs/models/brush/sw_model_brush.c +++ b/libs/models/brush/sw_model_brush.c @@ -40,22 +40,6 @@ #include "mod_internal.h" - -void -sw_Mod_SubdivideSurface (msurface_t *fa) -{ -} - -void -sw_Mod_ProcessTexture (texture_t *tx) -{ -} - -void -sw_Mod_LoadExternalTextures (model_t *mod) -{ -} - void sw_Mod_LoadLighting (bsp_t *bsp) { diff --git a/libs/models/null_model.c b/libs/models/null_model.c index 18cb987c1..6f482cc01 100644 --- a/libs/models/null_model.c +++ b/libs/models/null_model.c @@ -48,26 +48,11 @@ Mod_LoadSpriteModel (model_t *mod, void *buf) { } -void -Mod_ProcessTexture (texture_t *tx) -{ -} - void Mod_LoadExternalSkins (model_t *mod) { } -void -Mod_LoadExternalTextures (model_t *mod) -{ -} - -void -Mod_SubdivideSurface (msurface_t *fa) -{ -} - viddef_t vid; VISIBLE void diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 25bdb9224..6d6c87b3a 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -46,9 +46,9 @@ gl_ctx_t *glsl_ctx; static vid_model_funcs_t model_funcs = { - glsl_Mod_LoadExternalTextures, + 0,//Mod_LoadExternalTextures, glsl_Mod_LoadLighting, - glsl_Mod_SubdivideSurface, + 0,//Mod_SubdivideSurface, glsl_Mod_ProcessTexture, Mod_LoadIQM, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 02ff562e6..8c5360701 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -39,10 +39,10 @@ sw_ctx_t *sw_ctx; static vid_model_funcs_t model_funcs = { - sw_Mod_LoadExternalTextures, + 0,//Mod_LoadExternalTextures, sw_Mod_LoadLighting, - sw_Mod_SubdivideSurface, - sw_Mod_ProcessTexture, + 0,//Mod_SubdivideSurface, + 0,//Mod_ProcessTexture, Mod_LoadIQM, Mod_LoadAliasModel, diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index 97097e2ad..af72bc0df 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -44,10 +44,10 @@ sw_ctx_t *sw32_ctx; static vid_model_funcs_t model_funcs = { - sw_Mod_LoadExternalTextures, + 0,//Mod_LoadExternalTextures, sw_Mod_LoadLighting, - sw_Mod_SubdivideSurface, - sw_Mod_ProcessTexture, + 0,//Mod_SubdivideSurface, + 0,//Mod_ProcessTexture, Mod_LoadIQM, Mod_LoadAliasModel, From e50430e00cf44c41a60b9241ee5858abc86e5550 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 19 Jan 2021 10:15:57 +0900 Subject: [PATCH 248/435] [image] Add parameter to load only the header I want to be able to calculate texture sizes without actually loading the images. --- include/QF/image.h | 8 ++-- include/QF/pcx.h | 3 +- include/QF/png.h | 2 +- include/QF/tga.h | 2 +- libs/image/image.c | 11 ++--- libs/image/pcx.c | 18 +++++++-- libs/image/png.c | 60 ++++++++++++++++------------ libs/image/tga.c | 31 +++++++++----- libs/models/alias/gl_model_alias.c | 12 +++--- libs/models/brush/gl_model_brush.c | 13 +++--- libs/models/brush/glsl_model_brush.c | 2 +- libs/models/iqm/gl_model_iqm.c | 2 +- libs/models/iqm/glsl_model_iqm.c | 4 +- libs/models/iqm/sw_model_iqm.c | 4 +- libs/models/skin.c | 2 +- libs/models/sprite/gl_model_sprite.c | 2 +- libs/video/renderer/gl/gl_draw.c | 6 +-- libs/video/renderer/gl/gl_sky.c | 4 +- libs/video/renderer/glsl/glsl_bsp.c | 6 +-- tools/qflmp/lmp.c | 2 +- tools/qfspritegen/spritegen.c | 2 +- tools/wad/script.c | 2 +- 22 files changed, 116 insertions(+), 82 deletions(-) diff --git a/include/QF/image.h b/include/QF/image.h index 396547f42..cd649c42e 100644 --- a/include/QF/image.h +++ b/include/QF/image.h @@ -45,11 +45,11 @@ typedef struct tex_s { int width; int height; QFFormat format; - byte *palette; // 0 = 32 bit, otherwise 8 - byte data[4]; // variable length + int loaded; // 0 if size info only, otherwise data loaded + byte *palette; // 0 = 32 bit, otherwise 8 + byte data[4]; // variable length } tex_t; - -tex_t *LoadImage (const char *imageFile); +tex_t *LoadImage (const char *imageFile, int load); #endif//__QF_image_h diff --git a/include/QF/pcx.h b/include/QF/pcx.h index 8536b9f69..8ae83a156 100644 --- a/include/QF/pcx.h +++ b/include/QF/pcx.h @@ -71,10 +71,11 @@ pcx_t *EncodePCX (byte *data, int width, int height, int rowbytes, \param f The file to read the texture from \param convert If true, the texture is converted to RGB on load \param pal The palette to apply during conversion + \param load If false, only the format and size info is loaded \return A pointer to the texture. \warning Uses Hunk_TempAlloc() to allocate the texture. */ -struct tex_s *LoadPCX (QFile *f, qboolean convert, byte *pal); +struct tex_s *LoadPCX (QFile *f, qboolean convert, byte *pal, int load); #endif//__QF_pcx_h diff --git a/include/QF/png.h b/include/QF/png.h index c3e2ed562..b322a93f0 100644 --- a/include/QF/png.h +++ b/include/QF/png.h @@ -33,7 +33,7 @@ #include "QF/quakefs.h" -struct tex_s *LoadPNG (QFile *infile); +struct tex_s *LoadPNG (QFile *infile, int load); void WritePNG (const char *fileName, const byte *data, int width, int height); void WritePNGqfs (const char *fileName, const byte *data, int width, int height); diff --git a/include/QF/tga.h b/include/QF/tga.h index 365f5d366..08d610d95 100644 --- a/include/QF/tga.h +++ b/include/QF/tga.h @@ -67,7 +67,7 @@ typedef struct _TargaHeader { # endif #endif -struct tex_s *LoadTGA (QFile *fin); +struct tex_s *LoadTGA (QFile *fin, int load); void WriteTGAfile (const char *tganame, byte *data, int width, int height); #endif//__QF_tga_h diff --git a/libs/image/image.c b/libs/image/image.c index 7df5d9bb2..4da1e5827 100644 --- a/libs/image/image.c +++ b/libs/image/image.c @@ -43,7 +43,7 @@ #include "QF/tga.h" VISIBLE tex_t * -LoadImage (const char *imageFile) +LoadImage (const char *imageFile, int load) { int tmp; dstring_t *tmpFile; @@ -64,7 +64,7 @@ LoadImage (const char *imageFile) dstring_replace (tmpFile, tmp, tmpFile->size, ".png", 5); fp = QFS_FOpenFile (tmpFile->str); if (fp) { - tex = LoadPNG (fp); + tex = LoadPNG (fp, load); Qclose (fp); dstring_delete (tmpFile); return (tex); @@ -74,7 +74,7 @@ LoadImage (const char *imageFile) dstring_replace (tmpFile, tmp, tmpFile->size, ".tga", 5); fp = QFS_FOpenFile (tmpFile->str); if (fp) { - tex = LoadTGA (fp); + tex = LoadTGA (fp, load); Qclose (fp); dstring_delete (tmpFile); return (tex); @@ -85,7 +85,7 @@ LoadImage (const char *imageFile) dstring_replace (tmpFile, tmp, tmpFile->size, ".jpg", 5); fp = QFS_FOpenFile (tmpFile->str); if (fp) { - tex = LoadJPG (fp); + tex = LoadJPG (fp, load); Qclose (fp); dstring_delete (tmpFile); return (tex); @@ -96,7 +96,8 @@ LoadImage (const char *imageFile) dstring_replace (tmpFile, tmp, tmpFile->size, ".pcx", 5); fp = QFS_FOpenFile (tmpFile->str); if (fp) { - tex = LoadPCX (fp, 1, NULL); // Convert, some users don't grok paletted + // Convert, some users don't grok paletted + tex = LoadPCX (fp, 1, NULL, load); Qclose (fp); dstring_delete (tmpFile); return (tex); diff --git a/libs/image/pcx.c b/libs/image/pcx.c index 9ca47bc34..495b1b1d5 100644 --- a/libs/image/pcx.c +++ b/libs/image/pcx.c @@ -47,7 +47,7 @@ VISIBLE tex_t * -LoadPCX (QFile *f, qboolean convert, byte *pal) +LoadPCX (QFile *f, qboolean convert, byte *pal, int load) { pcx_t *pcx; int pcx_mark; @@ -58,8 +58,11 @@ LoadPCX (QFile *f, qboolean convert, byte *pal) int runLength = 1; int count; tex_t *tex; - int fsize = Qfilesize(f); + int fsize = sizeof (pcx_t); + if (load) { + fsize = Qfilesize(f); + } // parse the PCX file pcx_mark = Hunk_LowMark (); pcx = Hunk_AllocName (fsize, "PCX"); @@ -79,14 +82,16 @@ LoadPCX (QFile *f, qboolean convert, byte *pal) || pcx->encoding != 1 || pcx->bits_per_pixel != 8) { Sys_Printf ("Bad pcx file: %x %d %d %d\n", - pcx->manufacturer, pcx->version, pcx->encoding, pcx->bits_per_pixel); + pcx->manufacturer, pcx->version, pcx->encoding, + pcx->bits_per_pixel); + Hunk_FreeToLowMark (pcx_mark); return 0; } end = palette = ((byte *) pcx) + fsize - 768; dataByte = (byte *) &pcx[1]; - count = (pcx->xmax + 1) * (pcx->ymax + 1); + count = load ? (pcx->xmax + 1) * (pcx->ymax + 1) : 0; if (convert) { tex = Hunk_TempAlloc (field_offset (tex_t, data[count * 3])); tex->format = tex_rgb; @@ -101,6 +106,11 @@ LoadPCX (QFile *f, qboolean convert, byte *pal) } tex->width = pcx->xmax + 1; tex->height = pcx->ymax + 1; + tex->loaded = load; + if (!load) { + Hunk_FreeToLowMark (pcx_mark); + return tex; + } pix = tex->data; while (count) { diff --git a/libs/image/png.c b/libs/image/png.c index 62d9977df..9e81ca138 100644 --- a/libs/image/png.c +++ b/libs/image/png.c @@ -115,7 +115,7 @@ readpng_init (QFile *infile, png_structp *png_ptr, png_infop *info_ptr) /* Load the png file and return a texture */ VISIBLE tex_t * -LoadPNG (QFile *infile) +LoadPNG (QFile *infile, int load) { double gamma; png_structp png_ptr = NULL; @@ -131,37 +131,41 @@ LoadPNG (QFile *infile) png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand (png_ptr); + if (load) { + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand (png_ptr); - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand (png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand (png_ptr); - if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_expand (png_ptr); + if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand (png_ptr); - if (bit_depth == 16) - png_set_strip_16 (png_ptr); + if (bit_depth == 16) + png_set_strip_16 (png_ptr); - if (color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb (png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb (png_ptr); - /* NOTE: gamma support? */ - /* unlike the example in the libpng documentation, we have *no* idea where - * this file may have come from--so if it doesn't have a file gamma, don't - * do any correction ("do no harm") - */ - if (png_get_gAMA(png_ptr, info_ptr, &gamma)) - png_set_gamma (png_ptr, 1.0, gamma); + /* NOTE: gamma support? */ + /* unlike the example in the libpng documentation, we have *no* idea + * wherethis file may have come from--so if it doesn't have a file + * gamma, don't do any correction ("do no harm") + */ + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma (png_ptr, 1.0, gamma); - /* All transformations have been registered, now update the info_ptr - * structure */ - png_read_update_info (png_ptr, info_ptr); + /* All transformations have been registered, now update the info_ptr + * structure */ + png_read_update_info (png_ptr, info_ptr); - /* Allocate tex_t structure */ - rowbytes = png_get_rowbytes(png_ptr, info_ptr); - tex = Hunk_TempAlloc (field_offset (tex_t, data[height * rowbytes])); + /* Allocate tex_t structure */ + rowbytes = png_get_rowbytes(png_ptr, info_ptr); + tex = Hunk_TempAlloc (field_offset (tex_t, data[height * rowbytes])); + } else { + tex = Hunk_TempAlloc (field_offset (tex_t, data[0])); + } tex->width = width; tex->height = height; @@ -170,6 +174,12 @@ LoadPNG (QFile *infile) else tex->format = tex_rgb; tex->palette = NULL; + tex->loaded = load; + + if (!load) { + png_read_end (png_ptr, NULL); + return tex; + } if ((row_pointers = (png_bytepp) malloc (height * sizeof (png_bytep))) == NULL) { diff --git a/libs/image/tga.c b/libs/image/tga.c index 323a05d04..1a4dad133 100644 --- a/libs/image/tga.c +++ b/libs/image/tga.c @@ -620,15 +620,18 @@ static decoder_t decoder_functions[] = { / sizeof (decoder_functions[0])) struct tex_s * -LoadTGA (QFile *fin) +LoadTGA (QFile *fin, int load) { byte *dataByte; decoder_t decode; - int fsize = Qfilesize (fin); + int fsize = sizeof (TargaHeader); int numPixels, targa_mark; TargaHeader *targa; tex_t *tex; + if (load) { + fsize = Qfilesize (fin); + } targa_mark = Hunk_LowMark (); targa = Hunk_AllocName (fsize, "TGA"); Qread (fin, targa, fsize); @@ -641,20 +644,30 @@ LoadTGA (QFile *fin) targa->height = LittleShort (targa->height); if (targa->image_type >= NUM_DECODERS - || !(decode = decoder_functions[targa->image_type])) - Sys_Error ("LoadTGA: Unsupported targa type"); + || !(decode = decoder_functions[targa->image_type])) { + Sys_Printf ("LoadTGA: Unsupported targa type"); + Hunk_FreeToLowMark (targa_mark); + return 0; + } - numPixels = targa->width * targa->height; + if (load) { + numPixels = targa->width * targa->height; + } else { + numPixels = 0; + } tex = Hunk_TempAlloc (field_offset (tex_t, data[numPixels * 4])); tex->width = targa->width; tex->height = targa->height; tex->palette = 0; + tex->loaded = load; - // skip TARGA image comment - dataByte = (byte *) (targa + 1); - dataByte += targa->id_length; + if (load) { + // skip TARGA image comment + dataByte = (byte *) (targa + 1); + dataByte += targa->id_length; - decode (targa, tex, dataByte); + decode (targa, tex, dataByte); + } Hunk_FreeToLowMark (targa_mark); return tex; diff --git a/libs/models/alias/gl_model_alias.c b/libs/models/alias/gl_model_alias.c index 5d09f93b7..82919aad4 100644 --- a/libs/models/alias/gl_model_alias.c +++ b/libs/models/alias/gl_model_alias.c @@ -120,9 +120,9 @@ Mod_LoadExternalSkin (maliasskindesc_t *pskindesc, char *filename) if (!ptr) ptr = filename; - tex = LoadImage (filename); + tex = LoadImage (filename, 1); if (!tex) - tex = LoadImage (va ("textures/%s", ptr + 1)); + tex = LoadImage (va ("textures/%s", ptr + 1), 1); if (tex) { pskindesc->texnum = GL_LoadTexture (filename, tex->width, tex->height, tex->data, true, false, @@ -130,13 +130,13 @@ Mod_LoadExternalSkin (maliasskindesc_t *pskindesc, char *filename) pskindesc->fb_texnum = 0; - glow = LoadImage (va ("%s_luma", filename)); + glow = LoadImage (va ("%s_luma", filename), 1); if (!glow) - glow = LoadImage (va ("%s_glow", filename)); + glow = LoadImage (va ("%s_glow", filename), 1); if (!glow) - glow = LoadImage (va ("textures/%s_luma", ptr + 1)); + glow = LoadImage (va ("textures/%s_luma", ptr + 1), 1); if (!glow) - glow = LoadImage (va ("textures/%s_glow", ptr + 1)); + glow = LoadImage (va ("textures/%s_glow", ptr + 1), 1); if (glow) pskindesc->fb_texnum = GL_LoadTexture (va ("fb_%s", filename), glow->width, diff --git a/libs/models/brush/gl_model_brush.c b/libs/models/brush/gl_model_brush.c index 7b7e171ac..9c1057226 100644 --- a/libs/models/brush/gl_model_brush.c +++ b/libs/models/brush/gl_model_brush.c @@ -68,7 +68,7 @@ gl_Mod_ProcessTexture (texture_t *tx) } static tex_t * -Mod_LoadAnExternalTexture (char * tname, char *mname) +Mod_LoadAnExternalTexture (char *tname, char *mname) { char rname[32]; tex_t *image; @@ -78,17 +78,16 @@ Mod_LoadAnExternalTexture (char * tname, char *mname) if (rname[0] == '*') rname[0] = '#'; image = LoadImage (va ("textures/%.*s/%s", (int) strlen (mname + 5) - 4, - mname + 5, rname)); + mname + 5, rname), 1); if (!image) - image = LoadImage (va ("maps/%.*s/%s", - (int) strlen (mname + 5) - 4, - mname + 5, rname)); + image = LoadImage (va ("maps/%.*s/%s", (int) strlen (mname + 5) - 4, + mname + 5, rname), 1); // if (!image) // image = LoadImage (va ("textures/bmodels/%s", rname)); if (!image) - image = LoadImage (va ("textures/%s", rname)); + image = LoadImage (va ("textures/%s", rname), 1); if (!image) - image = LoadImage (va ("maps/%s", rname)); + image = LoadImage (va ("maps/%s", rname), 1); return image; } diff --git a/libs/models/brush/glsl_model_brush.c b/libs/models/brush/glsl_model_brush.c index e840e0b29..67fff7b44 100644 --- a/libs/models/brush/glsl_model_brush.c +++ b/libs/models/brush/glsl_model_brush.c @@ -135,7 +135,7 @@ glsl_Mod_ProcessTexture (texture_t *tx) void glsl_Mod_LoadLighting (bsp_t *bsp) { - // a big hacky, but it's as good a place as any + // a bit hacky, but it's as good a place as any loadmodel->clear = glsl_brush_clear; mod_lightmap_bytes = 1; if (!bsp->lightdatasize) { diff --git a/libs/models/iqm/gl_model_iqm.c b/libs/models/iqm/gl_model_iqm.c index e2e877d1d..f57b18637 100644 --- a/libs/models/iqm/gl_model_iqm.c +++ b/libs/models/iqm/gl_model_iqm.c @@ -80,7 +80,7 @@ gl_iqm_load_textures (iqm_t *iqm) for (i = 0; i < iqm->num_meshes; i++) { dstring_copystr (str, iqm->text + iqm->meshes[i].material); QFS_StripExtension (str->str, str->str); - if ((tex = LoadImage (va ("textures/%s", str->str)))) + if ((tex = LoadImage (va ("textures/%s", str->str), 1))) gl->textures[i] = GL_LoadTexture (str->str, tex->width, tex->height, tex->data, true, false, diff --git a/libs/models/iqm/glsl_model_iqm.c b/libs/models/iqm/glsl_model_iqm.c index 5e1a26030..6a79eede7 100644 --- a/libs/models/iqm/glsl_model_iqm.c +++ b/libs/models/iqm/glsl_model_iqm.c @@ -102,12 +102,12 @@ glsl_iqm_load_textures (iqm_t *iqm) for (i = 0; i < iqm->num_meshes; i++) { dstring_copystr (str, iqm->text + iqm->meshes[i].material); QFS_StripExtension (str->str, str->str); - if ((tex = LoadImage (va ("textures/%s", str->str)))) + if ((tex = LoadImage (va ("textures/%s", str->str), 1))) glsl->textures[i] = GLSL_LoadRGBATexture (str->str, tex->width, tex->height, tex->data); else glsl->textures[i] = GLSL_LoadRGBATexture ("", 2, 2, null_texture); - if ((tex = LoadImage (va ("textures/%s_norm", str->str)))) + if ((tex = LoadImage (va ("textures/%s_norm", str->str), 1))) glsl->normmaps[i] = GLSL_LoadRGBATexture (str->str, tex->width, tex->height, tex->data); else diff --git a/libs/models/iqm/sw_model_iqm.c b/libs/models/iqm/sw_model_iqm.c index 5b609ca75..4bc8fedb9 100644 --- a/libs/models/iqm/sw_model_iqm.c +++ b/libs/models/iqm/sw_model_iqm.c @@ -54,7 +54,7 @@ #include "r_internal.h" static tex_t null_texture = { - 2, 2, tex_palette, 0, {15, 15, 15, 15} + 2, 2, tex_palette, 1, 0, {15, 15, 15, 15} }; static void @@ -165,7 +165,7 @@ sw_iqm_load_textures (iqm_t *iqm) continue; dstring_copystr (str, iqm->text + iqm->meshes[i].material); QFS_StripExtension (str->str, str->str); - if ((tex = LoadImage (va ("textures/%s", str->str)))) + if ((tex = LoadImage (va ("textures/%s", str->str), 1))) tex = sw->skins[i] = convert_tex (tex); else tex = sw->skins[i] = &null_texture; diff --git a/libs/models/skin.c b/libs/models/skin.c index 9583383cc..5e1fe0d85 100644 --- a/libs/models/skin.c +++ b/libs/models/skin.c @@ -184,7 +184,7 @@ Skin_SetSkin (skin_t *skin, int cmap, const char *skinname) name = 0; break; } - tex = LoadPCX (file, 0, r_data->vid->palette); + tex = LoadPCX (file, 0, r_data->vid->palette, 1); Qclose (file); if (!tex || tex->width > 320 || tex->height > 200) { Sys_Printf ("Bad skin %s\n", name); diff --git a/libs/models/sprite/gl_model_sprite.c b/libs/models/sprite/gl_model_sprite.c index 647b5f687..f050e9bdb 100644 --- a/libs/models/sprite/gl_model_sprite.c +++ b/libs/models/sprite/gl_model_sprite.c @@ -49,7 +49,7 @@ gl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum) tex_t *targa; const char *name; - targa = LoadImage (name = va ("%s_%i", loadmodel->name, framenum)); + targa = LoadImage (name = va ("%s_%i", loadmodel->name, framenum), 1); if (targa) { if (targa->format < 4) pspriteframe->gl_texturenum = GL_LoadTexture (name, diff --git a/libs/video/renderer/gl/gl_draw.c b/libs/video/renderer/gl/gl_draw.c index 6cebda1fb..d84e8f17e 100644 --- a/libs/video/renderer/gl/gl_draw.c +++ b/libs/video/renderer/gl/gl_draw.c @@ -175,7 +175,7 @@ gl_Draw_PicFromWad (const char *name) tex_t *targa; pic = W_GetLumpName (name); - targa = LoadImage (name); + targa = LoadImage (name, 1); if (targa) { p = malloc (sizeof (qpic_t) + sizeof (glpic_t)); p->width = pic->width; @@ -236,7 +236,7 @@ gl_Draw_CachePic (const char *path, qboolean alpha) // Adjust for endian.. SwapPic (dat); // Check for a .tga first - targa = LoadImage (path); + targa = LoadImage (path, 1); if (targa) { if (targa->format < 4) { gl->texnum = GL_LoadTexture ("", targa->width, targa->height, @@ -353,7 +353,7 @@ gl_Draw_Init (void) // write the version string into the background before turning it into a // texture - image = LoadImage ("gfx/conchars"); + image = LoadImage ("gfx/conchars", 1); if (image) { if (image->format < 4) { char_texture = GL_LoadTexture ("charset", image->width, diff --git a/libs/video/renderer/gl/gl_sky.c b/libs/video/renderer/gl/gl_sky.c index a4d325f09..4f69ef8b7 100644 --- a/libs/video/renderer/gl/gl_sky.c +++ b/libs/video/renderer/gl/gl_sky.c @@ -131,11 +131,11 @@ gl_R_LoadSkys (const char *skyname) qfglBindTexture (GL_TEXTURE_2D, SKY_TEX + i); - targa = LoadImage (name = va ("env/%s%s", skyname, suf[i])); + targa = LoadImage (name = va ("env/%s%s", skyname, suf[i]), 1); if (!targa || targa->format < 3) { // FIXME Can't do PCX right now Sys_MaskPrintf (SYS_DEV, "Couldn't load %s\n", name); // also look in gfx/env, where Darkplaces looks for skies - targa = LoadImage (name = va ("gfx/env/%s%s", skyname, suf[i])); + targa = LoadImage (name = va ("gfx/env/%s%s", skyname, suf[i]), 1); if (!targa) { Sys_MaskPrintf (SYS_DEV, "Couldn't load %s\n", name); gl_skyloaded = false; diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index acdaf22c6..0dc19103e 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -1399,7 +1399,7 @@ glsl_R_LoadSkys (const char *sky) //blender envmap // bk rt ft // dn up lt - tex = LoadImage (name = va ("env/%s_map", sky)); + tex = LoadImage (name = va ("env/%s_map", sky), 1); if (tex && tex->format >= 3 && tex->height * 3 == tex->width * 2 && is_pow2 (tex->height)) { tex_t *sub; @@ -1426,12 +1426,12 @@ glsl_R_LoadSkys (const char *sky) } else { skybox_loaded = true; for (i = 0; i < 6; i++) { - tex = LoadImage (name = va ("env/%s%s", sky, sky_suffix[i])); + tex = LoadImage (name = va ("env/%s%s", sky, sky_suffix[i]), 1); if (!tex || tex->format < 3) { // FIXME pcx support Sys_MaskPrintf (SYS_GLSL, "Couldn't load %s\n", name); // also look in gfx/env, where Darkplaces looks for skies tex = LoadImage (name = va ("gfx/env/%s%s", sky, - sky_suffix[i])); + sky_suffix[i]), 1); if (!tex || tex->format < 3) { // FIXME pcx support Sys_MaskPrintf (SYS_GLSL, "Couldn't load %s\n", name); skybox_loaded = false; diff --git a/tools/qflmp/lmp.c b/tools/qflmp/lmp.c index b8021166c..1840ce328 100644 --- a/tools/qflmp/lmp.c +++ b/tools/qflmp/lmp.c @@ -213,7 +213,7 @@ importFile (const char *inpath) if (options.verbosity > 1) Sys_Printf ("PCX file size: %d\n", fsize); - lmp = LoadPCX (infile, false, NULL); + lmp = LoadPCX (infile, false, NULL, 1); if (!lmp) { Sys_Printf ("%s: Failed to load %s as texture.\n", diff --git a/tools/qfspritegen/spritegen.c b/tools/qfspritegen/spritegen.c index 5234adc0c..08ddc86f1 100644 --- a/tools/qfspritegen/spritegen.c +++ b/tools/qfspritegen/spritegen.c @@ -190,7 +190,7 @@ LoadScreen (const char *name) file = Qopen (name, "rb"); if (!file) Sys_Error ("could not open"); - image = LoadPCX (file, false, 0); + image = LoadPCX (file, false, 0, 1); } diff --git a/tools/wad/script.c b/tools/wad/script.c index eef6a90e9..b4eaeeeff 100644 --- a/tools/wad/script.c +++ b/tools/wad/script.c @@ -92,7 +92,7 @@ load_image (const char *name) if (!(file = Qopen (name, "rb"))) Sys_Error ("couldn't open %s. %s", name, strerror(errno)); - if (!(tex = LoadPNG (file))) + if (!(tex = LoadPNG (file, 1))) Sys_Error ("couldn't read %s as PNG", name); pixels = tex->width * tex->height; From 40fc9f00005eb163181ce4922d29c93f9ff6bd48 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 19 Jan 2021 10:30:37 +0900 Subject: [PATCH 249/435] [model] Make Mod_LoadExternalTextures private It never really needed to be externally accessible as it has always been gl-specific and can be called by Mod_ProcessTexture anyway. --- include/QF/plugin/vid_render.h | 1 - include/mod_internal.h | 3 - libs/models/brush/gl_model_brush.c | 91 ++++++++++++------------- libs/models/model.c | 4 -- libs/video/renderer/vid_render_gl.c | 1 - libs/video/renderer/vid_render_glsl.c | 1 - libs/video/renderer/vid_render_sw.c | 1 - libs/video/renderer/vid_render_sw32.c | 1 - libs/video/renderer/vid_render_vulkan.c | 6 -- 9 files changed, 45 insertions(+), 64 deletions(-) diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 462aaabf4..447bc8ce6 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -80,7 +80,6 @@ typedef struct vid_particle_funcs_s { } vid_particle_funcs_t; typedef struct vid_model_funcs_s { - void (*Mod_LoadExternalTextures) (model_t *mod); void (*Mod_LoadLighting) (bsp_t *bsp); void (*Mod_SubdivideSurface) (msurface_t *fa); void (*Mod_ProcessTexture) (texture_t *tx); diff --git a/include/mod_internal.h b/include/mod_internal.h index 7f6be3e4e..2dbf624bf 100644 --- a/include/mod_internal.h +++ b/include/mod_internal.h @@ -32,17 +32,14 @@ void sw_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr); void sw_Mod_LoadExternalSkins (model_t *mod); void sw_Mod_IQMFinish (model_t *mod); -void gl_Mod_LoadExternalTextures (model_t *mod); void gl_Mod_LoadLighting (bsp_t *bsp); void gl_Mod_SubdivideSurface (msurface_t *fa); void gl_Mod_ProcessTexture(texture_t *tx); -void glsl_Mod_LoadExternalTextures (model_t *mod); void glsl_Mod_LoadLighting (bsp_t *bsp); void glsl_Mod_SubdivideSurface (msurface_t *fa); void glsl_Mod_ProcessTexture(texture_t *tx); -void sw_Mod_LoadExternalTextures (model_t *mod); void sw_Mod_LoadLighting (bsp_t *bsp); void sw_Mod_SubdivideSurface (msurface_t *fa); void sw_Mod_ProcessTexture(texture_t *tx); diff --git a/libs/models/brush/gl_model_brush.c b/libs/models/brush/gl_model_brush.c index 9c1057226..2c95cbe64 100644 --- a/libs/models/brush/gl_model_brush.c +++ b/libs/models/brush/gl_model_brush.c @@ -51,22 +51,6 @@ #include "mod_internal.h" #include "r_internal.h" - -void -gl_Mod_ProcessTexture (texture_t *tx) -{ - const char *name; - - if (!strncmp (tx->name, "sky", 3)) - return; - name = va ("fb_%s", tx->name); - tx->gl_fb_texturenum = - Mod_Fullbright ((byte *) (tx + 1), tx->width, tx->height, name); - tx->gl_texturenum = - GL_LoadTexture (tx->name, tx->width, tx->height, (byte *) (tx + 1), - true, false, 1); -} - static tex_t * Mod_LoadAnExternalTexture (char *tname, char *mname) { @@ -92,44 +76,59 @@ Mod_LoadAnExternalTexture (char *tname, char *mname) return image; } -void -gl_Mod_LoadExternalTextures (model_t *mod) +static int +Mod_LoadExternalTextures (model_t *mod, texture_t *tx) { - int i; tex_t *base, *luma; - texture_t *tx; + int external = 0; + if ((base = Mod_LoadAnExternalTexture (tx->name, mod->name))) { + external = 1; + tx->gl_texturenum = + GL_LoadTexture (tx->name, base->width, base->height, + base->data, true, false, + base->format > 2 ? base->format : 1); - for (i = 0; i < mod->numtextures; i++) { - tx = mod->textures[i]; - if (!tx) - continue; - - if ((base = Mod_LoadAnExternalTexture (tx->name, mod->name))) { - tx->gl_texturenum = - GL_LoadTexture (tx->name, base->width, base->height, - base->data, true, false, - base->format > 2 ? base->format : 1); - - luma = Mod_LoadAnExternalTexture (va ("%s_luma", tx->name), + luma = Mod_LoadAnExternalTexture (va ("%s_luma", tx->name), + mod->name); + if (!luma) + luma = Mod_LoadAnExternalTexture (va ("%s_glow", tx->name), mod->name); - if (!luma) - luma = Mod_LoadAnExternalTexture (va ("%s_glow", tx->name), - mod->name); - tx->gl_fb_texturenum = 0; + tx->gl_fb_texturenum = 0; - if (luma) { - tx->gl_fb_texturenum = - GL_LoadTexture (va ("fb_%s", tx->name), luma->width, - luma->height, luma->data, true, true, - luma->format > 2 ? luma->format : 1); - } else if (base->format < 3) { - tx->gl_fb_texturenum = - Mod_Fullbright (base->data, base->width, base->height, - va ("fb_%s", tx->name)); - } + if (luma) { + tx->gl_fb_texturenum = + GL_LoadTexture (va ("fb_%s", tx->name), luma->width, + luma->height, luma->data, true, true, + luma->format > 2 ? luma->format : 1); + } else if (base->format < 3) { + tx->gl_fb_texturenum = + Mod_Fullbright (base->data, base->width, base->height, + va ("fb_%s", tx->name)); } } + return external; +} + +void +gl_Mod_ProcessTexture (texture_t *tx) +{ + const char *name; + + if (gl_textures_external && gl_textures_external->int_val) { + if (Mod_LoadExternalTextures (loadmodel, tx)) { + return; + } + } + if (strncmp (tx->name, "sky", 3) == 0) { + return; + } + name = va ("fb_%s", tx->name); + tx->gl_fb_texturenum = + Mod_Fullbright ((byte *) (tx + 1), tx->width, tx->height, name); + tx->gl_texturenum = + GL_LoadTexture (tx->name, tx->width, tx->height, (byte *) (tx + 1), + true, false, 1); } void diff --git a/libs/models/model.c b/libs/models/model.c index bac0223de..d8ce5df03 100644 --- a/libs/models/model.c +++ b/libs/models/model.c @@ -231,10 +231,6 @@ Mod_RealLoadModel (model_t *mod, qboolean crash, cache_allocator_t allocator) default: // Version 29: Quake 1 .bsp // Version 38: Quake 2 .bsp Mod_LoadBrushModel (mod, buf); - - if (gl_textures_external && gl_textures_external->int_val - && mod_funcs && mod_funcs->Mod_LoadExternalTextures) - mod_funcs->Mod_LoadExternalTextures (mod); break; } free (buf); diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 852a0a423..8e12a67ec 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -46,7 +46,6 @@ gl_ctx_t *gl_ctx; static vid_model_funcs_t model_funcs = { - gl_Mod_LoadExternalTextures, gl_Mod_LoadLighting, gl_Mod_SubdivideSurface, gl_Mod_ProcessTexture, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 6d6c87b3a..be427f3ca 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -46,7 +46,6 @@ gl_ctx_t *glsl_ctx; static vid_model_funcs_t model_funcs = { - 0,//Mod_LoadExternalTextures, glsl_Mod_LoadLighting, 0,//Mod_SubdivideSurface, glsl_Mod_ProcessTexture, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 8c5360701..e30ef9e2e 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -39,7 +39,6 @@ sw_ctx_t *sw_ctx; static vid_model_funcs_t model_funcs = { - 0,//Mod_LoadExternalTextures, sw_Mod_LoadLighting, 0,//Mod_SubdivideSurface, 0,//Mod_ProcessTexture, diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index af72bc0df..895098065 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -44,7 +44,6 @@ sw_ctx_t *sw32_ctx; static vid_model_funcs_t model_funcs = { - 0,//Mod_LoadExternalTextures, sw_Mod_LoadLighting, 0,//Mod_SubdivideSurface, 0,//Mod_ProcessTexture, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 80ccf0127..8cfb7926a 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -385,11 +385,6 @@ vulkan_r_particles_style_f (struct cvar_s *var) Vulkan_r_particles_style_f (var, vulkan_ctx); } -static void -vulkan_Mod_LoadExternalTextures (model_t *mod) -{ -} - static void vulkan_Mod_LoadLighting (bsp_t *bsp) { @@ -454,7 +449,6 @@ vulkan_Skin_InitTranslations (void) } static vid_model_funcs_t model_funcs = { - vulkan_Mod_LoadExternalTextures, vulkan_Mod_LoadLighting, vulkan_Mod_SubdivideSurface, vulkan_Mod_ProcessTexture, From 6e0cb7b917c951b2d42555156160bbf8de3152c9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 19 Jan 2021 13:05:39 +0900 Subject: [PATCH 250/435] [model] Isolate renderer specific texture data This cleans up texture_t and possibly even improves locality of reference when running through texture chains (not profiled, and not actually the goal). --- include/QF/model.h | 12 ++----- include/QF/plugin/vid_render.h | 1 + include/mod_internal.h | 3 -- include/r_internal.h | 27 +++++++++++++++ libs/models/brush/gl_model_brush.c | 22 ++++++++---- libs/models/brush/glsl_model_brush.c | 32 ++++++++++++------ libs/models/brush/model_brush.c | 16 ++++++++- libs/video/renderer/gl/gl_rsurf.c | 29 +++++++++------- libs/video/renderer/glsl/glsl_bsp.c | 45 +++++++++++++------------ libs/video/renderer/vid_render_gl.c | 1 + libs/video/renderer/vid_render_glsl.c | 1 + libs/video/renderer/vid_render_sw.c | 1 + libs/video/renderer/vid_render_sw32.c | 1 + libs/video/renderer/vid_render_vulkan.c | 1 + 14 files changed, 130 insertions(+), 62 deletions(-) diff --git a/include/QF/model.h b/include/QF/model.h index d4b243241..e8cb22367 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -91,19 +91,13 @@ typedef struct instsurf_s { typedef struct texture_s { char *name; - unsigned int width, height; - int gl_texturenum; - int gl_fb_texturenum; - int sky_tex[2]; - instsurf_t *tex_chain; // for gl_texsort drawing - instsurf_t **tex_chain_tail; - struct elechain_s *elechain; - struct elechain_s **elechain_tail; + unsigned width, height; + void *render; // renderer specific data int anim_total; // total tenths in sequence ( 0 = no) int anim_min, anim_max; // time for this frame min <=time< max struct texture_s *anim_next; // in the animation sequence struct texture_s *alternate_anims; // bmodels in frmae 1 use these - unsigned int offsets[MIPLEVELS]; // four mip maps stored + unsigned offsets[MIPLEVELS]; // four mip maps stored } texture_t; diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 447bc8ce6..b2ea3d224 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -80,6 +80,7 @@ typedef struct vid_particle_funcs_s { } vid_particle_funcs_t; typedef struct vid_model_funcs_s { + size_t texture_render_size;// size of renderer specific texture data void (*Mod_LoadLighting) (bsp_t *bsp); void (*Mod_SubdivideSurface) (msurface_t *fa); void (*Mod_ProcessTexture) (texture_t *tx); diff --git a/include/mod_internal.h b/include/mod_internal.h index 2dbf624bf..125da1065 100644 --- a/include/mod_internal.h +++ b/include/mod_internal.h @@ -37,12 +37,9 @@ void gl_Mod_SubdivideSurface (msurface_t *fa); void gl_Mod_ProcessTexture(texture_t *tx); void glsl_Mod_LoadLighting (bsp_t *bsp); -void glsl_Mod_SubdivideSurface (msurface_t *fa); void glsl_Mod_ProcessTexture(texture_t *tx); void sw_Mod_LoadLighting (bsp_t *bsp); -void sw_Mod_SubdivideSurface (msurface_t *fa); -void sw_Mod_ProcessTexture(texture_t *tx); void gl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum); void glsl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum); diff --git a/include/r_internal.h b/include/r_internal.h index b38f1706c..37edbbdd2 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -9,6 +9,33 @@ #include "r_screen.h" #include "r_shared.h" +typedef struct gltex_s { + texture_t *texture; + int gl_texturenum; + int gl_fb_texturenum; + instsurf_t *tex_chain; // for gl_texsort drawing + instsurf_t **tex_chain_tail; +} gltex_t; + +typedef struct glsltex_s { + texture_t *texture; + int gl_texturenum; + int sky_tex[2]; + instsurf_t *tex_chain; // for gl_texsort drawing + instsurf_t **tex_chain_tail; + struct elechain_s *elechain; + struct elechain_s **elechain_tail; +} glsltex_t; + +typedef struct vulktex_s { + texture_t *texture; + struct qfv_tex_s *tex; + instsurf_t *tex_chain; // for gl_texsort drawing + instsurf_t **tex_chain_tail; + struct elechain_s *elechain; + struct elechain_s **elechain_tail; +} vulktex_t; + extern viddef_t vid; // global video state extern vid_render_data_t vid_render_data; diff --git a/libs/models/brush/gl_model_brush.c b/libs/models/brush/gl_model_brush.c index 2c95cbe64..1d7d04634 100644 --- a/libs/models/brush/gl_model_brush.c +++ b/libs/models/brush/gl_model_brush.c @@ -51,6 +51,8 @@ #include "mod_internal.h" #include "r_internal.h" +static gltex_t gl_notexture = { }; + static tex_t * Mod_LoadAnExternalTexture (char *tname, char *mname) { @@ -80,10 +82,13 @@ static int Mod_LoadExternalTextures (model_t *mod, texture_t *tx) { tex_t *base, *luma; + gltex_t *gltx; int external = 0; + + gltx = tx->render; if ((base = Mod_LoadAnExternalTexture (tx->name, mod->name))) { external = 1; - tx->gl_texturenum = + gltx->gl_texturenum = GL_LoadTexture (tx->name, base->width, base->height, base->data, true, false, base->format > 2 ? base->format : 1); @@ -94,15 +99,15 @@ Mod_LoadExternalTextures (model_t *mod, texture_t *tx) luma = Mod_LoadAnExternalTexture (va ("%s_glow", tx->name), mod->name); - tx->gl_fb_texturenum = 0; + gltx->gl_fb_texturenum = 0; if (luma) { - tx->gl_fb_texturenum = + gltx->gl_fb_texturenum = GL_LoadTexture (va ("fb_%s", tx->name), luma->width, luma->height, luma->data, true, true, luma->format > 2 ? luma->format : 1); } else if (base->format < 3) { - tx->gl_fb_texturenum = + gltx->gl_fb_texturenum = Mod_Fullbright (base->data, base->width, base->height, va ("fb_%s", tx->name)); } @@ -115,6 +120,10 @@ gl_Mod_ProcessTexture (texture_t *tx) { const char *name; + if (!tx) { + r_notexture_mip->render = &gl_notexture; + return; + } if (gl_textures_external && gl_textures_external->int_val) { if (Mod_LoadExternalTextures (loadmodel, tx)) { return; @@ -123,10 +132,11 @@ gl_Mod_ProcessTexture (texture_t *tx) if (strncmp (tx->name, "sky", 3) == 0) { return; } + gltex_t *gltex = tx->render; name = va ("fb_%s", tx->name); - tx->gl_fb_texturenum = + gltex->gl_fb_texturenum = Mod_Fullbright ((byte *) (tx + 1), tx->width, tx->height, name); - tx->gl_texturenum = + gltex->gl_texturenum = GL_LoadTexture (tx->name, tx->width, tx->height, (byte *) (tx + 1), true, false, 1); } diff --git a/libs/models/brush/glsl_model_brush.c b/libs/models/brush/glsl_model_brush.c index 67fff7b44..e839f5317 100644 --- a/libs/models/brush/glsl_model_brush.c +++ b/libs/models/brush/glsl_model_brush.c @@ -57,6 +57,9 @@ #include "compat.h" #include "mod_internal.h" +#include "r_internal.h" + +static glsltex_t glsl_notexture = { }; static void glsl_brush_clear (model_t *m) @@ -66,11 +69,15 @@ glsl_brush_clear (model_t *m) m->needload = true; for (i = 0; i < m->numtextures; i++) { // NOTE: some maps (eg e1m2) have empty texture slots - if (m->textures[i] && m->textures[i]->gl_texturenum) { - GLSL_ReleaseTexture (m->textures[i]->gl_texturenum); - GLSL_ReleaseTexture (m->textures[i]->sky_tex[0]); - GLSL_ReleaseTexture (m->textures[i]->sky_tex[1]); - m->textures[i]->gl_texturenum = 0; + glsltex_t *tex = 0; + if (m->textures[i]) { + tex = m->textures[i]->render; + } + if (tex && tex->gl_texturenum) { + GLSL_ReleaseTexture (tex->gl_texturenum); + GLSL_ReleaseTexture (tex->sky_tex[0]); + GLSL_ReleaseTexture (tex->sky_tex[1]); + tex->gl_texturenum = 0; } } for (i = 0; i < m->numsurfaces; i++) { @@ -96,6 +103,11 @@ load_skytex (texture_t *tx, byte *data) void glsl_Mod_ProcessTexture (texture_t *tx) { + if (!tx) { + r_notexture_mip->render = &glsl_notexture; + return; + } + glsltex_t *tex = tx->render; if (!strncmp (tx->name, "sky", 3)) { // sky textures need to be loaded as two separate textures to allow // wrapping on both sky layers. @@ -112,23 +124,23 @@ glsl_Mod_ProcessTexture (texture_t *tx) // a square sky texture probably means it's black, but just in // case some other magic is being done, duplicate the square to // both sky layers. - tx->sky_tex[0] = load_skytex (tx, tx_data); - tx->sky_tex[1] = tx->sky_tex[0]; + tex->sky_tex[0] = load_skytex (tx, tx_data); + tex->sky_tex[1] = tex->sky_tex[0]; } else if (tx_w == 2 * tx_h) { data = alloca (tx_h * tx_h); for (i = 0; i < 2; i++) { for (j = 0; j < tx_h; j++) memcpy (&data[j * tx_h], &tx_data[j * tx_w + i * tx_h], tx_h); - tx->sky_tex[i] = load_skytex (tx, data); + tex->sky_tex[i] = load_skytex (tx, data); } - tx->gl_texturenum = 0; + tex->gl_texturenum = 0; } else { Sys_Error ("Mod_ProcessTexture: invalid sky texture: %dx%d\n", tx_w, tx_h); } } else { - tx->gl_texturenum = GLSL_LoadQuakeMipTex (tx); + tex->gl_texturenum = GLSL_LoadQuakeMipTex (tx); } } diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index 19d28a8c6..f3ab08689 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -204,8 +204,22 @@ Mod_LoadTextures (bsp_t *bsp) if (!strncmp (mt->name, "sky", 3)) loadmodel->skytexture = tx; - if (mod_funcs && mod_funcs->Mod_ProcessTexture) + } + if (mod_funcs && mod_funcs->Mod_ProcessTexture) { + size_t render_size = mod_funcs->texture_render_size; + byte *render_data = 0; + if (render_size) { + render_data = Hunk_AllocName (m->nummiptex * render_size, + loadname); + } + for (i = 0; i < m->nummiptex; i++) { + tx = loadmodel->textures[i]; + tx->render = render_data; + render_data += render_size; mod_funcs->Mod_ProcessTexture (tx); + } + // signal the end of the textures + mod_funcs->Mod_ProcessTexture (0); } // sequence the animations diff --git a/libs/video/renderer/gl/gl_rsurf.c b/libs/video/renderer/gl/gl_rsurf.c index 3cfb3c49b..f673e4cc4 100644 --- a/libs/video/renderer/gl/gl_rsurf.c +++ b/libs/video/renderer/gl/gl_rsurf.c @@ -85,7 +85,7 @@ static instsurf_t **sky_chain_tail; (chain) = inst; \ } while (0) -static texture_t **r_texture_chains; +static gltex_t **r_texture_chains; static int r_num_texture_chains; static int max_texture_chains; @@ -129,16 +129,17 @@ release_instsurfs (void) } void -gl_R_AddTexture (texture_t *tex) +gl_R_AddTexture (texture_t *tx) { int i; if (r_num_texture_chains == max_texture_chains) { max_texture_chains += 64; r_texture_chains = realloc (r_texture_chains, - max_texture_chains * sizeof (texture_t *)); + max_texture_chains * sizeof (gltex_t *)); for (i = r_num_texture_chains; i < max_texture_chains; i++) r_texture_chains[i] = 0; } + gltex_t *tex = tx->render; r_texture_chains[r_num_texture_chains++] = tex; tex->tex_chain = NULL; tex->tex_chain_tail = &tex->tex_chain; @@ -174,7 +175,7 @@ R_RenderFullbrights (void) int i, j; glpoly_t *p; instsurf_t *sc; - texture_t *tex; + gltex_t *tex; for (i = 0; i < r_num_texture_chains; i++) { if (!(tex = r_texture_chains[i]) || !tex->gl_fb_texturenum) @@ -332,13 +333,15 @@ gl_R_DrawWaterSurfaces (void) i = -1; for (s = waterchain; s; s = s->tex_chain) { + gltex_t *tex; fa = s->surface; if (s->transform) qfglLoadMatrixf (s->transform); else qfglLoadMatrixf (gl_r_world_matrix); - if (i != fa->texinfo->texture->gl_texturenum) { - i = fa->texinfo->texture->gl_texturenum; + tex = fa->texinfo->texture->render; + if (i != tex->gl_texturenum) { + i = tex->gl_texturenum; qfglBindTexture (GL_TEXTURE_2D, i); } GL_EmitWaterPolys (fa); @@ -360,7 +363,7 @@ DrawTextureChains (int disable_blend, int do_bind) int i; instsurf_t *s; msurface_t *fa; - texture_t *tex; + gltex_t *tex; if (gl_mtex_active_tmus >= 2) { // Lightmaps @@ -469,7 +472,7 @@ static void clear_texture_chains (void) { int i; - texture_t *tex; + gltex_t *tex; for (i = 0; i < r_num_texture_chains; i++) { tex = r_texture_chains[i]; @@ -478,7 +481,7 @@ clear_texture_chains (void) tex->tex_chain = NULL; tex->tex_chain_tail = &tex->tex_chain; } - tex = r_notexture_mip; + tex = r_notexture_mip->render; tex->tex_chain = NULL; tex->tex_chain_tail = &tex->tex_chain; release_instsurfs (); @@ -496,12 +499,14 @@ chain_surface (msurface_t *surf, vec_t *transform, float *color) } else if (surf->flags & SURF_DRAWSKY) { CHAIN_SURF_F2B (surf, sky_chain); } else { - texture_t *tex; + texture_t *tx; + gltex_t *tex; if (!surf->texinfo->texture->anim_total) - tex = surf->texinfo->texture; + tx = surf->texinfo->texture; else - tex = R_TextureAnimation (surf); + tx = R_TextureAnimation (surf); + tex = tx->render; CHAIN_SURF_F2B (surf, tex->tex_chain); R_AddToLightmapChain (surf); diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index 0dc19103e..409450901 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -73,7 +73,7 @@ static instsurf_t **waterchain_tail = &waterchain; static instsurf_t *sky_chain; static instsurf_t **sky_chain_tail = &sky_chain; -static texture_t **r_texture_chains; +static glsltex_t **r_texture_chains; static int r_num_texture_chains; static int max_texture_chains; @@ -293,16 +293,17 @@ GET_RELEASE (instsurf_t, static_instsurf) GET_RELEASE (instsurf_t, instsurf) void -glsl_R_AddTexture (texture_t *tex) +glsl_R_AddTexture (texture_t *tx) { int i; if (r_num_texture_chains == max_texture_chains) { max_texture_chains += 64; r_texture_chains = realloc (r_texture_chains, - max_texture_chains * sizeof (texture_t *)); + max_texture_chains * sizeof (glsltex_t *)); for (i = r_num_texture_chains; i < max_texture_chains; i++) r_texture_chains[i] = 0; } + glsltex_t *tex = tx->render; r_texture_chains[r_num_texture_chains++] = tex; tex->tex_chain = 0; tex->tex_chain_tail = &tex->tex_chain; @@ -325,7 +326,7 @@ glsl_R_InitSurfaceChains (model_t *model) } static inline void -clear_tex_chain (texture_t *tex) +clear_tex_chain (glsltex_t *tex) { tex->tex_chain = 0; tex->tex_chain_tail = &tex->tex_chain; @@ -343,7 +344,7 @@ clear_texture_chains (void) continue; clear_tex_chain (r_texture_chains[i]); } - clear_tex_chain (r_notexture_mip); + clear_tex_chain (r_notexture_mip->render); release_elechains (); release_elementss (); release_instsurfs (); @@ -382,12 +383,14 @@ chain_surface (msurface_t *surf, vec_t *transform, float *color) } else if ((surf->flags & SURF_DRAWTURB) || (color && color[3] < 1.0)) { CHAIN_SURF_B2F (surf, waterchain); } else { - texture_t *tex; + texture_t *tx; + glsltex_t *tex; if (!surf->texinfo->texture->anim_total) - tex = surf->texinfo->texture; + tx = surf->texinfo->texture; else - tex = R_TextureAnimation (surf); + tx = R_TextureAnimation (surf); + tex = tx->render; CHAIN_SURF_F2B (surf, tex->tex_chain); update_lightmap (surf); @@ -444,7 +447,7 @@ glsl_R_RegisterTextures (model_t **models, int num_models) } static elechain_t * -add_elechain (texture_t *tex, int ec_index) +add_elechain (glsltex_t *tex, int ec_index) { elechain_t *ec; @@ -563,7 +566,7 @@ glsl_R_BuildDisplayLists (model_t **models, int num_models) // non-bsp models don't have surfaces. dm = m->submodels; for (j = 0; j < m->numsurfaces; j++) { - texture_t *tex; + glsltex_t *tex; if (j == dm->firstface + dm->numfaces) { dm++; if (dm - m->submodels == m->numsubmodels) { @@ -578,7 +581,7 @@ glsl_R_BuildDisplayLists (model_t **models, int num_models) surf->ec_index = dm - m->submodels; if (!surf->ec_index && m != r_worldentity.model) surf->ec_index = -1 - i; // instanced model - tex = surf->texinfo->texture; + tex = surf->texinfo->texture->render; CHAIN_SURF_F2B (surf, tex->tex_chain); } } @@ -590,7 +593,7 @@ glsl_R_BuildDisplayLists (model_t **models, int num_models) // For animated textures, if a surface is on one texture of the group, it // will be on all. for (i = 0; i < r_num_texture_chains; i++) { - texture_t *tex; + glsltex_t *tex; instsurf_t *is; elechain_t *ec = 0; elements_t *el = 0; @@ -1057,7 +1060,7 @@ sky_end (void) } static inline void -add_surf_elements (texture_t *tex, instsurf_t *is, +add_surf_elements (glsltex_t *tex, instsurf_t *is, elechain_t **ec, elements_t **el) { msurface_t *surf = is->surface; @@ -1096,7 +1099,7 @@ add_surf_elements (texture_t *tex, instsurf_t *is, } static void -build_tex_elechain (texture_t *tex) +build_tex_elechain (glsltex_t *tex) { instsurf_t *is; elechain_t *ec = 0; @@ -1136,7 +1139,7 @@ glsl_R_DrawWorld (void) bsp_begin (); qfeglActiveTexture (GL_TEXTURE0 + 0); for (i = 0; i < r_num_texture_chains; i++) { - texture_t *tex; + glsltex_t *tex; elechain_t *ec = 0; tex = r_texture_chains[i]; @@ -1163,7 +1166,7 @@ glsl_R_DrawWaterSurfaces () { instsurf_t *is; msurface_t *surf; - texture_t *tex = 0; + glsltex_t *tex = 0; elechain_t *ec = 0; elements_t *el = 0; @@ -1173,7 +1176,7 @@ glsl_R_DrawWaterSurfaces () turb_begin (); for (is = waterchain; is; is = is->tex_chain) { surf = is->surface; - if (tex != surf->texinfo->texture) { + if (tex != surf->texinfo->texture->render) { if (tex) { qfeglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum); for (ec = tex->elechain; ec; ec = ec->next) @@ -1184,7 +1187,7 @@ glsl_R_DrawWaterSurfaces () tex->elechain = 0; tex->elechain_tail = &tex->elechain; } - tex = surf->texinfo->texture; + tex = surf->texinfo->texture->render; } add_surf_elements (tex, is, &ec, &el); } @@ -1209,7 +1212,7 @@ glsl_R_DrawSky (void) { instsurf_t *is; msurface_t *surf; - texture_t *tex = 0; + glsltex_t *tex = 0; elechain_t *ec = 0; elements_t *el = 0; @@ -1219,7 +1222,7 @@ glsl_R_DrawSky (void) sky_begin (); for (is = sky_chain; is; is = is->tex_chain) { surf = is->surface; - if (tex != surf->texinfo->texture) { + if (tex != surf->texinfo->texture->render) { if (tex) { if (!skybox_loaded) { qfeglActiveTexture (GL_TEXTURE0 + 0); @@ -1233,7 +1236,7 @@ glsl_R_DrawSky (void) tex->elechain = 0; tex->elechain_tail = &tex->elechain; } - tex = surf->texinfo->texture; + tex = surf->texinfo->texture->render; } add_surf_elements (tex, is, &ec, &el); } diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 8e12a67ec..584f03ada 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -46,6 +46,7 @@ gl_ctx_t *gl_ctx; static vid_model_funcs_t model_funcs = { + sizeof (gltex_t), gl_Mod_LoadLighting, gl_Mod_SubdivideSurface, gl_Mod_ProcessTexture, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index be427f3ca..d8abed43e 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -46,6 +46,7 @@ gl_ctx_t *glsl_ctx; static vid_model_funcs_t model_funcs = { + sizeof (glsltex_t), glsl_Mod_LoadLighting, 0,//Mod_SubdivideSurface, glsl_Mod_ProcessTexture, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index e30ef9e2e..0ef7a0108 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -39,6 +39,7 @@ sw_ctx_t *sw_ctx; static vid_model_funcs_t model_funcs = { + 0, sw_Mod_LoadLighting, 0,//Mod_SubdivideSurface, 0,//Mod_ProcessTexture, diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index 895098065..a3fe10d97 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -44,6 +44,7 @@ sw_ctx_t *sw32_ctx; static vid_model_funcs_t model_funcs = { + 0, sw_Mod_LoadLighting, 0,//Mod_SubdivideSurface, 0,//Mod_ProcessTexture, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 8cfb7926a..717809012 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -449,6 +449,7 @@ vulkan_Skin_InitTranslations (void) } static vid_model_funcs_t model_funcs = { + sizeof (vulktex_t), vulkan_Mod_LoadLighting, vulkan_Mod_SubdivideSurface, vulkan_Mod_ProcessTexture, From 7a353d5aeeecee59f42b1ac9ffd04d3d2b96b3d9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 19 Jan 2021 13:53:08 +0900 Subject: [PATCH 251/435] [model] Build vulkan model libs The contents are currently empty (required .c files), but this gets the build system updated. --- config.d/build_control.m4 | 29 +++++++++++++++--------- libs/models/Makemodule.am | 17 +++++++++++++- libs/models/alias/Makemodule.am | 15 ++++++++++-- libs/models/alias/vulkan_model_alias.c | 0 libs/models/brush/Makemodule.am | 16 +++++++++++-- libs/models/brush/vulkan_model_brush.c | 0 libs/models/iqm/Makemodule.am | 16 +++++++++++-- libs/models/iqm/vulkan_model_iqm.c | 0 libs/models/sprite/Makemodule.am | 16 +++++++++++-- libs/models/sprite/vulkan_model_sprite.c | 0 libs/models/vulkan_skin.c | 0 libs/video/renderer/Makemodule.am | 7 +++--- 12 files changed, 93 insertions(+), 23 deletions(-) create mode 100644 libs/models/alias/vulkan_model_alias.c create mode 100644 libs/models/brush/vulkan_model_brush.c create mode 100644 libs/models/iqm/vulkan_model_iqm.c create mode 100644 libs/models/sprite/vulkan_model_sprite.c create mode 100644 libs/models/vulkan_skin.c diff --git a/config.d/build_control.m4 b/config.d/build_control.m4 index d67d50033..be71d59f4 100644 --- a/config.d/build_control.m4 +++ b/config.d/build_control.m4 @@ -72,10 +72,14 @@ if test "x$HAVE_X" = xyes; then CL_TARGETS="$CL_TARGETS X11" VID_TARGETS="$VID_TARGETS libs/video/targets/libQFx11.la" if test "$HAVE_VULKAN" = "yes"; then - QF_NEED(vid_render, [sw sw32 gl glsl vulkan]) - else - QF_NEED(vid_render, [sw sw32 gl glsl]) + QF_NEED(vid_render, [vulkan]) + QF_NEED(models, [vulkan]) + QF_NEED(alias, [vulkan]) + QF_NEED(brush, [vulkan]) + QF_NEED(iqm, [vulkan]) + QF_NEED(sprite, [vulkan]) fi + QF_NEED(vid_render, [sw sw32 gl glsl]) QF_NEED(models, [sw gl glsl]) QF_NEED(alias, [sw gl glsl]) QF_NEED(brush, [sw gl glsl]) @@ -100,10 +104,13 @@ if test "x$HAVE_SDL" = xyes; then CL_TARGETS="$CL_TARGETS SDL" VID_TARGETS="$VID_TARGETS libs/video/targets/libQFsdl.la" if test "$HAVE_VULKAN" = "yes"; then - QF_NEED(vid_render, [sw sw32 gl glsl vulkan]) - else - QF_NEED(vid_render, [sw sw32 gl glsl]) + QF_NEED(vid_render, [vulkan]) + QF_NEED(alias, [vulkan]) + QF_NEED(brush, [vulkan]) + QF_NEED(iqm, [vulkan]) + QF_NEED(sprite, [vulkan]) fi + QF_NEED(vid_render, [sw sw32 gl glsl]) QF_NEED(models, [sw gl glsl]) QF_NEED(alias, [sw gl glsl]) QF_NEED(brush, [sw gl glsl]) @@ -291,11 +298,11 @@ QF_PROCESS_NEED_DIRS(top, [libs hw nq qtv qw tools ruamoko]) QF_PROCESS_NEED_LIBS(swrend, [asm]) QF_PROCESS_NEED_DIRS(vid_render, [gl glsl sw sw32 vulkan]) -QF_PROCESS_NEED_LIBS(models, [gl glsl sw], [libs/models]) -QF_PROCESS_NEED_LIBS(alias, [gl glsl sw], [libs/models/alias]) -QF_PROCESS_NEED_LIBS(brush, [gl glsl sw], [libs/models/brush]) -QF_PROCESS_NEED_LIBS(iqm, [gl glsl sw], [libs/models/iqm]) -QF_PROCESS_NEED_LIBS(sprite, [gl glsl sw], [libs/models/sprite]) +QF_PROCESS_NEED_LIBS(models, [gl glsl sw vulkan], [libs/models]) +QF_PROCESS_NEED_LIBS(alias, [gl glsl sw vulkan], [libs/models/alias]) +QF_PROCESS_NEED_LIBS(brush, [gl glsl sw vulkan], [libs/models/brush]) +QF_PROCESS_NEED_LIBS(iqm, [gl glsl sw vulkan], [libs/models/iqm]) +QF_PROCESS_NEED_LIBS(sprite, [gl glsl sw vulkan], [libs/models/sprite]) QF_PROCESS_NEED_LIBS(vid, [common sdl svga x11], [libs/video/targets]) QF_PROCESS_NEED_LIBS(qw, [client common sdl server], [qw/source], a) diff --git a/libs/models/Makemodule.am b/libs/models/Makemodule.am index 2fbc7380d..24e5a3ca3 100644 --- a/libs/models/Makemodule.am +++ b/libs/models/Makemodule.am @@ -6,7 +6,11 @@ include libs/models/test/Makemodule.am lib_LTLIBRARIES += libs/models/libQFmodels.la noinst_LTLIBRARIES += @models_libs@ -EXTRA_LTLIBRARIES += libs/models/libmodels_gl.la libs/models/libmodels_glsl.la libs/models/libmodels_sw.la +EXTRA_LTLIBRARIES += \ + libs/models/libmodels_gl.la \ + libs/models/libmodels_glsl.la \ + libs/models/libmodels_sw.la \ + libs/models/libmodels_vulkan.la models_sources = libs/models/clip_hull.c libs/models/model.c libs/models/portal.c libs/models/trace.c libs/models/winding.c @@ -53,3 +57,14 @@ libs_models_libmodels_sw_la_LDFLAGS= libs_models_libmodels_sw_la_LIBADD= $(sw_libs) libs_models_libmodels_sw_la_DEPENDENCIES= $(sw_libs) libs_models_libmodels_sw_la_SOURCES= libs/models/sw_skin.c libs/models/skin.c + +vulkan_libs= \ + libs/models/alias/libalias_vulkan.la \ + libs/models/brush/libbrush_vulkan.la \ + libs/models/iqm/libiqm_vulkan.la \ + libs/models/sprite/libsprite_vulkan.la \ + libs/image/libQFimage.la +libs_models_libmodels_vulkan_la_LDFLAGS= +libs_models_libmodels_vulkan_la_LIBADD= $(vulkan_libs) +libs_models_libmodels_vulkan_la_DEPENDENCIES= $(vulkan_libs) +libs_models_libmodels_vulkan_la_SOURCES= libs/models/vulkan_skin.c libs/models/skin.c diff --git a/libs/models/alias/Makemodule.am b/libs/models/alias/Makemodule.am index 42f2c5a73..cac8d4a09 100644 --- a/libs/models/alias/Makemodule.am +++ b/libs/models/alias/Makemodule.am @@ -1,15 +1,26 @@ noinst_LTLIBRARIES += @alias_libs@ -EXTRA_LTLIBRARIES += libs/models/alias/libalias_gl.la libs/models/alias/libalias_glsl.la libs/models/alias/libalias_sw.la +EXTRA_LTLIBRARIES += \ + libs/models/alias/libalias_gl.la \ + libs/models/alias/libalias_glsl.la \ + libs/models/alias/libalias_sw.la \ + libs/models/alias/libalias_vulkan.la alias_src= libs/models/alias/model_alias.c alias_gl_src= libs/models/alias/gl_mesh.c libs/models/alias/gl_model_alias.c libs/models/alias/floodfill.c alias_glsl_src= libs/models/alias/glsl_model_alias.c libs/models/alias/floodfill.c alias_sw_src= libs/models/alias/sw_model_alias.c +alias_vulkan_src= libs/models/alias/vulkan_model_alias.c libs_models_alias_libalias_gl_la_SOURCES= $(alias_gl_src) $(alias_src) libs_models_alias_libalias_glsl_la_SOURCES= $(alias_glsl_src) $(alias_src) libs_models_alias_libalias_sw_la_SOURCES= $(alias_sw_src) $(alias_src) +libs_models_alias_libalias_vulkan_la_SOURCES= $(alias_vulkan_src) $(alias_src) -EXTRA_DIST += $(alias_gl_src) $(alias_glsl_src) $(alias_sw_src) $(alias_src) +EXTRA_DIST += \ + $(alias_gl_src) \ + $(alias_glsl_src) \ + $(alias_sw_src) \ + $(alias_vulkan_src) \ + $(alias_src) diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c new file mode 100644 index 000000000..e69de29bb diff --git a/libs/models/brush/Makemodule.am b/libs/models/brush/Makemodule.am index a07ce0726..4a6f03a1f 100644 --- a/libs/models/brush/Makemodule.am +++ b/libs/models/brush/Makemodule.am @@ -1,10 +1,15 @@ noinst_LTLIBRARIES += libs/models/brush/libbrush.la @brush_libs@ -EXTRA_LTLIBRARIES += libs/models/brush/libbrush_gl.la libs/models/brush/libbrush_glsl.la libs/models/brush/libbrush_sw.la +EXTRA_LTLIBRARIES += \ + libs/models/brush/libbrush_gl.la \ + libs/models/brush/libbrush_glsl.la \ + libs/models/brush/libbrush_sw.la \ + libs/models/brush/libbrush_vulkan.la brush_src= libs/models/brush/model_brush.c brush_gl_src= libs/models/brush/gl_model_brush.c brush_glsl_src= libs/models/brush/glsl_model_brush.c brush_sw_src= libs/models/brush/sw_model_brush.c +brush_vulkan_src= libs/models/brush/vulkan_model_brush.c libs_models_brush_libbrush_la_SOURCES= $(brush_src) @@ -14,4 +19,11 @@ libs_models_brush_libbrush_glsl_la_SOURCES= $(brush_glsl_src) $(brush_src) libs_models_brush_libbrush_sw_la_SOURCES= $(brush_sw_src) $(brush_src) -EXTRA_DIST += $(brush_gl_src) $(brush_glsl_src) $(brush_sw_src) $(brush_src) +libs_models_brush_libbrush_vulkan_la_SOURCES= $(brush_vulkan_src) $(brush_src) + +EXTRA_DIST += \ + $(brush_gl_src) \ + $(brush_glsl_src) \ + $(brush_sw_src) \ + ${brush_vulkan_src} \ + $(brush_src) diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c new file mode 100644 index 000000000..e69de29bb diff --git a/libs/models/iqm/Makemodule.am b/libs/models/iqm/Makemodule.am index 20c29548b..cc362050d 100644 --- a/libs/models/iqm/Makemodule.am +++ b/libs/models/iqm/Makemodule.am @@ -1,10 +1,15 @@ noinst_LTLIBRARIES += @iqm_libs@ -EXTRA_LTLIBRARIES += libs/models/iqm/libiqm_gl.la libs/models/iqm/libiqm_glsl.la libs/models/iqm/libiqm_sw.la +EXTRA_LTLIBRARIES += \ + libs/models/iqm/libiqm_gl.la \ + libs/models/iqm/libiqm_glsl.la \ + libs/models/iqm/libiqm_sw.la \ + libs/models/iqm/libiqm_vulkan.la iqm_src= libs/models/iqm/model_iqm.c iqm_gl_src= libs/models/iqm/gl_model_iqm.c iqm_glsl_src= libs/models/iqm/glsl_model_iqm.c iqm_sw_src= libs/models/iqm/sw_model_iqm.c +iqm_vulkan_src= libs/models/iqm/vulkan_model_iqm.c libs_models_iqm_libiqm_gl_la_SOURCES= $(iqm_gl_src) $(iqm_src) @@ -12,4 +17,11 @@ libs_models_iqm_libiqm_glsl_la_SOURCES= $(iqm_glsl_src) $(iqm_src) libs_models_iqm_libiqm_sw_la_SOURCES= $(iqm_sw_src) $(iqm_src) -EXTRA_DIST += $(iqm_gl_src) $(iqm_glsl_src) $(iqm_sw_src) $(iqm_src) +libs_models_iqm_libiqm_vulkan_la_SOURCES= $(iqm_vulkan_src) $(iqm_src) + +EXTRA_DIST += \ + $(iqm_gl_src) \ + $(iqm_glsl_src) \ + $(iqm_sw_src) \ + $(iqm_vulkan_src) \ + $(iqm_src) diff --git a/libs/models/iqm/vulkan_model_iqm.c b/libs/models/iqm/vulkan_model_iqm.c new file mode 100644 index 000000000..e69de29bb diff --git a/libs/models/sprite/Makemodule.am b/libs/models/sprite/Makemodule.am index 76b9fa714..2021eb370 100644 --- a/libs/models/sprite/Makemodule.am +++ b/libs/models/sprite/Makemodule.am @@ -1,10 +1,15 @@ noinst_LTLIBRARIES += @sprite_libs@ -EXTRA_LTLIBRARIES += libs/models/sprite/libsprite_gl.la libs/models/sprite/libsprite_glsl.la libs/models/sprite/libsprite_sw.la +EXTRA_LTLIBRARIES += \ + libs/models/sprite/libsprite_gl.la \ + libs/models/sprite/libsprite_glsl.la \ + libs/models/sprite/libsprite_sw.la \ + libs/models/sprite/libsprite_vulkan.la sprite_src= libs/models/sprite/model_sprite.c sprite_gl_src= libs/models/sprite/gl_model_sprite.c sprite_glsl_src= libs/models/sprite/glsl_model_sprite.c sprite_sw_src= libs/models/sprite/sw_model_sprite.c +sprite_vulkan_src= libs/models/sprite/vulkan_model_sprite.c libs_models_sprite_libsprite_gl_la_SOURCES= $(sprite_gl_src) $(sprite_src) @@ -12,4 +17,11 @@ libs_models_sprite_libsprite_glsl_la_SOURCES= $(sprite_glsl_src) $(sprite_src) libs_models_sprite_libsprite_sw_la_SOURCES= $(sprite_sw_src) $(sprite_src) -EXTRA_DIST += $(sprite_gl_src) $(sprite_glsl_src) $(sprite_sw_src) $(sprite_src) +libs_models_sprite_libsprite_vulkan_la_SOURCES= $(sprite_vulkan_src) $(sprite_src) + +EXTRA_DIST += \ + $(sprite_gl_src) \ + $(sprite_glsl_src) \ + $(sprite_sw_src) \ + $(sprite_vulkan_src) \ + $(sprite_src) diff --git a/libs/models/sprite/vulkan_model_sprite.c b/libs/models/sprite/vulkan_model_sprite.c new file mode 100644 index 000000000..e69de29bb diff --git a/libs/models/vulkan_skin.c b/libs/models/vulkan_skin.c new file mode 100644 index 000000000..e69de29bb diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index bfe8cb5e3..b149d528c 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -210,10 +210,11 @@ libs_video_renderer_vid_render_sw32_la_SOURCES=\ pipeline_src = libs/video/renderer/vulkan/qfpipeline.plist pipeline_gen = libs/video/renderer/vulkan/qfpipeline.plc -vulkan_libs = +video_renderer_vulkan_libs = \ + libs/models/libmodels_vulkan.la libs_video_renderer_vid_render_vulkan_la_LDFLAGS= $(plugin_ldflags) -libs_video_renderer_vid_render_vulkan_la_LIBADD= $(vulkan_libs) -libs_video_renderer_vid_render_vulkan_la_DEPENDENCIES=$(vulkan_libs) +libs_video_renderer_vid_render_vulkan_la_LIBADD= $(video_renderer_vulkan_libs) +libs_video_renderer_vid_render_vulkan_la_DEPENDENCIES=$(video_renderer_vulkan_libs) libs_video_renderer_vid_render_vulkan_la_SOURCES = \ $(video_renderer_common_sources) \ libs/video/renderer/vid_render_vulkan.c \ From ba5e86d9274751748968493952bb406bef9b59a8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 19 Jan 2021 14:54:39 +0900 Subject: [PATCH 252/435] [model] Move Mod_CalcFullbright to its own file This allows it to be shared between renderers. --- libs/models/Makemodule.am | 8 ++++- libs/models/fullbright.c | 49 +++++++++++++++++++++++++++++++ libs/models/gl_model_fullbright.c | 18 ------------ 3 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 libs/models/fullbright.c diff --git a/libs/models/Makemodule.am b/libs/models/Makemodule.am index 24e5a3ca3..982e96a3a 100644 --- a/libs/models/Makemodule.am +++ b/libs/models/Makemodule.am @@ -12,7 +12,13 @@ EXTRA_LTLIBRARIES += \ libs/models/libmodels_sw.la \ libs/models/libmodels_vulkan.la -models_sources = libs/models/clip_hull.c libs/models/model.c libs/models/portal.c libs/models/trace.c libs/models/winding.c +models_sources = \ + libs/models/clip_hull.c \ + libs/models/fullbright.c \ + libs/models/model.c \ + libs/models/portal.c \ + libs/models/trace.c \ + libs/models/winding.c common_libs = \ libs/util/libQFutil.la diff --git a/libs/models/fullbright.c b/libs/models/fullbright.c new file mode 100644 index 000000000..79c32ede9 --- /dev/null +++ b/libs/models/fullbright.c @@ -0,0 +1,49 @@ +/* + fullbright.c + + fullbright skin handling + + Copyright (C) 1996-1997 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +// models are the only shared resource between a client and server running +// on the same machine. + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "r_local.h" + + +VISIBLE int +Mod_CalcFullbright (byte *in, byte *out, int pixels) +{ + byte fb = 0; + + while (pixels--) { + byte pix = *in++; + byte mask = (pix >= 256 - 32) - 1; + fb |= mask + 1; + *out++ = pix | mask; + } + return fb; +} diff --git a/libs/models/gl_model_fullbright.c b/libs/models/gl_model_fullbright.c index 3417b6646..f319581ae 100644 --- a/libs/models/gl_model_fullbright.c +++ b/libs/models/gl_model_fullbright.c @@ -40,24 +40,6 @@ #include "r_local.h" - -VISIBLE int -Mod_CalcFullbright (byte *in, byte *out, int pixels) -{ - int fb = 0; - - while (pixels--) { - if (*in >= 256 - 32) { - fb = 1; - *out++ = *in++; - } else { - *out++ = 255; - in++; - } - } - return fb; -} - int Mod_Fullbright (byte *skin, int width, int height, const char *name) { From 0f81432090c3e6a968de5fef52908b2983e25364 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 19 Jan 2021 18:15:05 +0900 Subject: [PATCH 253/435] [model] Load bsp textures into vulkan The textures for an entire model are loaded into a single memory object with shared between multiple images. --- include/QF/Vulkan/qf_texture.h | 9 +- include/QF/model.h | 3 +- include/mod_internal.h | 6 + include/r_internal.h | 3 +- libs/models/alias/glsl_model_alias.c | 2 +- libs/models/brush/glsl_model_brush.c | 2 +- libs/models/brush/model_brush.c | 11 +- libs/models/brush/vulkan_model_brush.c | 212 ++++++++++++++++++++ libs/models/iqm/gl_model_iqm.c | 2 +- libs/models/iqm/glsl_model_iqm.c | 2 +- libs/models/iqm/sw_model_iqm.c | 2 +- libs/models/model.c | 2 +- libs/models/sprite/glsl_model_sprite.c | 2 +- libs/video/renderer/r_init.c | 1 + libs/video/renderer/vid_render_vulkan.c | 4 +- libs/video/renderer/vulkan/vulkan_texture.c | 7 - 16 files changed, 247 insertions(+), 23 deletions(-) diff --git a/include/QF/Vulkan/qf_texture.h b/include/QF/Vulkan/qf_texture.h index a1750682d..90906873c 100644 --- a/include/QF/Vulkan/qf_texture.h +++ b/include/QF/Vulkan/qf_texture.h @@ -2,9 +2,14 @@ #define __QF_Vulkan_qf_texture_h #include "QF/image.h" +#include "QF/Vulkan/qf_vid.h" -typedef struct qfv_tex_s qfv_tex_t; -struct vulkan_ctx_s; +typedef struct qfv_tex_s { + VkDeviceMemory memory; + size_t offset; + VkImage image; + VkImageView view; +} qfv_tex_t; qfv_tex_t *Vulkan_LoadTex (struct vulkan_ctx_s *ctx, tex_t *tex, int mip); VkImageView Vulkan_TexImageView (qfv_tex_t *tex) __attribute__((pure)); diff --git a/include/QF/model.h b/include/QF/model.h index e8cb22367..1dbfe1b6f 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -422,7 +422,8 @@ typedef struct model_s { // additional model data cache_user_t cache; - void (*clear) (struct model_s *m); + void (*clear) (struct model_s *m, void *data); + void *data; } model_t; // ============================================================================ diff --git a/include/mod_internal.h b/include/mod_internal.h index 125da1065..632411785 100644 --- a/include/mod_internal.h +++ b/include/mod_internal.h @@ -6,6 +6,8 @@ #include "QF/skin.h" #include "QF/plugin/vid_render.h" +struct vulkan_ctx_s; + extern vid_model_funcs_t *m_funcs; void gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, @@ -41,6 +43,10 @@ void glsl_Mod_ProcessTexture(texture_t *tx); void sw_Mod_LoadLighting (bsp_t *bsp); +void Vulkan_Mod_LoadLighting (bsp_t *bsp, struct vulkan_ctx_s *ctx); +void Vulkan_Mod_SubdivideSurface (msurface_t *fa, struct vulkan_ctx_s *ctx); +void Vulkan_Mod_ProcessTexture(texture_t *tx, struct vulkan_ctx_s *ctx); + void gl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum); void glsl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum); void sw_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum); diff --git a/include/r_internal.h b/include/r_internal.h index 37edbbdd2..01c9af001 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -29,11 +29,12 @@ typedef struct glsltex_s { typedef struct vulktex_s { texture_t *texture; - struct qfv_tex_s *tex; instsurf_t *tex_chain; // for gl_texsort drawing instsurf_t **tex_chain_tail; struct elechain_s *elechain; struct elechain_s **elechain_tail; + struct qfv_tex_s *tex; + struct qfv_tex_s *glow; } vulktex_t; extern viddef_t vid; // global video state diff --git a/libs/models/alias/glsl_model_alias.c b/libs/models/alias/glsl_model_alias.c index 5e80ccbb8..215c9d400 100644 --- a/libs/models/alias/glsl_model_alias.c +++ b/libs/models/alias/glsl_model_alias.c @@ -55,7 +55,7 @@ static vec3_t vertex_normals[NUMVERTEXNORMALS] = { }; static void -glsl_alias_clear (model_t *m) +glsl_alias_clear (model_t *m, void *data) { int i, j; aliashdr_t *hdr; diff --git a/libs/models/brush/glsl_model_brush.c b/libs/models/brush/glsl_model_brush.c index e839f5317..23bb683ad 100644 --- a/libs/models/brush/glsl_model_brush.c +++ b/libs/models/brush/glsl_model_brush.c @@ -62,7 +62,7 @@ static glsltex_t glsl_notexture = { }; static void -glsl_brush_clear (model_t *m) +glsl_brush_clear (model_t *m, void *data) { int i; diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index f3ab08689..24af26c95 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -982,10 +982,13 @@ Mod_LoadBrushModel (model_t *mod, void *buffer) char name[12]; snprintf (name, sizeof (name), "*%i", i + 1); - loadmodel = Mod_FindName (name); - *loadmodel = *mod; - strcpy (loadmodel->name, name); - mod = loadmodel; + model_t *m = Mod_FindName (name); + *m = *mod; + strcpy (m->name, name); + mod = m; + // make sure clear is called only for the main model + m->clear = 0; + m->data = 0; } } } diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index e69de29bb..5cc5f2984 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -0,0 +1,212 @@ +/* + vulkan_model_brush.c + + Vulkan support routines for model loading and caching + + Copyright (C) 1996-1997 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +// models are the only shared resource between a client and server running +// on the same machine. + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/image.h" +#include "QF/qendian.h" +#include "QF/quakefs.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/Vulkan/qf_bsp.h" +#include "QF/Vulkan/qf_model.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" + +#include "compat.h" +#include "mod_internal.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +static vulktex_t vulkan_notexture = { }; + +static void vulkan_brush_clear (model_t *model, void *data) +{ + modelctx_t *mctx = data; + vulkan_ctx_t *ctx = mctx->ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + for (int i = 0; i < model->numtextures; i++) { + texture_t *tx = model->textures[i]; + if (!tx) { + continue; + } + vulktex_t *tex = tx->render; + dfunc->vkDestroyImage (device->dev, tex->tex->image, 0); + if (tex->glow) { + dfunc->vkDestroyImage (device->dev, tex->glow->image, 0); + } + } + dfunc->vkFreeMemory (device->dev, mctx->texture_memory, 0); +} + +static size_t +get_image_size (VkImage image, qfv_device_t *device) +{ + qfv_devfuncs_t *dfunc = device->funcs; + size_t size; + size_t align; + + VkMemoryRequirements requirements; + dfunc->vkGetImageMemoryRequirements (device->dev, image, &requirements); + size = requirements.size; + align = requirements.alignment - 1; + size = (size + align) & ~(align); + return size; +} + +static void +load_textures (model_t *model, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + modelctx_t *mctx = model->data; + VkImage image = 0; + + size_t memsize = 0; + for (int i = 0; i < model->numtextures; i++) { + texture_t *tx = model->textures[i]; + if (!tx) { + continue; + } + vulktex_t *tex = tx->render; + tex->tex->offset = memsize; + memsize += get_image_size (tex->tex->image, device); + // just so we have one in the end + image = tex->tex->image; + if (tex->glow) { + tex->glow->offset = memsize; + memsize += get_image_size (tex->glow->image, device); + } + } + VkDeviceMemory mem; + mem = QFV_AllocImageMemory (device, image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + memsize, 0); + mctx->texture_memory = mem; + + for (int i = 0; i < model->numtextures; i++) { + texture_t *tx = model->textures[i]; + if (!tx) { + continue; + } + vulktex_t *tex = tx->render; + + dfunc->vkBindImageMemory (device->dev, tex->tex->image, mem, + tex->tex->offset); + if (tex->glow) { + dfunc->vkBindImageMemory (device->dev, tex->glow->image, mem, + tex->glow->offset); + } + } +} + +void +Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + if (!tx) { + modelctx_t *mctx = Hunk_AllocName (sizeof (modelctx_t), + loadmodel->name); + mctx->ctx = ctx; + loadmodel->clear = vulkan_brush_clear; + loadmodel->data = mctx; + + r_notexture_mip->render = &vulkan_notexture; + load_textures (loadmodel, ctx); + return; + } + + vulktex_t *tex = tx->render; + tex->tex = (qfv_tex_t *) (tx + 1); + VkExtent3D extent = { tx->width, tx->height, 1 }; + + int layers = 1; + if (strncmp (tx->name, "sky", 3) == 0) { + layers = 2; + } + + tex->tex->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + extent, 4, layers, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT); + if (layers > 1) { + // skys are unlit, so no fullbrights + return; + } + + const char *name = va ("fb_%s", tx->name); + int size = (tx->width * tx->height * 85) / 64; + int fullbright_mark = Hunk_LowMark (); + byte *pixels = Hunk_AllocName (size, name); + + if (!Mod_CalcFullbright ((byte *) (tx + 1), pixels, size)) { + Hunk_FreeToLowMark (fullbright_mark); + return; + } + tex->glow = tex->tex + 1; + tex->glow->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + extent, 4, 1, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT); + // store the pointer to the fullbright data: memory will never be set to + // actual device memory because all of the textures will be loaded in one + // big buffer + tex->glow->memory = (VkDeviceMemory) pixels; +} + +void +Vulkan_Mod_LoadLighting (bsp_t *bsp, vulkan_ctx_t *ctx) +{ + mod_lightmap_bytes = 1; + if (!bsp->lightdatasize) { + loadmodel->lightdata = NULL; + return; + } + loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize, loadname); + memcpy (loadmodel->lightdata, bsp->lightdata, bsp->lightdatasize); +} diff --git a/libs/models/iqm/gl_model_iqm.c b/libs/models/iqm/gl_model_iqm.c index f57b18637..93a1e9992 100644 --- a/libs/models/iqm/gl_model_iqm.c +++ b/libs/models/iqm/gl_model_iqm.c @@ -56,7 +56,7 @@ static byte null_texture[] = { }; static void -gl_iqm_clear (model_t *mod) +gl_iqm_clear (model_t *mod, void *data) { iqm_t *iqm = (iqm_t *) mod->aliashdr; gliqm_t *gl = (gliqm_t *) iqm->extra_data; diff --git a/libs/models/iqm/glsl_model_iqm.c b/libs/models/iqm/glsl_model_iqm.c index 6a79eede7..5b37e0fd2 100644 --- a/libs/models/iqm/glsl_model_iqm.c +++ b/libs/models/iqm/glsl_model_iqm.c @@ -68,7 +68,7 @@ static byte null_normmap[] = { }; static void -glsl_iqm_clear (model_t *mod) +glsl_iqm_clear (model_t *mod, void *data) { iqm_t *iqm = (iqm_t *) mod->aliashdr; glsliqm_t *glsl = (glsliqm_t *) iqm->extra_data; diff --git a/libs/models/iqm/sw_model_iqm.c b/libs/models/iqm/sw_model_iqm.c index 4bc8fedb9..b15422090 100644 --- a/libs/models/iqm/sw_model_iqm.c +++ b/libs/models/iqm/sw_model_iqm.c @@ -58,7 +58,7 @@ static tex_t null_texture = { }; static void -sw_iqm_clear (model_t *mod) +sw_iqm_clear (model_t *mod, void *data) { iqm_t *iqm = (iqm_t *) mod->aliashdr; swiqm_t *sw = (swiqm_t *) iqm->extra_data; diff --git a/libs/models/model.c b/libs/models/model.c index d8ce5df03..198a69f7c 100644 --- a/libs/models/model.c +++ b/libs/models/model.c @@ -123,7 +123,7 @@ Mod_ClearAll (void) for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) { if (!(*mod)->needload && (*mod)->clear) { - (*mod)->clear (*mod); + (*mod)->clear (*mod, (*mod)->data); } else { if ((*mod)->type != mod_alias) (*mod)->needload = true; diff --git a/libs/models/sprite/glsl_model_sprite.c b/libs/models/sprite/glsl_model_sprite.c index 66e1318e2..bbef94e02 100644 --- a/libs/models/sprite/glsl_model_sprite.c +++ b/libs/models/sprite/glsl_model_sprite.c @@ -47,7 +47,7 @@ #include "mod_internal.h" static void -glsl_sprite_clear (model_t *m) +glsl_sprite_clear (model_t *m, void *data) { int i, j; msprite_t *sprite = (msprite_t *) m->cache.data; diff --git a/libs/video/renderer/r_init.c b/libs/video/renderer/r_init.c index 733004a21..94385e1c2 100644 --- a/libs/video/renderer/r_init.c +++ b/libs/video/renderer/r_init.c @@ -68,6 +68,7 @@ static U void (*const r_scrapdelete)(rscrap_t *) = R_ScrapDelete; static void R_shutdown (void *data) { + Mod_ClearAll (); if (vidrendmodule->functions->general->p_Shutdown) { vidrendmodule->functions->general->p_Shutdown (); } diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 717809012..4d2744089 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -388,6 +388,7 @@ vulkan_r_particles_style_f (struct cvar_s *var) static void vulkan_Mod_LoadLighting (bsp_t *bsp) { + Vulkan_Mod_LoadLighting (bsp, vulkan_ctx); } static void @@ -398,6 +399,7 @@ vulkan_Mod_SubdivideSurface (msurface_t *fa) static void vulkan_Mod_ProcessTexture (texture_t *tx) { + Vulkan_Mod_ProcessTexture (tx, vulkan_ctx); } static void @@ -449,7 +451,7 @@ vulkan_Skin_InitTranslations (void) } static vid_model_funcs_t model_funcs = { - sizeof (vulktex_t), + sizeof (vulktex_t) + 2 * sizeof (struct qfv_tex_s *), vulkan_Mod_LoadLighting, vulkan_Mod_SubdivideSurface, vulkan_Mod_ProcessTexture, diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index 0b2c2e102..c9dc0d60f 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -62,13 +62,6 @@ #include "r_scrap.h" #include "vid_vulkan.h" -struct qfv_tex_s { // qfv_tex_t - VkDeviceMemory memory; - size_t offset; - VkImage image; - VkImageView view; -}; - static int ilog2 (unsigned x) { From 82889a2c52d77117f8b5e0d063afd43b9da5c4d0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 19 Jan 2021 18:25:30 +0900 Subject: [PATCH 254/435] [model] Create and destroy the bsp image views --- libs/models/brush/vulkan_model_brush.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index 5cc5f2984..fe5fbfce5 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -72,8 +72,10 @@ static void vulkan_brush_clear (model_t *model, void *data) } vulktex_t *tex = tx->render; dfunc->vkDestroyImage (device->dev, tex->tex->image, 0); + dfunc->vkDestroyImageView (device->dev, tex->tex->view, 0); if (tex->glow) { dfunc->vkDestroyImage (device->dev, tex->glow->image, 0); + dfunc->vkDestroyImageView (device->dev, tex->glow->view, 0); } } dfunc->vkFreeMemory (device->dev, mctx->texture_memory, 0); @@ -133,9 +135,22 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) dfunc->vkBindImageMemory (device->dev, tex->tex->image, mem, tex->tex->offset); + VkImageViewType type = VK_IMAGE_VIEW_TYPE_2D; + if (strncmp (tx->name, "sky", 3) == 0) { + type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + } + tex->tex->view = QFV_CreateImageView (device, tex->tex->image, + type, VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); if (tex->glow) { dfunc->vkBindImageMemory (device->dev, tex->glow->image, mem, tex->glow->offset); + // skys are unlit so never have a glow texture thus glow + // textures are always simple 2D + tex->glow->view = QFV_CreateImageView (device, tex->tex->image, + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); } } } From 2de1c02f61eb69701efac1e61e5410ac6a1a5d51 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 20 Jan 2021 01:18:47 +0900 Subject: [PATCH 255/435] [image] Add support for float rgba for vulkan --- include/QF/image.h | 1 + libs/models/iqm/sw_model_iqm.c | 9 +++++++++ libs/video/renderer/vulkan/texture.c | 4 ++++ libs/video/renderer/vulkan/vulkan_texture.c | 4 ++++ 4 files changed, 18 insertions(+) diff --git a/include/QF/image.h b/include/QF/image.h index cd649c42e..62d57dd35 100644 --- a/include/QF/image.h +++ b/include/QF/image.h @@ -38,6 +38,7 @@ typedef enum QFFormat { tex_la = 2, tex_rgb = 3, tex_rgba = 4, + tex_frgba = 5, } QFFormat; // could not use texture_t as that is used for models. diff --git a/libs/models/iqm/sw_model_iqm.c b/libs/models/iqm/sw_model_iqm.c index b15422090..582109a73 100644 --- a/libs/models/iqm/sw_model_iqm.c +++ b/libs/models/iqm/sw_model_iqm.c @@ -130,6 +130,15 @@ convert_tex (tex_t *tex) for (i = 0; i < pixels; i++) new->data[i] = convert_color (tex->data + i * bpp); break; + case tex_frgba: + for (i = 0; i < pixels; i++) { + byte col[3]; + col[0] = ((float *)tex->data)[i * 4 + 0] * 255; + col[1] = ((float *)tex->data)[i * 4 + 1] * 255; + col[2] = ((float *)tex->data)[i * 4 + 2] * 255; + new->data[i] = convert_color (col); + } + break; } return new; } diff --git a/libs/video/renderer/vulkan/texture.c b/libs/video/renderer/vulkan/texture.c index b4eacf0e6..d926632a7 100644 --- a/libs/video/renderer/vulkan/texture.c +++ b/libs/video/renderer/vulkan/texture.c @@ -100,6 +100,10 @@ QFV_CreateScrap (qfv_device_t *device, int size, QFFormat format) bpp = 4; fmt = VK_FORMAT_R8G8B8A8_UNORM; break; + case tex_frgba: + bpp = 16; + fmt = VK_FORMAT_R32G32B32A32_SFLOAT; + break; } scrap_t *scrap = malloc (sizeof (scrap_t)); diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index c9dc0d60f..05d602d63 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -118,6 +118,10 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) format = VK_FORMAT_R8G8B8A8_UNORM; bpp = 4; break; + case tex_frgba: + format = VK_FORMAT_R32G32B32A32_SFLOAT; + bpp = 16; + break; } if (format == VK_FORMAT_UNDEFINED) { return 0; From df82cb88eec5f6b8573515ea09cd2110591da7d7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 20 Jan 2021 01:23:24 +0900 Subject: [PATCH 256/435] [vulkan] Make some little cleanups --- include/QF/Vulkan/qf_particles.h | 5 +++-- libs/video/renderer/glsl/glsl_lightmap.c | 3 --- libs/video/renderer/vulkan/vulkan_draw.c | 4 ++-- libs/video/renderer/vulkan/vulkan_particles.c | 11 ++++++++--- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/include/QF/Vulkan/qf_particles.h b/include/QF/Vulkan/qf_particles.h index 3ac71ac71..c256a9610 100644 --- a/include/QF/Vulkan/qf_particles.h +++ b/include/QF/Vulkan/qf_particles.h @@ -6,10 +6,11 @@ struct cvar_s; struct vulkan_ctx_s;; -void Vulkan_R_ClearParticles (struct vulkan_ctx_s *ctx); -void Vulkan_R_InitParticles (struct vulkan_ctx_s *ctx); +void Vulkan_ClearParticles (struct vulkan_ctx_s *ctx); +void Vulkan_InitParticles (struct vulkan_ctx_s *ctx); void Vulkan_r_easter_eggs_f (struct cvar_s *var, struct vulkan_ctx_s *ctx); void Vulkan_r_particles_style_f (struct cvar_s *var, struct vulkan_ctx_s *ctx); void Vulkan_Particles_Init (struct vulkan_ctx_s *ctx); +void Vulkan_DrawParticles (struct vulkan_ctx_s *ctx); #endif//__QF_Vulkan_qf_particles_h diff --git a/libs/video/renderer/glsl/glsl_lightmap.c b/libs/video/renderer/glsl/glsl_lightmap.c index 11ae46ca8..b6f37142b 100644 --- a/libs/video/renderer/glsl/glsl_lightmap.c +++ b/libs/video/renderer/glsl/glsl_lightmap.c @@ -58,7 +58,6 @@ #define BLOCK_SIZE (BLOCK_WIDTH * BLOCK_HEIGHT) static scrap_t *light_scrap; -static byte *light_data; static unsigned *blocklights; static int bl_extents[2]; @@ -201,10 +200,8 @@ glsl_R_BuildLightmaps (model_t **models, int num_models) //FIXME RGB support if (!light_scrap) { light_scrap = GLSL_CreateScrap (2048, GL_LUMINANCE, 1); - light_data = malloc (BLOCK_SIZE * MAX_LIGHTMAPS); } else { GLSL_ScrapClear (light_scrap); - memset (light_data, 0, BLOCK_SIZE * MAX_LIGHTMAPS); } glsl_R_BuildLightMap = R_BuildLightMap_1; diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 7aadd6692..5cb213b16 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -369,7 +369,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) create_quad_buffers (ctx); dctx->scrap = QFV_CreateScrap (device, 2048, tex_rgba); dctx->stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024, 4, - ctx->cmdpool); + ctx->cmdpool); dctx->sampler = QFV_GetSampler (ctx, "quakepic"); qpic_t *charspic = Draw_Font8x8Pic (); @@ -385,7 +385,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) dctx->layout = QFV_GetPipelineLayout (ctx, "twod"); - __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (ctx->framebuffers.size, alloca); + __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (frames, alloca); for (size_t i = 0; i < layouts->size; i++) { layouts->a[i] = QFV_GetDescriptorSetLayout (ctx, "twod"); } diff --git a/libs/video/renderer/vulkan/vulkan_particles.c b/libs/video/renderer/vulkan/vulkan_particles.c index 282bfaf8a..abb24924b 100644 --- a/libs/video/renderer/vulkan/vulkan_particles.c +++ b/libs/video/renderer/vulkan/vulkan_particles.c @@ -48,12 +48,12 @@ #include "vid_vulkan.h" void -Vulkan_R_ClearParticles (struct vulkan_ctx_s *ctx) +Vulkan_ClearParticles (struct vulkan_ctx_s *ctx) { } void -Vulkan_R_InitParticles (struct vulkan_ctx_s *ctx) +Vulkan_InitParticles (struct vulkan_ctx_s *ctx) { } @@ -241,7 +241,12 @@ Vulkan_r_easter_eggs_f (cvar_t *var, struct vulkan_ctx_s *ctx) void Vulkan_r_particles_style_f (cvar_t *var, struct vulkan_ctx_s *ctx) { - Vulkan_r_particles_style_f (var, ctx); + Vulkan_r_easter_eggs_f (var, ctx); +} + +void +Vulkan_DrawParticles (struct vulkan_ctx_s *ctx) +{ } void From 0622a24380d96359c71356cff09a30e4a89ee651 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 20 Jan 2021 01:24:32 +0900 Subject: [PATCH 257/435] [util] Support size_t constants Much like 1u and 1l, 1z is for size_t. --- libs/util/cexpr-lex.l | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libs/util/cexpr-lex.l b/libs/util/cexpr-lex.l index 9c9377beb..d34cd250a 100644 --- a/libs/util/cexpr-lex.l +++ b/libs/util/cexpr-lex.l @@ -71,6 +71,7 @@ FILE *cexpr_yyget_in (yyscan_t yyscanner) __attribute__((pure)); static exprval_t *parse_int (const char *str, exprctx_t *context); static exprval_t *parse_uint (const char *str, exprctx_t *context); +static exprval_t *parse_size_t (const char *str, exprctx_t *context); static exprval_t *parse_float (const char *str, exprctx_t *context); static exprval_t *parse_double (const char *str, exprctx_t *context); static exprsym_t *parse_name (const char *str, exprctx_t *context); @@ -127,6 +128,11 @@ STRING \"(\\.|[^"\\])*\" return VALUE; } +{INT}+[zZ] { + yylval->value = parse_size_t (yytext, context); + return VALUE; + } + {FLOAT} { yylval->value = parse_double (yytext, context); return VALUE; @@ -239,6 +245,13 @@ static exprval_t *parse_uint (const char *str, exprctx_t *context) return val; } +static exprval_t *parse_size_t (const char *str, exprctx_t *context) +{ + exprval_t *val = cexpr_value (&cexpr_size_t, context); + *(unsigned *) val->value = strtoumax (str, 0, 0); + return val; +} + static exprval_t *parse_float (const char *str, exprctx_t *context) { exprval_t *val = cexpr_value (&cexpr_float, context); From d33f5b8d0d6e693d17acce115b55c2c42882e4bd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 20 Jan 2021 01:25:54 +0900 Subject: [PATCH 258/435] [vulkan] Make a lot of progress for brush models Light maps are maybe updating, but as nothing is actually rendered yet, it's hard to tell. --- include/QF/Vulkan/qf_bsp.h | 134 ++ include/QF/Vulkan/qf_lightmap.h | 48 + include/QF/Vulkan/qf_main.h | 37 + include/QF/Vulkan/qf_model.h | 44 + include/QF/Vulkan/texture.h | 4 + include/r_local.h | 2 + include/vid_vulkan.h | 1 + libs/models/brush/vulkan_model_brush.c | 52 +- libs/video/renderer/Makemodule.am | 3 + libs/video/renderer/vid_render_vulkan.c | 28 +- libs/video/renderer/vulkan/qfpipeline.plist | 160 +++ libs/video/renderer/vulkan/quakebsp.frag | 9 +- libs/video/renderer/vulkan/quakebsp.vert | 5 +- libs/video/renderer/vulkan/texture.c | 6 + libs/video/renderer/vulkan/vulkan_bsp.c | 1286 ++++++++++++++++++ libs/video/renderer/vulkan/vulkan_draw.c | 3 +- libs/video/renderer/vulkan/vulkan_lightmap.c | 279 ++++ libs/video/renderer/vulkan/vulkan_main.c | 250 ++++ 18 files changed, 2329 insertions(+), 22 deletions(-) create mode 100644 include/QF/Vulkan/qf_bsp.h create mode 100644 include/QF/Vulkan/qf_lightmap.h create mode 100644 include/QF/Vulkan/qf_main.h create mode 100644 include/QF/Vulkan/qf_model.h create mode 100644 libs/video/renderer/vulkan/vulkan_bsp.c create mode 100644 libs/video/renderer/vulkan/vulkan_lightmap.c create mode 100644 libs/video/renderer/vulkan/vulkan_main.c diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h new file mode 100644 index 000000000..dec2fe085 --- /dev/null +++ b/include/QF/Vulkan/qf_bsp.h @@ -0,0 +1,134 @@ +/* + qf_bsp.h + + Vulkan specific brush model stuff + + Copyright (C) 2012 Bill Currie + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2012/1/7 + Date: 2021/1/18 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_qf_bsp_h +#define __QF_Vulkan_qf_bsp_h + +#include "QF/darray.h" +#include "QF/model.h" +#include "QF/Vulkan/qf_vid.h" + +typedef struct bspvert_s { + quat_t vertex; + quat_t tlst; +} bspvert_t; + +typedef struct elements_s { + struct elements_s *_next; + struct elements_s *next; + byte *base; + struct dstring_s *list; +} elements_t; + +typedef struct elechain_s { + struct elechain_s *_next; + struct elechain_s *next; + int index; + elements_t *elements; + vec_t *transform; + float *color; +} elechain_t; + +typedef struct bspframe_s { + uint32_t *indeces; + VkCommandBuffer bsp_cmd; + VkCommandBuffer turb_cmd; + VkCommandBuffer sky_cmd; + VkDescriptorSet descriptors; +} bspframe_t; + +typedef struct bspframeset_s + DARRAY_TYPE (bspframe_t) bspframeset_t; + +typedef struct texchainset_s + DARRAY_TYPE (struct vulktex_s *) texchainset_t; + +typedef struct bspctx_s { + instsurf_t *waterchain; + instsurf_t **waterchain_tail; + instsurf_t *sky_chain; + instsurf_t **sky_chain_tail; + + texchainset_t texture_chains; + + // for world and non-instance models + instsurf_t *static_instsurfs; + instsurf_t **static_instsurfs_tail; + instsurf_t *free_static_instsurfs; + + // for instance models + elechain_t *elechains; + elechain_t **elechains_tail; + elechain_t *free_elechains; + elements_t *elementss; + elements_t **elementss_tail; + elements_t *free_elementss; + instsurf_t *instsurfs; + instsurf_t **instsurfs_tail; + instsurf_t *free_instsurfs; + + struct qfv_tex_s *skybox_tex; + quat_t sky_rotation[2]; + quat_t sky_velocity; + quat_t sky_fix; + double sky_time; + + quat_t default_color; + quat_t last_color; + + struct scrap_s *light_scrap; + struct qfv_stagebuf_s *light_stage; + + VkDeviceMemory texture_memory; + VkPipeline main; + VkPipelineLayout layout; + size_t vertex_buffer_size; + size_t index_buffer_size; + VkBuffer vertex_buffer; + VkDeviceMemory vertex_memory; + VkBuffer index_buffer; + VkDeviceMemory index_memory; + bspframeset_t frames; +} bspctx_t; + +struct vulkan_ctx_s; +void Vulkan_ClearElements (struct vulkan_ctx_s *ctx); +void Vulkan_DrawWorld (struct vulkan_ctx_s *ctx); +void Vulkan_DrawSky (struct vulkan_ctx_s *ctx); +void Vulkan_RegisterTextures (model_t **models, int num_models, + struct vulkan_ctx_s *ctx); +void Vulkan_BuildDisplayLists (model_t **models, int num_models, + struct vulkan_ctx_s *ctx); +void Vulkan_Bsp_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx); +void Vulkan_DrawWaterSurfaces (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_bsp_h diff --git a/include/QF/Vulkan/qf_lightmap.h b/include/QF/Vulkan/qf_lightmap.h new file mode 100644 index 000000000..649a5b139 --- /dev/null +++ b/include/QF/Vulkan/qf_lightmap.h @@ -0,0 +1,48 @@ +/* + qf_lightmap.h + + Vulkan lightmap stuff from the renderer. + + Copyright (C) 2021 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_Vulkan_qf_lightmap_h +#define __QF_Vulkan_qf_lightmap_h + +#define MAX_LIGHTMAPS 1024 +#define BLOCK_WIDTH 64 +#define BLOCK_HEIGHT 64 + +#include "QF/Vulkan/qf_vid.h" + +struct vulkan_ctx_s; +struct model_s; +struct msurface_s; + +void Vulkan_lightmap_init (struct vulkan_ctx_s *ctx); +void Vulkan_BuildLightmaps (struct model_s **models, int num_models, struct vulkan_ctx_s *ctx); +void Vulkan_CalcLightmaps (struct vulkan_ctx_s *ctx); +void Vulkan_BuildLightMap (struct msurface_s *surf, struct vulkan_ctx_s *ctx); +VkImageView Vulkan_LightmapImageView (struct vulkan_ctx_s *ctx) __attribute__((pure)); +void Vulkan_FlushLightmaps (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_lightmap_h diff --git a/include/QF/Vulkan/qf_main.h b/include/QF/Vulkan/qf_main.h new file mode 100644 index 000000000..4b487da5e --- /dev/null +++ b/include/QF/Vulkan/qf_main.h @@ -0,0 +1,37 @@ +/* + qf_main.h + + Vulkan main stuff from the renderer. + + Copyright (C) 2021 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_Vulkan_qf_main_h +#define __QF_Vulkan_qf_main_h + +struct vulkan_ctx_s; + +void Vulkan_NewMap (model_t *worldmodel, struct model_s **models, + int num_models, struct vulkan_ctx_s *ctx); +void Vulkan_RenderView (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_main_h diff --git a/include/QF/Vulkan/qf_model.h b/include/QF/Vulkan/qf_model.h new file mode 100644 index 000000000..3a42e131d --- /dev/null +++ b/include/QF/Vulkan/qf_model.h @@ -0,0 +1,44 @@ +/* + qf_model.h + + Vulkan specific model stuff + + Copyright (C) 2012 Bill Currie + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2012/1/7 + Date: 2021/1/19 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_qf_model_h +#define __QF_Vulkan_qf_model_h + +#include "QF/darray.h" +#include "QF/model.h" +#include "QF/Vulkan/qf_vid.h" + +typedef struct modelctx_s { + struct vulkan_ctx_s *ctx; + VkDeviceMemory texture_memory; +} modelctx_t; + +#endif//__QF_Vulkan_qf_model_h diff --git a/include/QF/Vulkan/texture.h b/include/QF/Vulkan/texture.h index 39f5b07f2..35aaf5bb5 100644 --- a/include/QF/Vulkan/texture.h +++ b/include/QF/Vulkan/texture.h @@ -5,8 +5,12 @@ typedef struct scrap_s scrap_t; +struct qfv_stagebuf_s; +struct qfv_device_s; + scrap_t *QFV_CreateScrap (struct qfv_device_s *device, int size, QFFormat format); +size_t QFV_ScrapSize (scrap_t *scrap); void QFV_ScrapClear (scrap_t *scrap); void QFV_DestroyScrap (scrap_t *scrap); VkImageView QFV_ScrapImageView (scrap_t *scrap) __attribute__((pure)); diff --git a/include/r_local.h b/include/r_local.h index ebf1a9dd6..4a3645ded 100644 --- a/include/r_local.h +++ b/include/r_local.h @@ -180,6 +180,7 @@ void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist); void R_StepActiveU (edge_t *pedge); void R_RemoveEdges (edge_t *pedge); void R_AddTexture (texture_t *tex); +struct vulkan_ctx_s; void R_ClearTextures (void); void R_InitSurfaceChains (model_t *model); @@ -313,6 +314,7 @@ void R_MarkLights (const vec3_t lightorigin, struct dlight_s *light, int bit, model_t *model); void R_LoadSkys (const char *); +//void Vulkan_R_LoadSkys (const char *, struct vulkan_ctx_s *ctx); void R_LowFPPrecision (void); void R_HighFPPrecision (void); diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 90d4908f2..92208425e 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -63,6 +63,7 @@ typedef struct vulkan_ctx_s { struct hashtab_s *descriptorPools; struct hashtab_s *samplers; + struct bspctx_s *bsp_context; struct drawctx_s *draw_context; VkCommandPool cmdpool; diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index fe5fbfce5..52826d280 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -217,11 +217,57 @@ Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx) void Vulkan_Mod_LoadLighting (bsp_t *bsp, vulkan_ctx_t *ctx) { - mod_lightmap_bytes = 1; + mod_lightmap_bytes = 3; if (!bsp->lightdatasize) { loadmodel->lightdata = NULL; return; } - loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize, loadname); - memcpy (loadmodel->lightdata, bsp->lightdata, bsp->lightdatasize); + + byte d; + byte *in, *out, *data; + size_t i; + int ver; + QFile *lit_file; + + loadmodel->lightdata = 0; + if (mod_lightmap_bytes > 1) { + // LordHavoc: check for a .lit file to load + dstring_t *litfilename = dstring_new (); + dstring_copystr (litfilename, loadmodel->name); + QFS_StripExtension (litfilename->str, litfilename->str); + dstring_appendstr (litfilename, ".lit"); + lit_file = QFS_VOpenFile (litfilename->str, 0, loadmodel->vpath); + data = (byte *) QFS_LoadHunkFile (lit_file); + if (data) { + if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' + && data[3] == 'T') { + ver = LittleLong (((int32_t *) data)[1]); + if (ver == 1) { + Sys_MaskPrintf (SYS_DEV, "%s loaded", litfilename->str); + loadmodel->lightdata = data + 8; + } else { + Sys_MaskPrintf (SYS_DEV, + "Unknown .lit file version (%d)\n", ver); + } + } else { + Sys_MaskPrintf (SYS_DEV, "Corrupt .lit file (old version?)\n"); + } + } + dstring_delete (litfilename); + } + if (loadmodel->lightdata || !bsp->lightdatasize) { + return; + } + // LordHavoc: oh well, expand the white lighting data + loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize * 3, + loadmodel->name); + in = bsp->lightdata; + out = loadmodel->lightdata; + + for (i = 0; i < bsp->lightdatasize ; i++) { + d = *in++; + *out++ = d; + *out++ = d; + *out++ = d; + } } diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index b149d528c..a200747ff 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -236,7 +236,10 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/util.c \ libs/video/renderer/vulkan/util.h \ libs/video/renderer/vulkan/vkparse.c \ + libs/video/renderer/vulkan/vulkan_bsp.c \ libs/video/renderer/vulkan/vulkan_draw.c \ + libs/video/renderer/vulkan/vulkan_lightmap.c \ + libs/video/renderer/vulkan/vulkan_main.c \ libs/video/renderer/vulkan/vulkan_matrices.c \ libs/video/renderer/vulkan/vulkan_particles.c \ libs/video/renderer/vulkan/vulkan_texture.c \ diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 4d2744089..e6f993b38 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -39,7 +39,10 @@ #include "QF/plugin/general.h" #include "QF/plugin/vid_render.h" +#include "QF/Vulkan/qf_bsp.h" #include "QF/Vulkan/qf_draw.h" +#include "QF/Vulkan/qf_lightmap.h" +#include "QF/Vulkan/qf_main.h" #include "QF/Vulkan/qf_particles.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/command.h" @@ -92,6 +95,7 @@ vulkan_R_Init (void) // FIXME this should be staged so screen updates can begin while pipelines // are being built vulkan_ctx->pipeline = Vulkan_CreatePipeline (vulkan_ctx, "pipeline"); + Vulkan_Bsp_Init (vulkan_ctx); Vulkan_Draw_Init (vulkan_ctx); Vulkan_Particles_Init (vulkan_ctx); @@ -116,12 +120,6 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) VkDevice dev = device->dev; qfv_queue_t *queue = &vulkan_ctx->device->queue; - scr_3dfunc (); - while (*scr_funcs) { - (*scr_funcs) (); - scr_funcs++; - } - __auto_type framebuffer = &vulkan_ctx->framebuffers.a[vulkan_ctx->curFrame]; @@ -145,6 +143,12 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) attachments, sc->extent, 1); + scr_3dfunc (); + while (*scr_funcs) { + (*scr_funcs) (); + scr_funcs++; + } + Vulkan_FlushText (vulkan_ctx); VkCommandBufferBeginInfo beginInfo @@ -168,6 +172,8 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) dfunc->vkCmdExecuteCommands (framebuffer->cmdBuffer, framebuffer->subCommand->size, framebuffer->subCommand->a); + // reset for next time around + framebuffer->subCommand->size = 0; dfunc->vkCmdEndRenderPass (framebuffer->cmdBuffer); dfunc->vkEndCommandBuffer (framebuffer->cmdBuffer); @@ -208,6 +214,9 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) static void vulkan_R_ClearState (void) { + R_ClearEfrags (); + R_ClearDlights (); + Vulkan_ClearParticles (vulkan_ctx); } static void @@ -218,6 +227,7 @@ vulkan_R_LoadSkys (const char *skyname) static void vulkan_R_NewMap (model_t *worldmodel, model_t **models, int num_models) { + Vulkan_NewMap (worldmodel, models, num_models, vulkan_ctx); } static void @@ -228,6 +238,7 @@ vulkan_R_LineGraph (int x, int y, int *h_vals, int count) static void vulkan_R_RenderView (void) { + Vulkan_RenderView (vulkan_ctx); } static void @@ -359,13 +370,13 @@ vulkan_R_ViewChanged (float aspect) static void vulkan_R_ClearParticles (void) { - Vulkan_R_ClearParticles (vulkan_ctx); + Vulkan_ClearParticles (vulkan_ctx); } static void vulkan_R_InitParticles (void) { - Vulkan_R_InitParticles (vulkan_ctx); + Vulkan_InitParticles (vulkan_ctx); } static void @@ -593,6 +604,7 @@ vulkan_vid_render_shutdown (void) df->vkDestroyFence (dev, vulkan_ctx->fence, 0); df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0); Vulkan_Draw_Shutdown (vulkan_ctx); + Vulkan_Bsp_Shutdown (vulkan_ctx); Vulkan_Shutdown_Common (vulkan_ctx); } diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 4bc6017e9..822e187a5 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -9,6 +9,8 @@ pushcolor = $builtin/pushcolor.frag; twodv = $builtin/twod.vert; twodf = $builtin/twod.frag; + quakebspv = $builtin/quakebsp.vert; + quakebspf = $builtin/quakebsp.frag; }; samplers = { quakepic = { @@ -44,6 +46,20 @@ }, ); }; + quakebsp = { + flags = 0; + maxSets = $framebuffers.size; + bindings = ( + { + type = uniform_buffer; + descriptorCount = $framebuffers.size; + }, + { + type = combined_image_sampler; + descriptorCount = "5z * $framebuffers.size"; + }, + ); + }; }; setLayouts = { twod = { @@ -62,6 +78,46 @@ }, ); }; + quakebsp = { + bindings = ( + { + binding = 0; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = vertex; + }, + { + binding = 1; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 2; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 3; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 4; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 5; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; something = { flags = 0; bindings = ( @@ -84,6 +140,21 @@ twod = { setLayouts = (twod); }; + quakebsp = { + setLayouts = (quakebsp); + pushConstantRanges = ( + { + stageFlags = vertex; + offset = 0; + size = "16 * 4"; + }, + { + stageFlags = fragment; + offset = 0; + size = 32; + }, + ); + }; something = { setLayouts = (something); pushConstantRanges = ( @@ -96,6 +167,95 @@ }; }; pipelines = { + quakebsp.main = { + stages = ( + { stage = vertex; name = main; module = quakebspv; }, + { stage = fragment; name = main; module = quakebspf; }, + ); + vertexInput = { + bindings = ( + { + binding = 0; + stride = "3 * 4 * 4"; + inputRate = vertex; + }, + ); + attributes = ( + { + location = 0; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 0; + }, + { + location = 1; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 8; + }, + ); + }; + inputAssembly = { + topology = triangle_fan; + primitiveRestartEnable = true; + }; + viewport = { + viewports = ( + { + x = 0; y = 0; + width = 640; height = 480; + minDepth = 0; maxDepth = 1; + } + ); + scissors = ( + { + offset = { x = 0; y = 0 }; + extent = { width = 640; height = 480; }; + }, + ); + }; + rasterization = { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = fill; + cullMode = back; + frontFace = clockwise; + depthBiasEnable = false; + lineWidth = 1; + }; + multisample = { + rasterizationSamples = $msaaSamples; + sampleShadingEnable = false; + minSampleShading = 0.5f; + alphaToCoverageEnable = false; + alphaToOneEnable = false; + }; + depthStencil = { + depthTestEnable = true; + depthWriteEnable = true; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + colorBlend = { + logicOpEnable = false; + attachments = ({ + blendEnable = true; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }); + }; + dynamic = { + dynamicState = ( viewport, scissor, blend_constants ); + }; + layout = quakebsp; + //renderPass = renderpass; + }; twod = { stages = ( { stage = vertex; name = main; module = twodv; }, diff --git a/libs/video/renderer/vulkan/quakebsp.frag b/libs/video/renderer/vulkan/quakebsp.frag index 151243249..219ce9212 100644 --- a/libs/video/renderer/vulkan/quakebsp.frag +++ b/libs/video/renderer/vulkan/quakebsp.frag @@ -3,8 +3,8 @@ layout (set = 0, binding = 1) uniform sampler2D Texture; layout (set = 0, binding = 2) uniform sampler2D Glowmap; layout (set = 0, binding = 3) uniform sampler2D Lightmap; -layout (set = 0, binding = 4) uniform samplerCube SkyCube; -layout (set = 0, binding = 5) uniform sampler2DArray SkySheet; +layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; +layout (set = 0, binding = 5) uniform samplerCube SkyCube; layout (push_constant) uniform PushConstants { float time; @@ -12,8 +12,7 @@ layout (push_constant) uniform PushConstants { }; layout (location = 0) in vec4 tl_st; -layout (location = 1) in vec4 color; -layout (location = 2) out vec3 direction; +layout (location = 1) in vec3 direction; layout (location = 0) out vec4 frag_color; @@ -111,7 +110,7 @@ main (void) if (doSkyCube || doSkySheet) { c = sky_color (direction, time); } else { - c = texture (Texture, t_st) * color; + c = texture (Texture, t_st); } if (doLight) { c *= texture (Lightmap, l_st); diff --git a/libs/video/renderer/vulkan/quakebsp.vert b/libs/video/renderer/vulkan/quakebsp.vert index 11ae0c90a..bb9e87e4a 100644 --- a/libs/video/renderer/vulkan/quakebsp.vert +++ b/libs/video/renderer/vulkan/quakebsp.vert @@ -12,11 +12,9 @@ layout (push_constant) uniform PushConstants { layout (location = 0) in vec4 vertex; layout (location = 1) in vec4 tl_uv; -layout (location = 2) in vec4 vcolor; layout (location = 0) out vec4 tl_st; -layout (location = 1) out vec4 color; -layout (location = 2) out vec3 direction; +layout (location = 1) out vec3 direction; void main (void) @@ -24,5 +22,4 @@ main (void) gl_Position = Projection * (View * (Model * vertex)); direction = (Sky * vertex).xyz; tl_st = tl_uv; - color = vcolor; } diff --git a/libs/video/renderer/vulkan/texture.c b/libs/video/renderer/vulkan/texture.c index d926632a7..112c71a92 100644 --- a/libs/video/renderer/vulkan/texture.c +++ b/libs/video/renderer/vulkan/texture.c @@ -135,6 +135,12 @@ QFV_CreateScrap (qfv_device_t *device, int size, QFFormat format) return scrap; } +size_t +QFV_ScrapSize (scrap_t *scrap) +{ + return scrap->rscrap.width * scrap->rscrap.height * scrap->bpp; +} + void QFV_ScrapClear (scrap_t *scrap) { diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c new file mode 100644 index 000000000..466d6bbd7 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -0,0 +1,1286 @@ +/* + vulkan_bsp.c + + Vulkan bsp + + Copyright (C) 2012 Bill Currie + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2012/1/7 + Date: 2021/1/18 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define NH_DEFINE +//#include "namehack.h" + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "qfalloca.h" + +#include "QF/cvar.h" +#include "QF/darray.h" +#include "QF/dstring.h" +#include "QF/image.h" +#include "QF/render.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vrect.h" + +#include "QF/Vulkan/qf_bsp.h" +#include "QF/Vulkan/qf_lightmap.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/staging.h" +#include "QF/Vulkan/texture.h" + +#include "r_internal.h" +#include "vid_vulkan.h" +#include "vkparse.h" + +#define ALLOC_CHUNK 64 + +typedef struct { + uint32_t count; + uint32_t indices[1]; +} glslpoly_t; + +#define CHAIN_SURF_F2B(surf,chain) \ + do { \ + instsurf_t *inst = (surf)->instsurf; \ + if (__builtin_expect(!inst, 1)) \ + (surf)->tinst = inst = get_instsurf (bctx); \ + inst->surface = (surf); \ + *(chain##_tail) = inst; \ + (chain##_tail) = &inst->tex_chain; \ + *(chain##_tail) = 0; \ + } while (0) + +#define CHAIN_SURF_B2F(surf,chain) \ + do { \ + instsurf_t *inst = (surf)->instsurf; \ + if (__builtin_expect(!inst, 1)) \ + (surf)->tinst = inst = get_instsurf (bctx); \ + inst->surface = (surf); \ + inst->tex_chain = (chain); \ + (chain) = inst; \ + } while (0) + +#define GET_RELEASE(type,name) \ +static inline type * \ +get_##name (bspctx_t *bctx) \ +{ \ + type *ele; \ + if (!bctx->free_##name##s) { \ + int i; \ + bctx->free_##name##s = calloc (ALLOC_CHUNK, sizeof (type)); \ + for (i = 0; i < ALLOC_CHUNK - 1; i++) \ + bctx->free_##name##s[i]._next = &bctx->free_##name##s[i + 1]; \ + } \ + ele = bctx->free_##name##s; \ + bctx->free_##name##s = ele->_next; \ + ele->_next = 0; \ + *bctx->name##s_tail = ele; \ + bctx->name##s_tail = &ele->_next; \ + return ele; \ +} \ +static inline void \ +release_##name##s (bspctx_t *bctx) \ +{ \ + if (bctx->name##s) { \ + *bctx->name##s_tail = bctx->free_##name##s; \ + bctx->free_##name##s = bctx->name##s; \ + bctx->name##s = 0; \ + bctx->name##s_tail = &bctx->name##s; \ + } \ +} + +GET_RELEASE (elechain_t, elechain) +GET_RELEASE (elements_t, elements) +GET_RELEASE (instsurf_t, static_instsurf) +GET_RELEASE (instsurf_t, instsurf) + +static void +add_texture (texture_t *tx, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + + vulktex_t *tex = tx->render; + DARRAY_APPEND (&bctx->texture_chains, tex); + tex->tex_chain = 0; + tex->tex_chain_tail = &tex->tex_chain; + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; +} + +static void +init_surface_chains (model_t *model, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + int i; + + release_static_instsurfs (bctx); + release_instsurfs (bctx); + + for (i = 0; i < model->nummodelsurfaces; i++) { + model->surfaces[i].instsurf = get_static_instsurf (bctx); + model->surfaces[i].instsurf->surface = &model->surfaces[i]; + } +} + +static inline void +clear_tex_chain (vulktex_t *tex) +{ + tex->tex_chain = 0; + tex->tex_chain_tail = &tex->tex_chain; + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; +} + +static void +clear_texture_chains (bspctx_t *bctx) +{ + for (size_t i = 0; i < bctx->texture_chains.size; i++) { + if (!bctx->texture_chains.a[i]) + continue; + clear_tex_chain (bctx->texture_chains.a[i]); + } + clear_tex_chain (r_notexture_mip->render); + release_elechains (bctx); + release_elementss (bctx); + release_instsurfs (bctx); +} + +void +Vulkan_ClearElements (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + release_elechains (bctx); + release_elementss (bctx); +} + +static void +update_lightmap (msurface_t *surf, vulkan_ctx_t *ctx) +{ + int maps; + + for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++) + if (d_lightstylevalue[surf->styles[maps]] != surf->cached_light[maps]) + goto dynamic; + + if ((surf->dlightframe == r_framecount) || surf->cached_dlight) { +dynamic: + if (r_dynamic->int_val) + Vulkan_BuildLightMap (surf, ctx); + } +} + +static inline void +chain_surface (msurface_t *surf, vec_t *transform, float *color, + vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + instsurf_t *is; + + if (surf->flags & SURF_DRAWSKY) { + CHAIN_SURF_F2B (surf, bctx->sky_chain); + } else if ((surf->flags & SURF_DRAWTURB) || (color && color[3] < 1.0)) { + CHAIN_SURF_B2F (surf, bctx->waterchain); + } else { + texture_t *tx; + vulktex_t *tex; + + if (!surf->texinfo->texture->anim_total) + tx = surf->texinfo->texture; + else + tx = R_TextureAnimation (surf); + tex = tx->render; + CHAIN_SURF_F2B (surf, tex->tex_chain); + + update_lightmap (surf, ctx); + } + if (!(is = surf->instsurf)) + is = surf->tinst; + is->transform = transform; + is->color = color; +} + +static void +register_textures (model_t *model, vulkan_ctx_t *ctx) +{ + int i; + texture_t *tex; + + for (i = 0; i < model->numtextures; i++) { + tex = model->textures[i]; + if (!tex) + continue; + add_texture (tex, ctx); + } +} + +static void +clear_textures (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + bctx->texture_chains.size = 0; +} + +void +Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx) +{ + int i; + model_t *m; + + clear_textures (ctx); + init_surface_chains (r_worldentity.model, ctx); + add_texture (r_notexture_mip, ctx); + register_textures (r_worldentity.model, ctx); + for (i = 0; i < num_models; i++) { + m = models[i]; + if (!m) + continue; + // sub-models are done as part of the main model + if (*m->name == '*') + continue; + // world has already been done, not interested in non-brush models + if (m == r_worldentity.model || m->type != mod_brush) + continue; + m->numsubmodels = 1; // no support for submodels in non-world model + register_textures (m, ctx); + } +} + +static elechain_t * +add_elechain (vulktex_t *tex, int ec_index, bspctx_t *bctx) +{ + elechain_t *ec; + + ec = get_elechain (bctx); + ec->elements = get_elements (bctx); + ec->index = ec_index; + ec->transform = 0; + ec->color = 0; + *tex->elechain_tail = ec; + tex->elechain_tail = &ec->next; + return ec; +} + +static void +build_surf_displist (model_t **models, msurface_t *fa, int base, + dstring_t *vert_list) +{ + int numverts; + int numtris; + int numindices; + int i; + vec_t *vec; + mvertex_t *vertices; + medge_t *edges; + int *surfedges; + int index; + bspvert_t *verts; + glslpoly_t *poly; + uint32_t *ind; + float s, t; + + if (fa->ec_index < 0) { + vertices = models[-fa->ec_index - 1]->vertexes; + edges = models[-fa->ec_index - 1]->edges; + surfedges = models[-fa->ec_index - 1]->surfedges; + } else { + vertices = r_worldentity.model->vertexes; + edges = r_worldentity.model->edges; + surfedges = r_worldentity.model->surfedges; + } + numverts = fa->numedges; + numtris = numverts - 2; + numindices = numtris * 3; + verts = alloca (numverts * sizeof (bspvert_t)); + poly = malloc (field_offset (glslpoly_t, indices[numindices])); + poly->count = numindices; + for (i = 0, ind = poly->indices; i < numtris; i++) { + *ind++ = base; + *ind++ = base + i + 1; + *ind++ = base + i + 2; + } + fa->polys = (glpoly_t *) poly; + + for (i = 0; i < numverts; i++) { + index = surfedges[fa->firstedge + i]; + if (index > 0) + vec = vertices[edges[index].v[0]].position; + else + vec = vertices[edges[-index].v[1]].position; + + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + VectorCopy (vec, verts[i].vertex); + verts[i].vertex[3] = 1; + verts[i].tlst[0] = s / fa->texinfo->texture->width; + verts[i].tlst[1] = t / fa->texinfo->texture->height; + + //lightmap texture coordinates + if (!fa->lightpic) { + // sky and water textures don't have lightmaps + verts[i].tlst[2] = 0; + verts[i].tlst[3] = 0; + continue; + } + s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; + t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; + s -= fa->texturemins[0]; + t -= fa->texturemins[1]; + s += fa->lightpic->rect->x * 16 + 8; + t += fa->lightpic->rect->y * 16 + 8; + s /= 16; + t /= 16; + verts[i].tlst[2] = s * fa->lightpic->size; + verts[i].tlst[3] = t * fa->lightpic->size; + } + dstring_append (vert_list, (char *) verts, numverts * sizeof (bspvert_t)); +} + +void +Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + int i, j; + int vertex_index_base; + model_t *m; + dmodel_t *dm; + msurface_t *surf; + dstring_t *vertices; + + QuatSet (0, 0, sqrt(0.5), sqrt(0.5), bctx->sky_fix); // proper skies + QuatSet (0, 0, 0, 1, bctx->sky_rotation[0]); + QuatCopy (bctx->sky_rotation[0], bctx->sky_rotation[1]); + QuatSet (0, 0, 0, 0, bctx->sky_velocity); + QuatExp (bctx->sky_velocity, bctx->sky_velocity); + bctx->sky_time = vr_data.realtime; + + // now run through all surfaces, chaining them to their textures, thus + // effectively sorting the surfaces by texture (without worrying about + // surface order on the same texture chain). + for (i = 0; i < num_models; i++) { + m = models[i]; + if (!m) + continue; + // sub-models are done as part of the main model + if (*m->name == '*') + continue; + // non-bsp models don't have surfaces. + dm = m->submodels; + for (j = 0; j < m->numsurfaces; j++) { + vulktex_t *tex; + if (j == dm->firstface + dm->numfaces) { + dm++; + if (dm - m->submodels == m->numsubmodels) { + // limit the surfaces + // probably never hit + Sys_Printf ("R_BuildDisplayLists: too many surfaces\n"); + m->numsurfaces = j; + break; + } + } + surf = m->surfaces + j; + surf->ec_index = dm - m->submodels; + if (!surf->ec_index && m != r_worldentity.model) + surf->ec_index = -1 - i; // instanced model + tex = surf->texinfo->texture->render; + CHAIN_SURF_F2B (surf, tex->tex_chain); + } + } + // All vertices from all brush models go into one giant vbo. + vertices = dstring_new (); + vertex_index_base = 0; + // All usable surfaces have been chained to the (base) texture they use. + // Run through the textures, using their chains to build display maps. + // For animated textures, if a surface is on one texture of the group, it + // will be on all. + for (size_t i = 0; i < bctx->texture_chains.size; i++) { + vulktex_t *tex; + instsurf_t *is; + elechain_t *ec = 0; + elements_t *el = 0; + + tex = bctx->texture_chains.a[i]; + + for (is = tex->tex_chain; is; is = is->tex_chain) { + msurface_t *surf = is->surface; + if (!tex->elechain) { + ec = add_elechain (tex, surf->ec_index, bctx); + el = ec->elements; + el->base = (byte *) (intptr_t) vertices->size; + vertex_index_base = 0; + } + if (surf->ec_index != ec->index) { // next sub-model + ec = add_elechain (tex, surf->ec_index, bctx); + el = ec->elements; + el->base = (byte *) (intptr_t) vertices->size; + vertex_index_base = 0; + } + if (vertex_index_base + surf->numedges > 65535) { + // elements index overflow + el->next = get_elements (bctx); + el = el->next; + el->base = (byte *) (intptr_t) vertices->size; + vertex_index_base = 0; + } + // we don't use it now, but pre-initializing the list won't hurt + if (!el->list) + el->list = dstring_new (); + dstring_clear (el->list); + + surf->base = el->base; + build_surf_displist (models, surf, vertex_index_base, vertices); + vertex_index_base += surf->numedges; + } + } + clear_texture_chains (bctx); + Sys_MaskPrintf (SYS_GLSL, "R_BuildDisplayLists: %ld verts total\n", + (long) (vertices->size / sizeof (bspvert_t))); + /*XXX if (!bsp_vbo) + qfeglGenBuffers (1, &bsp_vbo); + qfeglBindBuffer (GL_ARRAY_BUFFER, bsp_vbo); + qfeglBufferData (GL_ARRAY_BUFFER, vertices->size, vertices->str, + GL_STATIC_DRAW); + qfeglBindBuffer (GL_ARRAY_BUFFER, 0);*/ + dstring_delete (vertices); +} + +static void +R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) +{ + float dot, radius; + int i; + unsigned k; + model_t *model; + plane_t *plane; + msurface_t *surf; + qboolean rotated; + vec3_t mins, maxs, org; + + model = e->model; + if (e->transform[0] != 1 || e->transform[5] != 1 || e->transform[10] != 1) { + rotated = true; + radius = model->radius; + if (R_CullSphere (e->origin, radius)) + return; + } else { + rotated = false; + VectorAdd (e->origin, model->mins, mins); + VectorAdd (e->origin, model->maxs, maxs); + if (R_CullBox (mins, maxs)) + return; + } + + VectorSubtract (r_refdef.vieworg, e->origin, org); + if (rotated) { + vec3_t temp; + + VectorCopy (org, temp); + org[0] = DotProduct (temp, e->transform + 0); + org[1] = DotProduct (temp, e->transform + 4); + org[2] = DotProduct (temp, e->transform + 8); + } + + // calculate dynamic lighting for bmodel if it's not an instanced model + if (model->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { + vec3_t lightorigin; + + for (k = 0; k < r_maxdlights; k++) { + if ((r_dlights[k].die < vr_data.realtime) + || (!r_dlights[k].radius)) + continue; + + VectorSubtract (r_dlights[k].origin, e->origin, lightorigin); + R_RecursiveMarkLights (lightorigin, &r_dlights[k], k, + model->nodes + model->hulls[0].firstclipnode); + } + } + + surf = &model->surfaces[model->firstmodelsurface]; + + for (i = 0; i < model->nummodelsurfaces; i++, surf++) { + // find the node side on which we are + plane = surf->plane; + + dot = PlaneDiff (org, plane); + + // enqueue the polygon + if (((surf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) + || (!(surf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { + chain_surface (surf, e->transform, e->colormod, ctx); + } + } +} + +static inline void +visit_leaf (mleaf_t *leaf) +{ + // deal with model fragments in this leaf + if (leaf->efrags) + R_StoreEfrags (leaf->efrags); +} + +static inline int +get_side (mnode_t *node) +{ + // find the node side on which we are + plane_t *plane = node->plane; + + if (plane->type < 3) + return (r_origin[plane->type] - plane->dist) < 0; + return (DotProduct (r_origin, plane->normal) - plane->dist) < 0; +} + +static inline void +visit_node (mnode_t *node, int side, vulkan_ctx_t *ctx) +{ + int c; + msurface_t *surf; + + // sneaky hack for side = side ? SURF_PLANEBACK : 0; + side = (~side + 1) & SURF_PLANEBACK; + // draw stuff + if ((c = node->numsurfaces)) { + surf = r_worldentity.model->surfaces + node->firstsurface; + for (; c; c--, surf++) { + if (surf->visframe != r_visframecount) + continue; + + // side is either 0 or SURF_PLANEBACK + if (side ^ (surf->flags & SURF_PLANEBACK)) + continue; // wrong side + + chain_surface (surf, 0, 0, ctx); + } + } +} + +static inline int +test_node (mnode_t *node) +{ + if (node->contents < 0) + return 0; + if (node->visframe != r_visframecount) + return 0; + if (R_CullBox (node->minmaxs, node->minmaxs + 3)) + return 0; + return 1; +} + +static void +R_VisitWorldNodes (model_t *model, vulkan_ctx_t *ctx) +{ + typedef struct { + mnode_t *node; + int side; + } rstack_t; + rstack_t *node_ptr; + rstack_t *node_stack; + mnode_t *node; + mnode_t *front; + int side; + + node = model->nodes; + // +2 for paranoia + node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); + node_ptr = node_stack; + + while (1) { + while (test_node (node)) { + side = get_side (node); + front = node->children[side]; + if (test_node (front)) { + node_ptr->node = node; + node_ptr->side = side; + node_ptr++; + node = front; + continue; + } + if (front->contents < 0 && front->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) front); + visit_node (node, side, ctx); + node = node->children[!side]; + } + if (node->contents < 0 && node->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) node); + if (node_ptr != node_stack) { + node_ptr--; + node = node_ptr->node; + side = node_ptr->side; + visit_node (node, side, ctx); + node = node->children[!side]; + continue; + } + break; + } + if (node->contents < 0 && node->contents != CONTENTS_SOLID) + visit_leaf ((mleaf_t *) node); +} + +/*static void +draw_elechain (elechain_t *ec, int matloc, int vertloc, int tlstloc, + int colloc, bspctx_t *bctx) +{ + mat4_t mat; + elements_t *el; + int count; + float *color; + + if (colloc >= 0) { + color = ec->color; + if (!color) + color = bctx->default_color; + if (!QuatCompare (color, bctx->last_color)) { + QuatCopy (color, bctx->last_color); + qfeglVertexAttrib4fv (quake_bsp.color.location, color); + } + } + if (ec->transform) { + Mat4Mult (bsp_vp, ec->transform, mat); + qfeglUniformMatrix4fv (matloc, 1, false, mat); + } else { + qfeglUniformMatrix4fv (matloc, 1, false, bsp_vp); + } + for (el = ec->elements; el; el = el->next) { + if (!el->list->size) + continue; + count = el->list->size / sizeof (GLushort); + qfeglVertexAttribPointer (vertloc, 4, GL_FLOAT, + 0, sizeof (bspvert_t), + el->base + field_offset (bspvert_t, vertex)); + if (tlstloc >= 0) + qfeglVertexAttribPointer (tlstloc, 4, GL_FLOAT, + 0, sizeof (bspvert_t), + el->base + field_offset (bspvert_t,tlst)); + qfeglDrawElements (GL_TRIANGLES, count, + GL_UNSIGNED_SHORT, el->list->str); + dstring_clear (el->list); + } +}*/ + +static void +bsp_begin (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + //XXX quat_t fog; + + bctx->default_color[3] = 1; + QuatCopy (bctx->default_color, bctx->last_color); + + __auto_type cframe = &ctx->framebuffers.a[ctx->curFrame]; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + DARRAY_APPEND (cframe->subCommand, bframe->bsp_cmd); + + dfunc->vkResetCommandBuffer (bframe->bsp_cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + ctx->renderpass.renderpass, 0, + cframe->framebuffer, + 0, 0, 0, + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (bframe->bsp_cmd, &beginInfo); + + //XXX glsl_Fog_GetColor (fog); + //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; +} + +static void +bsp_end (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + dfunc->vkEndCommandBuffer (bframe->bsp_cmd); +} + +/*static void +turb_begin (bspctx_t *bctx) +{ + quat_t fog; + + bctx->default_color[3] = bound (0, r_wateralpha->value, 1); + QuatCopy (bctx->default_color, bctx->last_color); + qfeglVertexAttrib4fv (quake_bsp.color.location, default_color); + + Mat4Mult (glsl_projection, glsl_view, bsp_vp); + + qfeglUseProgram (quake_turb.program); + qfeglEnableVertexAttribArray (quake_turb.vertex.location); + qfeglEnableVertexAttribArray (quake_turb.tlst.location); + qfeglDisableVertexAttribArray (quake_turb.color.location); + + qfeglVertexAttrib4fv (quake_turb.color.location, default_color); + + glsl_Fog_GetColor (fog); + fog[3] = glsl_Fog_GetDensity () / 64.0; + qfeglUniform4fv (quake_turb.fog.location, 1, fog); + + qfeglUniform1i (quake_turb.palette.location, 1); + qfeglActiveTexture (GL_TEXTURE0 + 1); + qfeglEnable (GL_TEXTURE_2D); + qfeglBindTexture (GL_TEXTURE_2D, glsl_palette); + + qfeglUniform1f (quake_turb.time.location, vr_data.realtime); + + qfeglUniform1i (quake_turb.texture.location, 0); + qfeglActiveTexture (GL_TEXTURE0 + 0); + qfeglEnable (GL_TEXTURE_2D); + + qfeglBindBuffer (GL_ARRAY_BUFFER, bsp_vbo); +}*/ + +/*static void +turb_end (bspctx_t *bctx) +{ + qfeglDisableVertexAttribArray (quake_turb.vertex.location); + qfeglDisableVertexAttribArray (quake_turb.tlst.location); + + qfeglActiveTexture (GL_TEXTURE0 + 0); + qfeglDisable (GL_TEXTURE_2D); + qfeglActiveTexture (GL_TEXTURE0 + 1); + qfeglDisable (GL_TEXTURE_2D); + + qfeglBindBuffer (GL_ARRAY_BUFFER, 0); +}*/ + +/*XXX static void +spin (mat4_t mat, bspctx_t *bctx) +{ + quat_t q; + mat4_t m; + float blend; + + while (vr_data.realtime - bctx->sky_time > 1) { + QuatCopy (bctx->sky_rotation[1], bctx->sky_rotation[0]); + QuatMult (bctx->sky_velocity, bctx->sky_rotation[0], + bctx->sky_rotation[1]); + bctx->sky_time += 1; + } + blend = bound (0, (vr_data.realtime - bctx->sky_time), 1); + + QuatBlend (bctx->sky_rotation[0], bctx->sky_rotation[1], blend, q); + QuatMult (bctx->sky_fix, q, q); + Mat4Identity (mat); + VectorNegate (r_origin, mat + 12); + QuatToMatrix (q, m, 1, 1); + Mat4Mult (m, mat, mat); +}*/ + +static void +sky_begin (bspctx_t *bctx) +{ + //XXX mat4_t mat; + //XXX quat_t fog; + + bctx->default_color[3] = 1; + QuatCopy (bctx->default_color, bctx->last_color); +/* qfeglVertexAttrib4fv (quake_bsp.color.location, bctx->default_color); + + Mat4Mult (glsl_projection, glsl_view, bsp_vp); + + if (bctx->skybox_tex) { + sky_params.mvp_matrix = &quake_skybox.mvp_matrix; + sky_params.vertex = &quake_skybox.vertex; + sky_params.sky_matrix = &quake_skybox.sky_matrix; + sky_params.fog = &quake_skybox.fog; + + qfeglUseProgram (quake_skybox.program); + qfeglEnableVertexAttribArray (quake_skybox.vertex.location); + + qfeglUniform1i (quake_skybox.sky.location, 0); + qfeglActiveTexture (GL_TEXTURE0 + 0); + qfeglEnable (GL_TEXTURE_CUBE_MAP); + qfeglBindTexture (GL_TEXTURE_CUBE_MAP, skybox_tex); + } else { + sky_params.mvp_matrix = &quake_skyid.mvp_matrix; + sky_params.sky_matrix = &quake_skyid.sky_matrix; + sky_params.vertex = &quake_skyid.vertex; + sky_params.fog = &quake_skyid.fog; + + qfeglUseProgram (quake_skyid.program); + qfeglEnableVertexAttribArray (quake_skyid.vertex.location); + + qfeglUniform1i (quake_skyid.palette.location, 2); + qfeglActiveTexture (GL_TEXTURE0 + 2); + qfeglEnable (GL_TEXTURE_2D); + qfeglBindTexture (GL_TEXTURE_2D, glsl_palette); + + qfeglUniform1f (quake_skyid.time.location, vr_data.realtime); + + qfeglUniform1i (quake_skyid.trans.location, 0); + qfeglActiveTexture (GL_TEXTURE0 + 0); + qfeglEnable (GL_TEXTURE_2D); + + qfeglUniform1i (quake_skyid.solid.location, 1); + qfeglActiveTexture (GL_TEXTURE0 + 1); + qfeglEnable (GL_TEXTURE_2D); + } + + glsl_Fog_GetColor (fog); + fog[3] = glsl_Fog_GetDensity () / 64.0; + qfeglUniform4fv (sky_params.fog->location, 1, fog); + + spin (mat); + qfeglUniformMatrix4fv (sky_params.sky_matrix->location, 1, false, mat); + + qfeglBindBuffer (GL_ARRAY_BUFFER, bsp_vbo);*/ +} + +static void +sky_end (bspctx_t *bctx) +{ + /*XXX qfeglDisableVertexAttribArray (sky_params.vertex->location); + + qfeglActiveTexture (GL_TEXTURE0 + 0); + qfeglDisable (GL_TEXTURE_2D); + qfeglDisable (GL_TEXTURE_CUBE_MAP); + qfeglActiveTexture (GL_TEXTURE0 + 1); + qfeglDisable (GL_TEXTURE_2D); + qfeglActiveTexture (GL_TEXTURE0 + 2); + qfeglDisable (GL_TEXTURE_2D); + + qfeglBindBuffer (GL_ARRAY_BUFFER, 0);*/ +} + +static inline void +add_surf_elements (vulktex_t *tex, instsurf_t *is, + elechain_t **ec, elements_t **el, bspctx_t *bctx) +{ + msurface_t *surf = is->surface; + glslpoly_t *poly = (glslpoly_t *) surf->polys; + + if (!tex->elechain) { + (*ec) = add_elechain (tex, surf->ec_index, bctx); + (*ec)->transform = is->transform; + (*ec)->color = is->color; + (*el) = (*ec)->elements; + (*el)->base = surf->base; + if (!(*el)->list) + (*el)->list = dstring_new (); + dstring_clear ((*el)->list); + } + if (is->transform != (*ec)->transform || is->color != (*ec)->color) { + (*ec) = add_elechain (tex, surf->ec_index, bctx); + (*ec)->transform = is->transform; + (*ec)->color = is->color; + (*el) = (*ec)->elements; + (*el)->base = surf->base; + if (!(*el)->list) + (*el)->list = dstring_new (); + dstring_clear ((*el)->list); + } + if (surf->base != (*el)->base) { + (*el)->next = get_elements (bctx); + (*el) = (*el)->next; + (*el)->base = surf->base; + if (!(*el)->list) + (*el)->list = dstring_new (); + dstring_clear ((*el)->list); + } + dstring_append ((*el)->list, (char *) poly->indices, + poly->count * sizeof (poly->indices[0])); +} + +static void +build_tex_elechain (vulktex_t *tex, bspctx_t *bctx) +{ + instsurf_t *is; + elechain_t *ec = 0; + elements_t *el = 0; + + for (is = tex->tex_chain; is; is = is->tex_chain) { + add_surf_elements (tex, is, &ec, &el, bctx); + } +} + +void +Vulkan_DrawWorld (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + entity_t worldent; + + clear_texture_chains (bctx); // do this first for water and skys + + memset (&worldent, 0, sizeof (worldent)); + worldent.model = r_worldentity.model; + + currententity = &worldent; + + R_VisitWorldNodes (worldent.model, ctx); + if (r_drawentities->int_val) { + entity_t *ent; + for (ent = r_ent_queue; ent; ent = ent->next) { + if (ent->model->type != mod_brush) + continue; + currententity = ent; + + R_DrawBrushModel (ent, ctx); + } + } + + Vulkan_FlushLightmaps (ctx); + bsp_begin (ctx); + //XXX qfeglActiveTexture (GL_TEXTURE0 + 0); + for (size_t i = 0; i < bctx->texture_chains.size; i++) { + vulktex_t *tex; + //XXX elechain_t *ec = 0; + + tex = bctx->texture_chains.a[i]; + + build_tex_elechain (tex, bctx); + + //XXX if (tex->elechain) + //XXX qfeglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum); + + /*XXX for (ec = tex->elechain; ec; ec = ec->next) { + draw_elechain (ec, quake_bsp.mvp_matrix.location, + quake_bsp.vertex.location, + quake_bsp.tlst.location, + quake_bsp.color.location); + }*/ + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; + } + bsp_end (ctx); +} + +void +Vulkan_DrawWaterSurfaces (vulkan_ctx_t *ctx) +{ +/* bspctx_t *bctx = ctx->bsp_context; + instsurf_t *is; + msurface_t *surf; + vulktex_t *tex = 0; + elechain_t *ec = 0; + elements_t *el = 0; + + if (!bctx->waterchain) + return; + + turb_begin (bctx); + for (is = bctx->waterchain; is; is = is->tex_chain) { + surf = is->surface; + if (tex != surf->texinfo->texture) { + if (tex) { + //XXX qfeglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum); + //for (ec = tex->elechain; ec; ec = ec->next) + // draw_elechain (ec, quake_turb.mvp_matrix.location, + // quake_turb.vertex.location, + // quake_turb.tlst.location, + // quake_turb.color.location); + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; + } + tex = surf->texinfo->texture; + } + add_surf_elements (tex, is, &ec, &el, bctx); + } + if (tex) { + //XXX qfeglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum); + //for (ec = tex->elechain; ec; ec = ec->next) + // draw_elechain (ec, quake_turb.mvp_matrix.location, + // quake_turb.vertex.location, + // quake_turb.tlst.location, + // quake_turb.color.location); + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; + } + turb_end (bctx); + + bctx->waterchain = 0; + bctx->waterchain_tail = &bctx->waterchain;*/ +} + +void +Vulkan_DrawSky (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + instsurf_t *is; + msurface_t *surf; + vulktex_t *tex = 0; + elechain_t *ec = 0; + elements_t *el = 0; + + if (!bctx->sky_chain) + return; + + sky_begin (bctx); + for (is = bctx->sky_chain; is; is = is->tex_chain) { + surf = is->surface; + if (tex != surf->texinfo->texture->render) { + if (tex) { + if (!bctx->skybox_tex) { + //XXX qfeglActiveTexture (GL_TEXTURE0 + 0); + //qfeglBindTexture (GL_TEXTURE_2D, tex->sky_tex[0]); + //qfeglActiveTexture (GL_TEXTURE0 + 1); + //qfeglBindTexture (GL_TEXTURE_2D, tex->sky_tex[1]); + } + //for (ec = tex->elechain; ec; ec = ec->next) + // draw_elechain (ec, sky_params.mvp_matrix->location, + // sky_params.vertex->location, -1, -1); + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; + } + tex = surf->texinfo->texture->render; + } + add_surf_elements (tex, is, &ec, &el, bctx); + } + if (tex) { + if (!bctx->skybox_tex) { + //XXX qfeglActiveTexture (GL_TEXTURE0 + 0); + //qfeglBindTexture (GL_TEXTURE_2D, tex->sky_tex[0]); + //qfeglActiveTexture (GL_TEXTURE0 + 1); + //qfeglBindTexture (GL_TEXTURE_2D, tex->sky_tex[1]); + } + //for (ec = tex->elechain; ec; ec = ec->next) + // draw_elechain (ec, sky_params.mvp_matrix->location, + // sky_params.vertex->location, -1, -1); + tex->elechain = 0; + tex->elechain_tail = &tex->elechain; + } + sky_end (bctx); + + bctx->sky_chain = 0; + bctx->sky_chain_tail = &bctx->sky_chain; +} + +void +Vulkan_Bsp_Init (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + bspctx_t *bctx = calloc (1, sizeof (bspctx_t)); + ctx->bsp_context = bctx; + + bctx->waterchain_tail = &bctx->waterchain; + bctx->sky_chain_tail = &bctx->sky_chain; + bctx->static_instsurfs_tail = &bctx->static_instsurfs; + bctx->elechains_tail = &bctx->elechains; + bctx->elementss_tail = &bctx->elementss; + bctx->instsurfs_tail = &bctx->instsurfs; + + bctx->light_scrap = QFV_CreateScrap (device, 2048, tex_frgba); + size_t size = QFV_ScrapSize (bctx->light_scrap); + bctx->light_stage = QFV_CreateStagingBuffer (device, size, 3, + ctx->cmdpool); + + DARRAY_INIT (&bctx->texture_chains, 64); + + size_t frames = ctx->framebuffers.size; + DARRAY_INIT (&bctx->frames, frames); + DARRAY_RESIZE (&bctx->frames, frames); + bctx->frames.grow = 0; + + bctx->main = Vulkan_CreatePipeline (ctx, "quakebsp.main"); + bctx->layout = QFV_GetPipelineLayout (ctx, "quakebsp"); + + __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (frames, alloca); + for (size_t i = 0; i < layouts->size; i++) { + layouts->a[i] = QFV_GetDescriptorSetLayout (ctx, "quakebsp"); + } + __auto_type pool = QFV_GetDescriptorPool (ctx, "quakebsp"); + + __auto_type cmdBuffers = QFV_AllocCommandBufferSet (3 * frames, alloca); + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); + + __auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); + for (size_t i = 0; i < frames; i++) { + __auto_type bframe = &bctx->frames.a[i]; + bframe->descriptors = sets->a[i]; + bframe->bsp_cmd = cmdBuffers->a[i]; + bframe->turb_cmd = cmdBuffers->a[i]; + bframe->sky_cmd = cmdBuffers->a[i]; + } + free (sets); +} + +void +Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + + dfunc->vkDestroyPipeline (device->dev, bctx->main, 0); + DARRAY_CLEAR (&bctx->texture_chains); + DARRAY_CLEAR (&bctx->frames); + QFV_DestroyStagingBuffer (bctx->light_stage); + QFV_DestroyScrap (bctx->light_scrap); +} + +static inline __attribute__((const)) int +is_pow2 (unsigned x) +{ + int count; + + for (count = 0; x; x >>= 1) + if (x & 1) + count++; + return count == 1; +} + +// NOTE: this expects the destination tex_t to be set up: memory allocated +// and dimentions/format etc already set. the size of the rect to be copied +// is taken from dst. Also, dst->format and src->format must be the same, and +// either 3 or 4, or bad things will happen. Also, no clipping is done, so if +// x < 0 or y < 0 or x + dst->width > src->width +// or y + dst->height > src->height, bad things will happen. +/*XXX static void +copy_sub_tex (tex_t *src, int x, int y, tex_t *dst) +{ + int dstbytes; + int srcbytes; + int i; + + srcbytes = src->width * src->format; + dstbytes = dst->width * dst->format; + + x *= src->format; + for (i = 0; i < dst->height; i++) + memcpy (dst->data + i * dstbytes, src->data + (i + y) * srcbytes + x, + dstbytes); +}*/ + +/*XXX void +Vulkan_R_LoadSkys (const char *sky, vulkan_ctx_t *ctx) +{ +const char *name; + int i; + tex_t *tex; + // NOTE: quake's world and GL's world are rotated relative to each other + // quake has x right, y in, z up. gl has x right, y up, z out + // quake order: +x -x +z -z +y -y + // gl order: +x -x +y -y +z -z + // fizquake orger: -y +y +z -z +x -x + // to get from quake order to fitzquake order, all that's needed is + // a -90 degree rotation on the (quake) z-axis. This is taken care of in + // the sky_matrix setup code. + // However, from the player's perspective, skymaps have lf and rt + // swapped, but everythink makes sense if looking at the cube from outside + // along the positive y axis, with the front of the cube being the nearest + // face. This matches nicely with Blender's default cube in front (num-1) + // view. + static const char *sky_suffix[] = { "ft", "bk", "up", "dn", "rt", "lf"}; + static int sky_coords[][2] = { + {2, 0}, // front + {0, 0}, // back + {1, 1}, // up + {0, 1}, // down + {2, 1}, // left + {1, 0}, // right + }; + + if (!sky || !*sky) + sky = r_skyname->string; + + if (!*sky || !strcasecmp (sky, "none")) { + skybox_loaded = false; + return; + } + + if (!skybox_tex) + qfeglGenTextures (1, &skybox_tex); + + qfeglBindTexture (GL_TEXTURE_CUBE_MAP, skybox_tex); + + //blender envmap + // bk rt ft + // dn up lt + tex = LoadImage (name = va ("env/%s_map", sky)); + if (tex && tex->format >= 3 && tex->height * 3 == tex->width * 2 + && is_pow2 (tex->height)) { + tex_t *sub; + int size = tex->height / 2; + + skybox_loaded = true; + sub = malloc (field_offset (tex_t, data[size * size * tex->format])); + sub->width = size; + sub->height = size; + sub->format = tex->format; + sub->palette = tex->palette; + for (i = 0; i < 6; i++) { + int x, y; + x = sky_coords[i][0] * size; + y = sky_coords[i][1] * size; + copy_sub_tex (tex, x, y, sub); + qfeglTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, + sub->format == 3 ? GL_RGB : GL_RGBA, + sub->width, sub->height, 0, + sub->format == 3 ? GL_RGB : GL_RGBA, + GL_UNSIGNED_BYTE, sub->data); + } + free (sub); + } else { + skybox_loaded = true; + for (i = 0; i < 6; i++) { + tex = LoadImage (name = va ("env/%s%s", sky, sky_suffix[i])); + if (!tex || tex->format < 3) { // FIXME pcx support + Sys_MaskPrintf (SYS_GLSL, "Couldn't load %s\n", name); + // also look in gfx/env, where Darkplaces looks for skies + tex = LoadImage (name = va ("gfx/env/%s%s", sky, + sky_suffix[i])); + if (!tex || tex->format < 3) { // FIXME pcx support + Sys_MaskPrintf (SYS_GLSL, "Couldn't load %s\n", name); + skybox_loaded = false; + continue; + } + } + Sys_MaskPrintf (SYS_GLSL, "Loaded %s\n", name); + qfeglTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, + tex->format == 3 ? GL_RGB : GL_RGBA, + tex->width, tex->height, 0, + tex->format == 3 ? GL_RGB : GL_RGBA, + GL_UNSIGNED_BYTE, tex->data); + } + } + qfeglTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + qfeglTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + qfeglTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qfeglTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qfeglGenerateMipmap (GL_TEXTURE_CUBE_MAP); +}*/ diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 5cb213b16..cca17f727 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -404,7 +404,6 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) __auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); for (size_t i = 0; i < frames; i++) { - __auto_type cframe = &ctx->framebuffers.a[i]; __auto_type dframe = &dctx->frames.a[i]; dframe->descriptors = sets->a[i]; @@ -420,7 +419,6 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) }; dfunc->vkUpdateDescriptorSets (device->dev, 2, write, 0, 0); dframe->cmd = cmdBuffers->a[i]; - DARRAY_APPEND (cframe->subCommand, cmdBuffers->a[i]); } free (sets); } @@ -686,6 +684,7 @@ Vulkan_FlushText (vulkan_ctx_t *ctx) drawframe_t *dframe = &dctx->frames.a[ctx->curFrame]; VkCommandBuffer cmd = dframe->cmd; + DARRAY_APPEND (cframe->subCommand, cmd); VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, diff --git a/libs/video/renderer/vulkan/vulkan_lightmap.c b/libs/video/renderer/vulkan/vulkan_lightmap.c new file mode 100644 index 000000000..495864d9f --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_lightmap.c @@ -0,0 +1,279 @@ +/* + vulkan_lightmap.c + + surface-related refresh code + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2000 Joseph Carter + Copyright (C) 2021 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define NH_DEFINE +#include "namehack.h" + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include + +#include "QF/cvar.h" +#include "QF/render.h" +#include "QF/sys.h" +#include "QF/Vulkan/qf_bsp.h" +#include "QF/Vulkan/qf_lightmap.h" +#include "QF/Vulkan/qf_main.h" +#include "QF/Vulkan/texture.h" + +#include "compat.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +#define LUXEL_SIZE 4 + +static inline void +add_dynamic_lights (msurface_t *surf, float *block) +{ + unsigned lnum; + int sd, td; + float dist, rad, minlight; + vec3_t impact, local, lightorigin; + int smax, tmax; + int s, t; + mtexinfo_t *tex; + plane_t *plane; + + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + tex = surf->texinfo; + plane = surf->plane; + + for (lnum = 0; lnum < r_maxdlights; lnum++) { + if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) + continue; // not lit by this light + + dlight_t *light = &r_dlights[lnum]; + + VectorSubtract (light->origin, currententity->origin, lightorigin); + rad = light->radius; + dist = DotProduct (lightorigin, plane->normal) - plane->dist; + rad -= fabs (dist); + + minlight = light->minlight; + if (rad < minlight) { + continue; + } + VectorMultSub (light->origin, dist, plane->normal, impact); + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; + + local[0] -= surf->texturemins[0]; + local[1] -= surf->texturemins[1]; + + for (t = 0; t < tmax; t++) { + td = local[1] - t * 16; + if (td < 0) { + td = -td; + } + for (s = 0; s < smax; s++) { + sd = local[0] - s * 16; + if (sd < 0) { + sd = -sd; + } + if (sd > td) { + dist = sd + (td >> 1); + } else { + dist = td + (sd >> 1); + } + if (dist < minlight) { + float *out = block + (t * smax + s) * LUXEL_SIZE; + float l = (rad - dist) * 256; + VectorMultAdd (out, l, light->color, out); + out[3] = 1; + out += LUXEL_SIZE; + } + } + } + } +} + +void +Vulkan_BuildLightMap (msurface_t *surf, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + int smax, tmax, size; + unsigned scale; + int i; + float *out, *block; + + surf->cached_dlight = (surf->dlightframe == r_framecount); + + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + size = smax * tmax * LUXEL_SIZE; + + block = QFV_SubpicBatch (surf->lightpic, bctx->light_stage); + + // set to full bright if no light data + if (!r_worldentity.model->lightdata) { + out = block; + while (size-- > 0) { + *out++ = 1; + } + return; + } + + // clear to no light + memset (block, 0, size * sizeof(float)); + + // add all the lightmaps + if (surf->samples) { + byte *lightmap; + + lightmap = surf->samples; + for (int maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; + maps++) { + scale = d_lightstylevalue[surf->styles[maps]]; + surf->cached_light[maps] = scale; // 8.8 fraction + out = block; + for (i = 0; i < smax * tmax; i++) { + *out++ += *lightmap++ * scale / 256.0; + *out++ += *lightmap++ * scale / 256.0; + *out++ += *lightmap++ * scale / 256.0; + } + } + } + // add all the dynamic lights + if (surf->dlightframe == r_framecount) { + add_dynamic_lights (surf, block); + } +} + +void +Vulkan_CalcLightmaps (vulkan_ctx_t *ctx) +{ +/* int i; + + for (i = 0; i < MAX_LIGHTMAPS; i++) { + if (!gl_lightmap_polys[i]) + continue; + if (gl_lightmap_modified[i]) { + qfglBindTexture (GL_TEXTURE_2D, gl_lightmap_textures + i); + GL_UploadLightmap (i); + gl_lightmap_modified[i] = false; + } + }*/ +} + +static void +vulkan_create_surf_lightmap (msurface_t *surf, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + int smax, tmax; + + smax = (surf->extents[0] >> 4) + 1; + tmax = (surf->extents[1] >> 4) + 1; + + surf->lightpic = QFV_ScrapSubpic (bctx->light_scrap, smax, tmax); + if (!surf->lightpic) { + Sys_Error ("FIXME taniwha is being lazy"); + } +} + +/* + GL_BuildLightmaps + + Builds the lightmap texture with all the surfaces from all brush models +*/ +void +Vulkan_BuildLightmaps (model_t **models, int num_models, vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + int i, j; + model_t *m; + + QFV_ScrapClear (bctx->light_scrap); + + r_framecount = 1; // no dlightcache + + for (j = 1; j < num_models; j++) { + m = models[j]; + if (!m) + break; + if (m->name[0] == '*') { + // sub model surfaces are processed as part of the main model + continue; + } + // non-bsp models don't have surfaces. + for (i = 0; i < m->numsurfaces; i++) { + msurface_t *surf = m->surfaces + i; + surf->lightpic = 0; // paranoia + if (surf->flags & SURF_DRAWTURB) { + continue; + } + if (surf->flags & SURF_DRAWSKY) { + continue; + } + vulkan_create_surf_lightmap (surf, ctx); + } + } + + for (j = 1; j < num_models; j++) { + m = models[j]; + if (!m) { + break; + } + if (m->name[0] == '*') { + // sub model surfaces are processed as part of the main model + continue; + } + // non-bsp models don't have surfaces. + for (i = 0; i < m->numsurfaces; i++) { + msurface_t *surf = m->surfaces + i; + if (surf->lightpic) { + Vulkan_BuildLightMap (surf, ctx); + } + } + } +} + +VkImageView +Vulkan_LightmapImageView (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + return QFV_ScrapImageView (bctx->light_scrap); +} + +void +Vulkan_FlushLightmaps (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + QFV_ScrapFlush (bctx->light_scrap); +} diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c new file mode 100644 index 000000000..1e1913de9 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -0,0 +1,250 @@ +/* + vulkan_main.c + + Vulkan rendering + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/1/19 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define NH_DEFINE +#include "namehack.h" + +#ifdef HAVE_STRING_H +# include "string.h" +#endif +#ifdef HAVE_STRINGS_H +# include "strings.h" +#endif + +#include "QF/cmd.h" +#include "QF/cvar.h" +#include "QF/image.h" +#include "QF/render.h" +#include "QF/screen.h" +#include "QF/sys.h" + +#include "QF/Vulkan/qf_vid.h" +//#include "QF/Vulkan/qf_alias.h" +#include "QF/Vulkan/qf_bsp.h" +//#include "QF/Vulkan/qf_iqm.h" +#include "QF/Vulkan/qf_lightmap.h" +#include "QF/Vulkan/qf_main.h" +#include "QF/Vulkan/qf_particles.h" +//#include "QF/Vulkan/qf_textures.h" + +#include "mod_internal.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +static void +setup_frame (vulkan_ctx_t *ctx) +{ + R_AnimateLight (); + R_ClearEnts (); + r_framecount++; + + VectorCopy (r_refdef.vieworg, r_origin); + AngleVectors (r_refdef.viewangles, vpn, vright, vup); + R_SetFrustum (); + + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.model); +} + +static void +setup_view (vulkan_ctx_t *ctx) +{ + float *mat = ctx->matrices.view_3d; + static mat4_t z_up = { + 0, 0, -1, 0, + -1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 1, + }; + + /*x = r_refdef.vrect.x; + y = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)); + w = r_refdef.vrect.width; + h = r_refdef.vrect.height; + qfeglViewport (x, y, w, h);*/ + + Mat4Zero (mat); + VectorCopy (vpn, mat + 0); + VectorNegate (vright, mat + 4); // we want vleft + VectorCopy (vup, mat + 8); + mat[15] = 1; + Mat4Transpose (mat, mat);//AngleVectors gives the transpose of what we want + Mat4Mult (z_up, mat, glsl_view); + + Mat4Identity (mat); + VectorNegate (r_refdef.vieworg, mat + 12); + Mat4Mult (glsl_view, mat, glsl_view); +} + +static void +R_RenderEntities (vulkan_ctx_t *ctx) +{ + //entity_t *ent; + //int begun; + + if (!r_drawentities->int_val) + return; +#define RE_LOOP(type_name, Type) \ + do { \ + begun = 0; \ + for (ent = r_ent_queue; ent; ent = ent->next) { \ + if (ent->model->type != mod_##type_name) \ + continue; \ + if (!begun) { \ + glsl_R_##Type##Begin (); \ + begun = 1; \ + } \ + currententity = ent; \ + glsl_R_Draw##Type (); \ + } \ + if (begun) \ + glsl_R_##Type##End (); \ + } while (0) + + //RE_LOOP (alias, Alias); + //RE_LOOP (iqm, IQM); + //RE_LOOP (sprite, Sprite); +} + +static void +R_DrawViewModel (void) +{ + currententity = vr_data.view_model; + if (vr_data.inhibit_viewmodel + || !r_drawviewmodel->int_val + || !r_drawentities->int_val + || !currententity->model) + return; + + // hack the depth range to prevent view model from poking into walls + //qfeglDepthRangef (0, 0.3); + //glsl_R_AliasBegin (); + //glsl_R_DrawAlias (); + //glsl_R_AliasEnd (); + //qfeglDepthRangef (0, 1); +} + +void +Vulkan_RenderView (vulkan_ctx_t *ctx) +{ + double t[10] = {}; + int speeds = r_speeds->int_val; + + if (speeds) + t[0] = Sys_DoubleTime (); + setup_frame (ctx); + setup_view (ctx); + if (speeds) + t[1] = Sys_DoubleTime (); + R_MarkLeaves (); + if (speeds) + t[2] = Sys_DoubleTime (); + R_PushDlights (vec3_origin); + if (speeds) + t[3] = Sys_DoubleTime (); + Vulkan_DrawWorld (ctx); + if (speeds) + t[4] = Sys_DoubleTime (); + Vulkan_DrawSky (ctx); + if (speeds) + t[5] = Sys_DoubleTime (); + R_RenderEntities (ctx); + if (speeds) + t[6] = Sys_DoubleTime (); + Vulkan_DrawWaterSurfaces (ctx); + if (speeds) + t[7] = Sys_DoubleTime (); + Vulkan_DrawParticles (ctx); + if (speeds) + t[8] = Sys_DoubleTime (); + R_DrawViewModel (); + if (speeds) + t[9] = Sys_DoubleTime (); + if (speeds) { + Sys_Printf ("frame: %g, setup: %g, mark: %g, pushdl: %g, world: %g," + " sky: %g, ents: %g, water: %g, part: %g, view: %g\n", + (t[9] - t[0]) * 1000, (t[1] - t[0]) * 1000, + (t[2] - t[1]) * 1000, (t[3] - t[2]) * 1000, + (t[4] - t[3]) * 1000, (t[5] - t[4]) * 1000, + (t[6] - t[5]) * 1000, (t[7] - t[6]) * 1000, + (t[8] - t[7]) * 1000, (t[9] - t[8]) * 1000); + } +} + +void +Vulkan_NewMap (model_t *worldmodel, struct model_s **models, int num_models, + vulkan_ctx_t *ctx) +{ + int i; + + for (i = 0; i < 256; i++) { + d_lightstylevalue[i] = 264; // normal light value + } + + memset (&r_worldentity, 0, sizeof (r_worldentity)); + r_worldentity.model = worldmodel; + + // Force a vis update + r_viewleaf = NULL; + R_MarkLeaves (); + + R_FreeAllEntities (); + Vulkan_ClearParticles (ctx); + Vulkan_RegisterTextures (models, num_models, ctx); + Vulkan_BuildLightmaps (models, num_models, ctx); + Vulkan_BuildDisplayLists (models, num_models, ctx); +} + +/*void +glsl_R_LineGraph (int x, int y, int *h_vals, int count) +{ +}*/ + +/*void +glsl_R_TimeRefresh_f (void) +{ + double start, stop, time; + int i; + + glsl_ctx->end_rendering (); + + start = Sys_DoubleTime (); + for (i = 0; i < 128; i++) { + r_refdef.viewangles[1] = i * (360.0 / 128.0); + Vulkan_RenderView (ctx); + glsl_ctx->end_rendering (); + } + + stop = Sys_DoubleTime (); + time = stop - start; + Sys_Printf ("%g seconds (%g fps)\n", time, 128 / time); +}*/ From 7d9ef9a47e8391b078ae6192f0cb5c2288ad8bff Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 20 Jan 2021 13:55:50 +0900 Subject: [PATCH 259/435] [model] Mark all cleared models as cleared This fixes a nine year old bug that I discovered only today thanks to the vulkan renderer. The problem was that when a model had a clear callback, it was not getting marked as needing to be reloaded, and thus the model would be "reused" after being trampled on by another model loading over it. Also, plug a potential string buffer overflow (strcpy just will not die!). --- libs/models/model.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libs/models/model.c b/libs/models/model.c index 198a69f7c..8c5036278 100644 --- a/libs/models/model.c +++ b/libs/models/model.c @@ -122,14 +122,15 @@ Mod_ClearAll (void) model_t **mod; for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) { + //FIXME this seems to be correct but need to double check the behavior + //with alias models if (!(*mod)->needload && (*mod)->clear) { (*mod)->clear (*mod, (*mod)->data); - } else { - if ((*mod)->type != mod_alias) - (*mod)->needload = true; - if ((*mod)->type == mod_sprite) - (*mod)->cache.data = 0; } + if ((*mod)->type != mod_alias) + (*mod)->needload = true; + if ((*mod)->type == mod_sprite) + (*mod)->cache.data = 0; } } @@ -156,7 +157,8 @@ Mod_FindName (const char *name) for (i = 1; i < MOD_BLOCK; i++) mod[i] = mod[0] + i; } - strcpy ((*mod)->name, name); + memset ((*mod), 0, sizeof (model_t)); + strncpy ((*mod)->name, name, sizeof (*mod)->name - 1); (*mod)->needload = true; mod_numknown++; Cache_Add (&(*mod)->cache, *mod, Mod_CallbackLoad); From 9eef805b7db232c5784af82a3493121cef04ec58 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 20 Jan 2021 15:11:50 +0900 Subject: [PATCH 260/435] [vulkan] Generate triangle fans for bsp models They're not uploaded to the card yet, but the basics seem to be working. --- include/QF/Vulkan/qf_bsp.h | 3 +- include/QF/model.h | 2 +- libs/video/renderer/vid_render_vulkan.c | 3 +- libs/video/renderer/vulkan/vulkan_bsp.c | 133 ++++++++++++++---------- 4 files changed, 85 insertions(+), 56 deletions(-) diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index dec2fe085..0dae9450a 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -45,7 +45,6 @@ typedef struct elements_s { struct elements_s *_next; struct elements_s *next; byte *base; - struct dstring_s *list; } elements_t; typedef struct elechain_s { @@ -107,6 +106,8 @@ typedef struct bspctx_s { struct scrap_s *light_scrap; struct qfv_stagebuf_s *light_stage; + struct bsppoly_s *polys; + VkDeviceMemory texture_memory; VkPipeline main; VkPipelineLayout layout; diff --git a/include/QF/model.h b/include/QF/model.h index 1dbfe1b6f..8d0129721 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -153,7 +153,7 @@ typedef struct msurface_s { int light_s, light_t; // gl lightmap coordinates - glpoly_t *polys; // multiple if warped + glpoly_t *polys; // multiple if warped instsurf_t *instsurf; ///< null if not part of world model/sub-model instsurf_t *tinst; ///< for instance models diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index e6f993b38..9e6dc90fd 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -44,6 +44,7 @@ #include "QF/Vulkan/qf_lightmap.h" #include "QF/Vulkan/qf_main.h" #include "QF/Vulkan/qf_particles.h" +#include "QF/Vulkan/qf_texture.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" @@ -462,7 +463,7 @@ vulkan_Skin_InitTranslations (void) } static vid_model_funcs_t model_funcs = { - sizeof (vulktex_t) + 2 * sizeof (struct qfv_tex_s *), + sizeof (vulktex_t) + 2 * sizeof (qfv_tex_t), vulkan_Mod_LoadLighting, vulkan_Mod_SubdivideSurface, vulkan_Mod_ProcessTexture, diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 466d6bbd7..a755f3d86 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -70,10 +70,10 @@ #define ALLOC_CHUNK 64 -typedef struct { +typedef struct bsppoly_s { uint32_t count; uint32_t indices[1]; -} glslpoly_t; +} bsppoly_t; #define CHAIN_SURF_F2B(surf,chain) \ do { \ @@ -297,11 +297,18 @@ add_elechain (vulktex_t *tex, int ec_index, bspctx_t *bctx) } static void +count_verts_inds (model_t **models, msurface_t *fa, + uint32_t *verts, uint32_t *inds) +{ + *verts = fa->numedges; + *inds = fa->numedges + 1; +} + +static bsppoly_t * build_surf_displist (model_t **models, msurface_t *fa, int base, - dstring_t *vert_list) + bspvert_t **vert_list) { int numverts; - int numtris; int numindices; int i; vec_t *vec; @@ -310,38 +317,41 @@ build_surf_displist (model_t **models, msurface_t *fa, int base, int *surfedges; int index; bspvert_t *verts; - glslpoly_t *poly; + bsppoly_t *poly; uint32_t *ind; float s, t; if (fa->ec_index < 0) { - vertices = models[-fa->ec_index - 1]->vertexes; - edges = models[-fa->ec_index - 1]->edges; - surfedges = models[-fa->ec_index - 1]->surfedges; + // instance model + vertices = models[~fa->ec_index]->vertexes; + edges = models[~fa->ec_index]->edges; + surfedges = models[~fa->ec_index]->surfedges; } else { - vertices = r_worldentity.model->vertexes; - edges = r_worldentity.model->edges; + // main or sub model + vertices = r_worldentity.model->vertexes; + edges = r_worldentity.model->edges; surfedges = r_worldentity.model->surfedges; } + // create a triangle fan numverts = fa->numedges; - numtris = numverts - 2; - numindices = numtris * 3; - verts = alloca (numverts * sizeof (bspvert_t)); - poly = malloc (field_offset (glslpoly_t, indices[numindices])); + numindices = numverts + 1; + verts = *vert_list; + // surf->polys is set to the next slow before the call + poly = (bsppoly_t *) fa->polys; poly->count = numindices; - for (i = 0, ind = poly->indices; i < numtris; i++) { - *ind++ = base; - *ind++ = base + i + 1; - *ind++ = base + i + 2; + for (i = 0, ind = poly->indices; i < numverts; i++) { + *ind++ = base + i; } + *ind++ = -1; // end of primitive fa->polys = (glpoly_t *) poly; for (i = 0; i < numverts; i++) { index = surfedges[fa->firstedge + i]; - if (index > 0) + if (index > 0) { vec = vertices[edges[index].v[0]].position; - else + } else { vec = vertices[edges[-index].v[1]].position; + } s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]; t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]; @@ -368,19 +378,23 @@ build_surf_displist (model_t **models, msurface_t *fa, int base, verts[i].tlst[2] = s * fa->lightpic->size; verts[i].tlst[3] = t * fa->lightpic->size; } - dstring_append (vert_list, (char *) verts, numverts * sizeof (bspvert_t)); + *vert_list += numverts; + return (bsppoly_t *) &poly->indices[numindices]; } void Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) { + qfv_device_t *device = ctx->device; bspctx_t *bctx = ctx->bsp_context; int i, j; int vertex_index_base; model_t *m; dmodel_t *dm; msurface_t *surf; - dstring_t *vertices; + qfv_stagebuf_t *stage; + bspvert_t *vertices; + bsppoly_t *poly; QuatSet (0, 0, sqrt(0.5), sqrt(0.5), bctx->sky_fix); // proper skies QuatSet (0, 0, 0, 1, bctx->sky_rotation[0]); @@ -418,16 +432,38 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) if (!surf->ec_index && m != r_worldentity.model) surf->ec_index = -1 - i; // instanced model tex = surf->texinfo->texture->render; + // append surf to the texture chain CHAIN_SURF_F2B (surf, tex->tex_chain); } } // All vertices from all brush models go into one giant vbo. - vertices = dstring_new (); + uint32_t vertex_count = 0; + uint32_t index_count = 0; + uint32_t poly_count = 0; + for (size_t i = 0; i < bctx->texture_chains.size; i++) { + vulktex_t *tex = bctx->texture_chains.a[i]; + for (instsurf_t *is = tex->tex_chain; is; is = is->tex_chain) { + uint32_t verts, inds; + count_verts_inds (models, is->surface, &verts, &inds); + vertex_count += verts; + index_count += inds; + poly_count++; + } + } + stage = QFV_CreateStagingBuffer (device, + vertex_count * sizeof (bspvert_t), 1, + ctx->cmdpool); + vertices = stage->data; vertex_index_base = 0; + // holds all the polygon definitions (count + indices) + bctx->polys = malloc ((index_count + poly_count) * sizeof (uint32_t)); + // All usable surfaces have been chained to the (base) texture they use. // Run through the textures, using their chains to build display maps. // For animated textures, if a surface is on one texture of the group, it // will be on all. + poly = bctx->polys; + int count = 0; for (size_t i = 0; i < bctx->texture_chains.size; i++) { vulktex_t *tex; instsurf_t *is; @@ -441,42 +477,43 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) if (!tex->elechain) { ec = add_elechain (tex, surf->ec_index, bctx); el = ec->elements; - el->base = (byte *) (intptr_t) vertices->size; vertex_index_base = 0; } if (surf->ec_index != ec->index) { // next sub-model ec = add_elechain (tex, surf->ec_index, bctx); el = ec->elements; - el->base = (byte *) (intptr_t) vertices->size; vertex_index_base = 0; } if (vertex_index_base + surf->numedges > 65535) { // elements index overflow el->next = get_elements (bctx); el = el->next; - el->base = (byte *) (intptr_t) vertices->size; vertex_index_base = 0; } // we don't use it now, but pre-initializing the list won't hurt - if (!el->list) - el->list = dstring_new (); - dstring_clear (el->list); + //XXX if (!el->list) + //XXX el->list = dstring_new (); + //XXX dstring_clear (el->list); - surf->base = el->base; - build_surf_displist (models, surf, vertex_index_base, vertices); + surf->polys = (glpoly_t *) poly; + poly = build_surf_displist (models, surf, vertex_index_base, + &vertices); vertex_index_base += surf->numedges; + count++; } } clear_texture_chains (bctx); - Sys_MaskPrintf (SYS_GLSL, "R_BuildDisplayLists: %ld verts total\n", - (long) (vertices->size / sizeof (bspvert_t))); + Sys_MaskPrintf (SYS_VULKAN, + "R_BuildDisplayLists: verts:%u, inds:%u, polys:%u (%d) %zd\n", + vertex_count, index_count, poly_count, count, + ((size_t) poly - (size_t) bctx->polys)/sizeof(uint32_t)); /*XXX if (!bsp_vbo) qfeglGenBuffers (1, &bsp_vbo); qfeglBindBuffer (GL_ARRAY_BUFFER, bsp_vbo); qfeglBufferData (GL_ARRAY_BUFFER, vertices->size, vertices->str, GL_STATIC_DRAW); qfeglBindBuffer (GL_ARRAY_BUFFER, 0);*/ - dstring_delete (vertices); + QFV_DestroyStagingBuffer (stage); } static void @@ -890,38 +927,28 @@ add_surf_elements (vulktex_t *tex, instsurf_t *is, elechain_t **ec, elements_t **el, bspctx_t *bctx) { msurface_t *surf = is->surface; - glslpoly_t *poly = (glslpoly_t *) surf->polys; + //XXX bsppoly_t *poly = (bsppoly_t *) surf->polys; if (!tex->elechain) { (*ec) = add_elechain (tex, surf->ec_index, bctx); (*ec)->transform = is->transform; (*ec)->color = is->color; (*el) = (*ec)->elements; - (*el)->base = surf->base; - if (!(*el)->list) - (*el)->list = dstring_new (); - dstring_clear ((*el)->list); + //XXX if (!(*el)->list) + //XXX (*el)->list = dstring_new (); + //XXX dstring_clear ((*el)->list); } if (is->transform != (*ec)->transform || is->color != (*ec)->color) { (*ec) = add_elechain (tex, surf->ec_index, bctx); (*ec)->transform = is->transform; (*ec)->color = is->color; (*el) = (*ec)->elements; - (*el)->base = surf->base; - if (!(*el)->list) - (*el)->list = dstring_new (); - dstring_clear ((*el)->list); + //XXX if (!(*el)->list) + //XXX (*el)->list = dstring_new (); + //XXX dstring_clear ((*el)->list); } - if (surf->base != (*el)->base) { - (*el)->next = get_elements (bctx); - (*el) = (*el)->next; - (*el)->base = surf->base; - if (!(*el)->list) - (*el)->list = dstring_new (); - dstring_clear ((*el)->list); - } - dstring_append ((*el)->list, (char *) poly->indices, - poly->count * sizeof (poly->indices[0])); + //XXX dstring_append ((*el)->list, (char *) poly->indices, + //XXX poly->count * sizeof (poly->indices[0])); } static void From 6f73a7388b16c4e80f5b732208253ccf8128e8c8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 20 Jan 2021 16:25:26 +0900 Subject: [PATCH 261/435] [vulkan] Ensure staging buffer is idle before free I never actually tested what would happen, but I suspect destroying a staging buffer before it is finished its job would lead to unpleasant issues. --- include/QF/Vulkan/command.h | 3 +++ libs/video/renderer/vulkan/staging.c | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/QF/Vulkan/command.h b/include/QF/Vulkan/command.h index 47418db1a..c9ed3021e 100644 --- a/include/QF/Vulkan/command.h +++ b/include/QF/Vulkan/command.h @@ -15,6 +15,9 @@ typedef struct qfv_semaphoreset_s typedef struct qfv_fenceset_s DARRAY_TYPE (VkFence) qfv_fenceset_t; +#define QFV_AllocFenceSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_fenceset_t, num, allocator) + typedef struct qfv_bufferimagecopy_s DARRAY_TYPE (VkBufferImageCopy) qfv_bufferimagecopy_t; diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c index 40ad459a6..68bf6a9aa 100644 --- a/libs/video/renderer/vulkan/staging.c +++ b/libs/video/renderer/vulkan/staging.c @@ -1,7 +1,7 @@ /* - shader.c + staging.c - Vulkan shader manager + Vulkan staging buffer manager Copyright (C) 2021 Bill Currie @@ -97,6 +97,12 @@ QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage) qfv_device_t *device = stage->device; qfv_devfuncs_t *dfunc = device->funcs; + __auto_type fences = QFV_AllocFenceSet (stage->num_packets, alloca); + for (size_t i = 0; i < stage->num_packets; i++) { + fences->a[i] = stage->packet[i].fence; + } + dfunc->vkWaitForFences (device->dev, fences->size, fences->a, VK_TRUE, + ~0ull); for (size_t i = 0; i < stage->num_packets; i++) { dfunc->vkDestroyFence (device->dev, stage->packet[i].fence, 0); } From 9ebecf08bb2ccc86730dfb4946ff2abdcc07fe2d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 20 Jan 2021 16:28:04 +0900 Subject: [PATCH 262/435] [vulkan] Create a populate the vertex buffer And create/map the index buffer. --- include/QF/Vulkan/qf_bsp.h | 3 +- libs/video/renderer/vulkan/vulkan_bsp.c | 103 ++++++++++++++++++++---- 2 files changed, 91 insertions(+), 15 deletions(-) diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index 0dae9450a..c5a74c76e 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -57,7 +57,8 @@ typedef struct elechain_s { } elechain_t; typedef struct bspframe_s { - uint32_t *indeces; + uint32_t *index_data; + uint32_t index_count; VkCommandBuffer bsp_cmd; VkCommandBuffer turb_cmd; VkCommandBuffer sky_cmd; diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index a755f3d86..eb1ccacc4 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -58,6 +58,7 @@ #include "QF/Vulkan/qf_bsp.h" #include "QF/Vulkan/qf_lightmap.h" #include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/buffer.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" @@ -386,6 +387,7 @@ void Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; bspctx_t *bctx = ctx->bsp_context; int i, j; int vertex_index_base; @@ -450,10 +452,14 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) poly_count++; } } - stage = QFV_CreateStagingBuffer (device, - vertex_count * sizeof (bspvert_t), 1, + + size_t frames = bctx->frames.size; + size_t index_buffer_size = index_count * frames * sizeof (uint32_t); + size_t vertex_buffer_size = vertex_count * sizeof (bspvert_t); + stage = QFV_CreateStagingBuffer (device, vertex_buffer_size, 1, ctx->cmdpool); - vertices = stage->data; + qfv_packet_t *packet = QFV_PacketAcquire (stage); + vertices = QFV_PacketExtend (packet, vertex_buffer_size); vertex_index_base = 0; // holds all the polygon definitions (count + indices) bctx->polys = malloc ((index_count + poly_count) * sizeof (uint32_t)); @@ -468,7 +474,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) vulktex_t *tex; instsurf_t *is; elechain_t *ec = 0; - elements_t *el = 0; + //elements_t *el = 0; tex = bctx->texture_chains.a[i]; @@ -476,20 +482,20 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) msurface_t *surf = is->surface; if (!tex->elechain) { ec = add_elechain (tex, surf->ec_index, bctx); - el = ec->elements; + //el = ec->elements; vertex_index_base = 0; } if (surf->ec_index != ec->index) { // next sub-model ec = add_elechain (tex, surf->ec_index, bctx); - el = ec->elements; + //el = ec->elements; vertex_index_base = 0; } - if (vertex_index_base + surf->numedges > 65535) { + /*if (vertex_index_base + surf->numedges > 65535) { // elements index overflow el->next = get_elements (bctx); el = el->next; vertex_index_base = 0; - } + }*/ // we don't use it now, but pre-initializing the list won't hurt //XXX if (!el->list) //XXX el->list = dstring_new (); @@ -507,12 +513,73 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) "R_BuildDisplayLists: verts:%u, inds:%u, polys:%u (%d) %zd\n", vertex_count, index_count, poly_count, count, ((size_t) poly - (size_t) bctx->polys)/sizeof(uint32_t)); - /*XXX if (!bsp_vbo) - qfeglGenBuffers (1, &bsp_vbo); - qfeglBindBuffer (GL_ARRAY_BUFFER, bsp_vbo); - qfeglBufferData (GL_ARRAY_BUFFER, vertices->size, vertices->str, - GL_STATIC_DRAW); - qfeglBindBuffer (GL_ARRAY_BUFFER, 0);*/ + if (index_buffer_size > bctx->index_buffer_size) { + if (bctx->index_buffer) { + dfunc->vkUnmapMemory (device->dev, bctx->index_memory); + dfunc->vkDestroyBuffer (device->dev, bctx->index_buffer, 0); + dfunc->vkFreeMemory (device->dev, bctx->index_memory, 0); + } + bctx->index_buffer + = QFV_CreateBuffer (device, index_buffer_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + bctx->index_memory + = QFV_AllocBufferMemory (device, bctx->index_buffer, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + index_buffer_size, 0); + QFV_BindBufferMemory (device, + bctx->index_buffer, bctx->index_memory, 0); + bctx->index_buffer_size = index_buffer_size; + void *data; + dfunc->vkMapMemory (device->dev, bctx->index_memory, 0, + index_buffer_size, 0, &data); + uint32_t *index_data = data; + for (size_t i = 0; i < frames; i++) { + bctx->frames.a[i].index_data = index_data + index_count * i; + } + } + if (vertex_buffer_size > bctx->vertex_buffer_size) { + if (bctx->vertex_buffer) { + dfunc->vkDestroyBuffer (device->dev, bctx->vertex_buffer, 0); + dfunc->vkFreeMemory (device->dev, bctx->vertex_memory, 0); + } + bctx->vertex_buffer + = QFV_CreateBuffer (device, vertex_buffer_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + bctx->vertex_memory + = QFV_AllocBufferMemory (device, bctx->vertex_buffer, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + vertex_buffer_size, 0); + QFV_BindBufferMemory (device, + bctx->vertex_buffer, bctx->vertex_memory, 0); + bctx->vertex_buffer_size = vertex_buffer_size; + } + + VkBufferMemoryBarrier wr_barrier = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + bctx->vertex_buffer, 0, vertex_buffer_size, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 1, &wr_barrier, 0, 0); + VkBufferCopy copy_region = { packet->offset, 0, vertex_buffer_size }; + dfunc->vkCmdCopyBuffer (packet->cmd, ctx->staging->buffer, + bctx->vertex_buffer, 1, ©_region); + VkBufferMemoryBarrier rd_barrier = { + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + bctx->vertex_buffer, 0, vertex_buffer_size, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + 0, 0, 0, 1, &rd_barrier, 0, 0); + QFV_PacketSubmit (packet); QFV_DestroyStagingBuffer (stage); } @@ -1176,6 +1243,14 @@ Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx) DARRAY_CLEAR (&bctx->frames); QFV_DestroyStagingBuffer (bctx->light_stage); QFV_DestroyScrap (bctx->light_scrap); + if (bctx->vertex_buffer) { + dfunc->vkDestroyBuffer (device->dev, bctx->vertex_buffer, 0); + dfunc->vkFreeMemory (device->dev, bctx->vertex_memory, 0); + } + if (bctx->index_buffer) { + dfunc->vkDestroyBuffer (device->dev, bctx->index_buffer, 0); + dfunc->vkFreeMemory (device->dev, bctx->index_memory, 0); + } } static inline __attribute__((const)) int From 1080c89a268de9bb5650068bcd207068c104ff1a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 20 Jan 2021 16:51:35 +0900 Subject: [PATCH 263/435] [vulkan] Bind the bsp main pipeline No drawing commands are issued yet, but vulkan seems to be happy with the state. --- include/QF/Vulkan/qf_bsp.h | 1 + libs/video/renderer/vulkan/vulkan_bsp.c | 30 ++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index c5a74c76e..6d4440bd6 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -59,6 +59,7 @@ typedef struct elechain_s { typedef struct bspframe_s { uint32_t *index_data; uint32_t index_count; + uint32_t index_offset; VkCommandBuffer bsp_cmd; VkCommandBuffer turb_cmd; VkCommandBuffer sky_cmd; diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index eb1ccacc4..aba44c043 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -522,7 +522,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) bctx->index_buffer = QFV_CreateBuffer (device, index_buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT - | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); bctx->index_memory = QFV_AllocBufferMemory (device, bctx->index_buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, @@ -535,7 +535,9 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) index_buffer_size, 0, &data); uint32_t *index_data = data; for (size_t i = 0; i < frames; i++) { - bctx->frames.a[i].index_data = index_data + index_count * i; + uint32_t offset = index_count * i; + bctx->frames.a[i].index_data = index_data + offset; + bctx->frames.a[i].index_offset = offset * sizeof (uint32_t); } } if (vertex_buffer_size > bctx->vertex_buffer_size) { @@ -809,9 +811,10 @@ bsp_begin (vulkan_ctx_t *ctx) __auto_type cframe = &ctx->framebuffers.a[ctx->curFrame]; bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; - DARRAY_APPEND (cframe->subCommand, bframe->bsp_cmd); + VkCommandBuffer cmd = bframe->bsp_cmd; + DARRAY_APPEND (cframe->subCommand, cmd); - dfunc->vkResetCommandBuffer (bframe->bsp_cmd, 0); + dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, ctx->renderpass.renderpass, 0, @@ -823,7 +826,24 @@ bsp_begin (vulkan_ctx_t *ctx) VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, }; - dfunc->vkBeginCommandBuffer (bframe->bsp_cmd, &beginInfo); + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + bctx->main); + VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; + VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; + dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); + + VkDeviceSize offsets[] = { 0 }; + dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &bctx->vertex_buffer, offsets); + dfunc->vkCmdBindIndexBuffer (cmd, bctx->index_buffer, bframe->index_offset, + VK_INDEX_TYPE_UINT32); + + VkDescriptorSet set = bframe->descriptors; + VkPipelineLayout layout = bctx->layout; + dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + layout, 0, 1, &set, 0, 0); //XXX glsl_Fog_GetColor (fog); //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; From e0e6677bd337143412549cb2cb21564db563d1d0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Jan 2021 00:40:22 +0900 Subject: [PATCH 264/435] [vulkan] Upload brush model textures Things aren't quite right with them (sky texture is very wrong), but the heavy lifting is done. --- include/QF/Vulkan/image.h | 2 + include/QF/Vulkan/qf_texture.h | 2 + libs/models/brush/vulkan_model_brush.c | 154 ++++++++++++++++++++ libs/video/renderer/vulkan/vulkan_texture.c | 34 ++++- 4 files changed, 184 insertions(+), 8 deletions(-) diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index 501a5025e..489c86e40 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -28,6 +28,8 @@ typedef struct qfv_imagetransitionset_s DARRAY_TYPE (qfv_imagetransition_t) qfv_imagetransitionset_t; typedef struct qfv_imagebarrierset_s DARRAY_TYPE (VkImageMemoryBarrier) qfv_imagebarrierset_t; +#define QFV_AllocImageBarrierSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_imagebarrierset_t, num, allocator) struct qfv_device_s; VkImage QFV_CreateImage (struct qfv_device_s *device, int cubemap, diff --git a/include/QF/Vulkan/qf_texture.h b/include/QF/Vulkan/qf_texture.h index 90906873c..a2ffbd38e 100644 --- a/include/QF/Vulkan/qf_texture.h +++ b/include/QF/Vulkan/qf_texture.h @@ -11,6 +11,8 @@ typedef struct qfv_tex_s { VkImageView view; } qfv_tex_t; +void Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, + int alpha, int count); qfv_tex_t *Vulkan_LoadTex (struct vulkan_ctx_s *ctx, tex_t *tex, int mip); VkImageView Vulkan_TexImageView (qfv_tex_t *tex) __attribute__((pure)); void Vulkan_UnloadTex (struct vulkan_ctx_s *ctx, qfv_tex_t *tex); diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index 52826d280..2b5ed2021 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -48,9 +48,13 @@ #include "QF/Vulkan/qf_bsp.h" #include "QF/Vulkan/qf_model.h" #include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/barrier.h" +#include "QF/Vulkan/command.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" +#include "QF/Vulkan/staging.h" +#include "qfalloca.h" #include "compat.h" #include "mod_internal.h" #include "r_internal.h" @@ -96,6 +100,75 @@ get_image_size (VkImage image, qfv_device_t *device) return size; } +static void +transfer_mips (byte *dst, const void *_src, const texture_t *tx) +{ + const byte *src = _src; + unsigned width = tx->width; + unsigned height = tx->height; + unsigned count, offset; + + for (int i = 0; i < MIPLEVELS; i++) { + // mip offsets are relative to the texture pointer rather than the + // end of the texture struct + offset = tx->offsets[i] - sizeof (texture_t); + count = width * height; + Vulkan_ExpandPalette (dst, src + offset, vid.palette, 1, count); + dst += count; + width >>= 1; + height >>= 1; + } +} + +static void +copy_mips (qfv_packet_t *packet, texture_t *tx, qfv_tex_t *tex, + qfv_devfuncs_t *dfunc) +{ + // base copy + VkBufferImageCopy copy = { + tex->offset, tx->width, 0, + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, + {0, 0, 0}, {tx->width, tx->height, 1}, + }; + int is_sky = 0; + int sky_offset = 0; + size_t size = tx->width * tx->height * 4; + int copy_count = MIPLEVELS; + + if (strncmp (tx->name, "sky", 3) == 0) { + if (tx->width == 2 * tx->height) { + copy.imageExtent.width /= 2; + sky_offset = tx->width * 4 / 2; + } + is_sky = 1; + copy_count *= 2; + } + + __auto_type copies = QFV_AllocBufferImageCopy (copy_count, alloca); + copies->size = 0; + + for (int i = 0; i < MIPLEVELS; i++) { + __auto_type c = &copies->a[copies->size++]; + *c = copy; + if (is_sky) { + __auto_type c = &copies->a[copies->size++]; + *c = copy; + c->bufferOffset += sky_offset * 4; + c->imageSubresource.baseArrayLayer = 1; + } + copy.bufferOffset += size; + size >>= 2; + copy.bufferRowLength >>= 1; + copy.imageExtent.width >>= 1; + copy.imageExtent.height >>= 1; + sky_offset >>= 1; + } + dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer, + tex->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + copies->size, copies->a); +} + static void load_textures (model_t *model, vulkan_ctx_t *ctx) { @@ -103,7 +176,10 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) qfv_devfuncs_t *dfunc = device->funcs; modelctx_t *mctx = model->data; VkImage image = 0; + byte *buffer; + size_t image_count = 0; + size_t copy_count = 0; size_t memsize = 0; for (int i = 0; i < model->numtextures; i++) { texture_t *tx = model->textures[i]; @@ -113,11 +189,18 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) vulktex_t *tex = tx->render; tex->tex->offset = memsize; memsize += get_image_size (tex->tex->image, device); + image_count++; + copy_count += MIPLEVELS; + if (strncmp (tx->name, "sky", 3) == 0) { + copy_count += MIPLEVELS; + } // just so we have one in the end image = tex->tex->image; if (tex->glow) { + copy_count += MIPLEVELS; tex->glow->offset = memsize; memsize += get_image_size (tex->glow->image, device); + image_count++; } } VkDeviceMemory mem; @@ -126,6 +209,11 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) memsize, 0); mctx->texture_memory = mem; + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, memsize, 1, + ctx->cmdpool); + qfv_packet_t *packet = QFV_PacketAcquire (stage); + buffer = QFV_PacketExtend (packet, memsize); + for (int i = 0; i < model->numtextures; i++) { texture_t *tx = model->textures[i]; if (!tx) { @@ -142,6 +230,7 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) tex->tex->view = QFV_CreateImageView (device, tex->tex->image, type, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); + transfer_mips (buffer + tex->tex->offset, tx + 1, tx); if (tex->glow) { dfunc->vkBindImageMemory (device->dev, tex->glow->image, mem, tex->glow->offset); @@ -151,8 +240,67 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); + transfer_mips (buffer + tex->glow->offset, tex->glow->memory, tx); } } + + // base barrier + VkImageMemoryBarrier barrier; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + + __auto_type barriers = QFV_AllocImageBarrierSet (image_count, malloc); + barriers->size = 0; + for (int i = 0; i < model->numtextures; i++) { + texture_t *tx = model->textures[i]; + if (!tx) { + continue; + } + vulktex_t *tex = tx->render; + __auto_type b = &barriers->a[barriers->size++]; + *b = barrier; + b->image = tex->tex->image; + if (tex->glow) { + b = &barriers->a[barriers->size++]; + *b = barrier; + b->image = tex->glow->image; + } + } + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + barriers->size, barriers->a); + for (int i = 0, j = 0; i < model->numtextures; i++) { + texture_t *tx = model->textures[i]; + if (!tx) { + continue; + } + vulktex_t *tex = tx->render; + __auto_type b = &barriers->a[j++]; + b->oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + b->newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + b->srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + b->dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + copy_mips (packet, tx, tex->tex, dfunc); + if (tex->glow) { + b = &barriers->a[j++]; + b->oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + b->newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + b->srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + b->dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + copy_mips (packet, tx, tex->glow, dfunc); + } + } + + stages=imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + barriers->size, barriers->a); + QFV_PacketSubmit (packet); + QFV_DestroyStagingBuffer (stage); } void @@ -173,12 +321,18 @@ Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx) } vulktex_t *tex = tx->render; + tex->texture = tx; tex->tex = (qfv_tex_t *) (tx + 1); VkExtent3D extent = { tx->width, tx->height, 1 }; int layers = 1; if (strncmp (tx->name, "sky", 3) == 0) { layers = 2; + // the sky texture is normally 2 side-by-side squares, but + // some maps have just a single square + if (tx->width == 2 * tx->height) { + extent.width /= 2; + } } tex->tex->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index 05d602d63..bc95431b0 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -85,6 +85,30 @@ ilog2 (unsigned x) return y; } +void +Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, + int alpha, int count) +{ + if (alpha) { + while (count-- > 0) { + byte pix = *src++; + const byte *col = palette + pix; + *dst++ = *col++; + *dst++ = *col++; + *dst++ = *col++; + *dst++ = 0xff; + } + } else { + while (count-- > 0) { + byte pix = *src++; + const byte *col = palette + pix; + *dst++ = *col++; + *dst++ = *col++; + *dst++ = *col++; + } + } +} + qfv_tex_t * Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) { @@ -152,14 +176,8 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) byte *tex_data = QFV_PacketExtend (packet, bytes); if (tex->format == tex_palette) { - byte *data = tex->data; - for (size_t count = tex->width * tex->height; count-- > 0; ) { - byte pix = *data++; - byte *col = tex->palette + pix; - *tex_data++ = *col++; - *tex_data++ = *col++; - *tex_data++ = *col++; - } + Vulkan_ExpandPalette (tex_data, tex->data, tex->palette, + 0, tex->width * tex->height); } else { memcpy (tex_data, tex->data, bytes); } From 9e03096da6d116461a06bce1c35df4498094ebab Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Jan 2021 02:13:40 +0900 Subject: [PATCH 265/435] [vulkan] Build brush model display lists Not working particularly well yet, but no errors out of validation. --- include/QF/Vulkan/funclist.h | 1 + include/QF/Vulkan/qf_bsp.h | 11 +- libs/video/renderer/r_init.c | 1 - libs/video/renderer/vid_render_vulkan.c | 1 + libs/video/renderer/vulkan/qfpipeline.plist | 25 ++- libs/video/renderer/vulkan/quakebsp.frag | 17 ++- libs/video/renderer/vulkan/vulkan_bsp.c | 161 ++++++++++++++------ 7 files changed, 151 insertions(+), 66 deletions(-) diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 209ee0561..b0fe394d9 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -169,6 +169,7 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdEndRenderPass) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindPipeline) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdClearColorImage) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdExecuteCommands) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPushConstants) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdSetViewport) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdSetScissor) diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index 6d4440bd6..95f128e5b 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -44,7 +44,8 @@ typedef struct bspvert_s { typedef struct elements_s { struct elements_s *_next; struct elements_s *next; - byte *base; + uint32_t first_index; + uint32_t index_count; } elements_t; typedef struct elechain_s { @@ -57,9 +58,9 @@ typedef struct elechain_s { } elechain_t; typedef struct bspframe_s { - uint32_t *index_data; - uint32_t index_count; - uint32_t index_offset; + uint32_t *index_data; // pointer into mega-buffer for this frame (c) + uint32_t index_offset; // offset of index_data within mega-buffer (c) + uint32_t index_count; // number if indices queued (d) VkCommandBuffer bsp_cmd; VkCommandBuffer turb_cmd; VkCommandBuffer sky_cmd; @@ -96,6 +97,7 @@ typedef struct bspctx_s { instsurf_t **instsurfs_tail; instsurf_t *free_instsurfs; + struct qfv_tex_s *skysheet_tex; struct qfv_tex_s *skybox_tex; quat_t sky_rotation[2]; quat_t sky_velocity; @@ -110,6 +112,7 @@ typedef struct bspctx_s { struct bsppoly_s *polys; + VkSampler sampler; VkDeviceMemory texture_memory; VkPipeline main; VkPipelineLayout layout; diff --git a/libs/video/renderer/r_init.c b/libs/video/renderer/r_init.c index 94385e1c2..733004a21 100644 --- a/libs/video/renderer/r_init.c +++ b/libs/video/renderer/r_init.c @@ -68,7 +68,6 @@ static U void (*const r_scrapdelete)(rscrap_t *) = R_ScrapDelete; static void R_shutdown (void *data) { - Mod_ClearAll (); if (vidrendmodule->functions->general->p_Shutdown) { vidrendmodule->functions->general->p_Shutdown (); } diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 9e6dc90fd..85d090b37 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -606,6 +606,7 @@ vulkan_vid_render_shutdown (void) df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0); Vulkan_Draw_Shutdown (vulkan_ctx); Vulkan_Bsp_Shutdown (vulkan_ctx); + Mod_ClearAll (); Vulkan_Shutdown_Common (vulkan_ctx); } diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 822e187a5..aa60ec958 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -30,6 +30,23 @@ borderColor = float_transparent_black; unnormalizedCoordinates = false; }; + quakebsp = { + magFilter = linear; + minFilter = linear; + mipmapMode = linear; + addressModeU = repeat; + addressModeV = repeat; + addressModeW = repeat; + mipLodBias = 0; + anisotropyEnable = false; + maxAnisotropy = 0; + compareEnable = false; + compareOp = always; + minLod = 0; + maxLod = 1; + borderColor = float_transparent_black; + unnormalizedCoordinates = false; + }; }; descriptorPools = { twod = { @@ -110,12 +127,12 @@ descriptorCount = 1; stageFlags = fragment; }, - { + /*{ binding = 5; descriptorType = combined_image_sampler; descriptorCount = 1; stageFlags = fragment; - }, + },*/ ); }; something = { @@ -150,7 +167,7 @@ }, { stageFlags = fragment; - offset = 0; + offset = 64; size = 32; }, ); @@ -176,7 +193,7 @@ bindings = ( { binding = 0; - stride = "3 * 4 * 4"; + stride = "2 * 4 * 4"; inputRate = vertex; }, ); diff --git a/libs/video/renderer/vulkan/quakebsp.frag b/libs/video/renderer/vulkan/quakebsp.frag index 219ce9212..24745fba0 100644 --- a/libs/video/renderer/vulkan/quakebsp.frag +++ b/libs/video/renderer/vulkan/quakebsp.frag @@ -4,9 +4,10 @@ layout (set = 0, binding = 1) uniform sampler2D Texture; layout (set = 0, binding = 2) uniform sampler2D Glowmap; layout (set = 0, binding = 3) uniform sampler2D Lightmap; layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; -layout (set = 0, binding = 5) uniform samplerCube SkyCube; +//layout (set = 0, binding = 5) uniform samplerCube SkyCube; layout (push_constant) uniform PushConstants { + layout (offset = 64) float time; vec4 fog; }; @@ -70,7 +71,7 @@ sky_sheet (vec3 dir, float time) return c; } - +/* vec4 sky_cube (vec3 dir, float time) { @@ -80,20 +81,22 @@ sky_cube (vec3 dir, float time) // to do here is swizzle the Y and Z coordinates return texture (SkyCube, dir.xzy); } - +*/ vec4 sky_color (vec3 dir, float time) { if (!doSkySheet) { - return sky_cube (dir, time); + return vec4 (1, 0, 1, 1); + //return sky_cube (dir, time); } if (!doSkyCube) { return sky_sheet (dir, time); } else { - // can see through the sheet (may look funny when looking down) + /*// can see through the sheet (may look funny when looking down) // maybe have 4 sheet layers instead of 2? vec4 c1 = sky_sheet (dir, time); vec4 c2 = sky_cube (dir, time); - return vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + return vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a));*/ + return vec4 (1, 0, 1, 1); } } @@ -117,5 +120,5 @@ main (void) } c += texture (Glowmap, t_st); - frag_color = fogBlend (c); + frag_color = vec4(t_st, 1, 1);//fogBlend (c); } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index aba44c043..d60f95bb5 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -496,10 +496,6 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) el = el->next; vertex_index_base = 0; }*/ - // we don't use it now, but pre-initializing the list won't hurt - //XXX if (!el->list) - //XXX el->list = dstring_new (); - //XXX dstring_clear (el->list); surf->polys = (glpoly_t *) poly; poly = build_surf_displist (models, surf, vertex_index_base, @@ -757,16 +753,14 @@ R_VisitWorldNodes (model_t *model, vulkan_ctx_t *ctx) visit_leaf ((mleaf_t *) node); } -/*static void -draw_elechain (elechain_t *ec, int matloc, int vertloc, int tlstloc, - int colloc, bspctx_t *bctx) +static void +draw_elechain (elechain_t *ec, VkPipelineLayout layout, qfv_devfuncs_t *dfunc, + VkCommandBuffer cmd) { - mat4_t mat; elements_t *el; - int count; - float *color; - if (colloc >= 0) { + /*if (colloc >= 0) { + float *color; color = ec->color; if (!color) color = bctx->default_color; @@ -774,29 +768,31 @@ draw_elechain (elechain_t *ec, int matloc, int vertloc, int tlstloc, QuatCopy (color, bctx->last_color); qfeglVertexAttrib4fv (quake_bsp.color.location, color); } - } + }*/ if (ec->transform) { - Mat4Mult (bsp_vp, ec->transform, mat); - qfeglUniformMatrix4fv (matloc, 1, false, mat); - } else { - qfeglUniformMatrix4fv (matloc, 1, false, bsp_vp); + dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_VERTEX_BIT, + 0, 16 * sizeof (float), ec->transform); } for (el = ec->elements; el; el = el->next) { - if (!el->list->size) + //FIXME check if these are contiguous and if so merge into one + //command + if (!el->index_count) continue; - count = el->list->size / sizeof (GLushort); - qfeglVertexAttribPointer (vertloc, 4, GL_FLOAT, - 0, sizeof (bspvert_t), - el->base + field_offset (bspvert_t, vertex)); - if (tlstloc >= 0) - qfeglVertexAttribPointer (tlstloc, 4, GL_FLOAT, - 0, sizeof (bspvert_t), - el->base + field_offset (bspvert_t,tlst)); - qfeglDrawElements (GL_TRIANGLES, count, - GL_UNSIGNED_SHORT, el->list->str); - dstring_clear (el->list); + dfunc->vkCmdDrawIndexed (cmd, el->index_count, 1, el->first_index, + 0, 0); + el->first_index = 0; + el->index_count = 0; } -}*/ +} + +static VkImageView +get_view (qfv_tex_t *tex) +{ + if (tex) { + return tex->view; + } + return 0; +} static void bsp_begin (vulkan_ctx_t *ctx) @@ -814,6 +810,54 @@ bsp_begin (vulkan_ctx_t *ctx) VkCommandBuffer cmd = bframe->bsp_cmd; DARRAY_APPEND (cframe->subCommand, cmd); + VkDescriptorBufferInfo bufferInfo = { + ctx->matrices.buffer_3d, 0, VK_WHOLE_SIZE + }; + VkDescriptorImageInfo imageInfo[] = { + { bctx->sampler, + QFV_ScrapImageView (bctx->light_scrap), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + { bctx->sampler, + QFV_ScrapImageView (bctx->light_scrap), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + { bctx->sampler, + QFV_ScrapImageView (bctx->light_scrap), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + { bctx->sampler, + get_view (bctx->skysheet_tex), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + { bctx->sampler, + get_view (bctx->skybox_tex), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, + }; + VkWriteDescriptorSet write[] = { + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, + bframe->descriptors, 0, 0, 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, &bufferInfo, 0 }, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, + bframe->descriptors, 1, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + &imageInfo[0], 0, 0 }, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, + bframe->descriptors, 2, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + &imageInfo[1], 0, 0 }, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, + bframe->descriptors, 3, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + &imageInfo[2], 0, 0 }, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, + bframe->descriptors, 4, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + &imageInfo[3], 0, 0 }, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, + bframe->descriptors, 5, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + &imageInfo[4], 0, 0 }, + }; + dfunc->vkUpdateDescriptorSets (device->dev, 5, write, 0, 0); + dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, @@ -1011,49 +1055,56 @@ sky_end (bspctx_t *bctx) static inline void add_surf_elements (vulktex_t *tex, instsurf_t *is, - elechain_t **ec, elements_t **el, bspctx_t *bctx) + elechain_t **ec, elements_t **el, + bspctx_t *bctx, bspframe_t *bframe) { msurface_t *surf = is->surface; - //XXX bsppoly_t *poly = (bsppoly_t *) surf->polys; + bsppoly_t *poly = (bsppoly_t *) surf->polys; if (!tex->elechain) { (*ec) = add_elechain (tex, surf->ec_index, bctx); (*ec)->transform = is->transform; (*ec)->color = is->color; (*el) = (*ec)->elements; - //XXX if (!(*el)->list) - //XXX (*el)->list = dstring_new (); - //XXX dstring_clear ((*el)->list); + (*el)-> first_index = bframe->index_count; } if (is->transform != (*ec)->transform || is->color != (*ec)->color) { (*ec) = add_elechain (tex, surf->ec_index, bctx); (*ec)->transform = is->transform; (*ec)->color = is->color; (*el) = (*ec)->elements; - //XXX if (!(*el)->list) - //XXX (*el)->list = dstring_new (); - //XXX dstring_clear ((*el)->list); + (*el)-> first_index = bframe->index_count; } - //XXX dstring_append ((*el)->list, (char *) poly->indices, - //XXX poly->count * sizeof (poly->indices[0])); + memcpy (bframe->index_data + bframe->index_count, + poly->indices, poly->count * sizeof (poly->indices[0])); + (*el)->index_count += poly->count; } static void -build_tex_elechain (vulktex_t *tex, bspctx_t *bctx) +build_tex_elechain (vulktex_t *tex, bspctx_t *bctx, bspframe_t *bframe) { instsurf_t *is; elechain_t *ec = 0; elements_t *el = 0; for (is = tex->tex_chain; is; is = is->tex_chain) { - add_surf_elements (tex, is, &ec, &el, bctx); + add_surf_elements (tex, is, &ec, &el, bctx, bframe); } } void Vulkan_DrawWorld (vulkan_ctx_t *ctx) { + static float identity[] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + }; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; entity_t worldent; clear_texture_chains (bctx); // do this first for water and skys @@ -1061,6 +1112,9 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) memset (&worldent, 0, sizeof (worldent)); worldent.model = r_worldentity.model; + vulktex_t *tex = r_worldentity.model->skytexture->render; + bctx->skysheet_tex = tex->tex; + currententity = &worldent; R_VisitWorldNodes (worldent.model, ctx); @@ -1077,24 +1131,29 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) Vulkan_FlushLightmaps (ctx); bsp_begin (ctx); + + dfunc->vkCmdPushConstants (bframe->bsp_cmd, bctx->layout, + VK_SHADER_STAGE_VERTEX_BIT, + 0, 16 * sizeof (float), identity); + float frag_pc[8] = { }; + dfunc->vkCmdPushConstants (bframe->bsp_cmd, bctx->layout, + VK_SHADER_STAGE_FRAGMENT_BIT, + 64, 8 * sizeof (float), &frag_pc); //XXX qfeglActiveTexture (GL_TEXTURE0 + 0); for (size_t i = 0; i < bctx->texture_chains.size; i++) { vulktex_t *tex; - //XXX elechain_t *ec = 0; + elechain_t *ec = 0; tex = bctx->texture_chains.a[i]; - build_tex_elechain (tex, bctx); + build_tex_elechain (tex, bctx, bframe); //XXX if (tex->elechain) //XXX qfeglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum); - /*XXX for (ec = tex->elechain; ec; ec = ec->next) { - draw_elechain (ec, quake_bsp.mvp_matrix.location, - quake_bsp.vertex.location, - quake_bsp.tlst.location, - quake_bsp.color.location); - }*/ + for (ec = tex->elechain; ec; ec = ec->next) { + draw_elechain (ec, bctx->layout, dfunc, bframe->bsp_cmd); + } tex->elechain = 0; tex->elechain_tail = &tex->elechain; } @@ -1152,6 +1211,7 @@ void Vulkan_DrawSky (vulkan_ctx_t *ctx) { bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; instsurf_t *is; msurface_t *surf; vulktex_t *tex = 0; @@ -1180,7 +1240,7 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) } tex = surf->texinfo->texture->render; } - add_surf_elements (tex, is, &ec, &el, bctx); + add_surf_elements (tex, is, &ec, &el, bctx, bframe); } if (tex) { if (!bctx->skybox_tex) { @@ -1230,6 +1290,7 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bctx->main = Vulkan_CreatePipeline (ctx, "quakebsp.main"); bctx->layout = QFV_GetPipelineLayout (ctx, "quakebsp"); + bctx->sampler = QFV_GetSampler (ctx, "quakebsp"); __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (frames, alloca); for (size_t i = 0; i < layouts->size; i++) { From 2c1a335715a9531b50266b802af44e1d9a423cfb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Jan 2021 12:39:08 +0900 Subject: [PATCH 266/435] [vulkan] Use vkCmdPushDescriptorSetKHR for bsp This makes switching textures on the fly much easier. --- include/QF/Vulkan/funclist.h | 1 + include/QF/Vulkan/qf_bsp.h | 1 - libs/video/renderer/vulkan/qfpipeline.plist | 15 +------- libs/video/renderer/vulkan/vulkan_bsp.c | 35 ++++++++----------- .../video/renderer/vulkan/vulkan_vid_common.c | 2 ++ 5 files changed, 18 insertions(+), 36 deletions(-) diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index b0fe394d9..90c3a51d2 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -170,6 +170,7 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindPipeline) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdClearColorImage) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdExecuteCommands) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPushConstants) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdPushDescriptorSetKHR) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdSetViewport) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdSetScissor) diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index 95f128e5b..5b01da407 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -64,7 +64,6 @@ typedef struct bspframe_s { VkCommandBuffer bsp_cmd; VkCommandBuffer turb_cmd; VkCommandBuffer sky_cmd; - VkDescriptorSet descriptors; } bspframe_t; typedef struct bspframeset_s diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index aa60ec958..fee54e446 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -63,20 +63,6 @@ }, ); }; - quakebsp = { - flags = 0; - maxSets = $framebuffers.size; - bindings = ( - { - type = uniform_buffer; - descriptorCount = $framebuffers.size; - }, - { - type = combined_image_sampler; - descriptorCount = "5z * $framebuffers.size"; - }, - ); - }; }; setLayouts = { twod = { @@ -96,6 +82,7 @@ ); }; quakebsp = { + flags = push_descriptor; bindings = ( { binding = 0; diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index d60f95bb5..5d7c9efc2 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -831,32 +831,31 @@ bsp_begin (vulkan_ctx_t *ctx) VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, }; VkWriteDescriptorSet write[] = { - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, - bframe->descriptors, 0, 0, 1, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &bufferInfo, 0 }, - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, - bframe->descriptors, 1, 0, 1, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 1, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageInfo[0], 0, 0 }, - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, - bframe->descriptors, 2, 0, 1, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 2, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageInfo[1], 0, 0 }, - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, - bframe->descriptors, 3, 0, 1, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 3, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageInfo[2], 0, 0 }, - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, - bframe->descriptors, 4, 0, 1, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 4, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageInfo[3], 0, 0 }, - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, - bframe->descriptors, 5, 0, 1, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 5, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageInfo[4], 0, 0 }, }; - dfunc->vkUpdateDescriptorSets (device->dev, 5, write, 0, 0); dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { @@ -884,10 +883,8 @@ bsp_begin (vulkan_ctx_t *ctx) dfunc->vkCmdBindIndexBuffer (cmd, bctx->index_buffer, bframe->index_offset, VK_INDEX_TYPE_UINT32); - VkDescriptorSet set = bframe->descriptors; - VkPipelineLayout layout = bctx->layout; - dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - layout, 0, 1, &set, 0, 0); + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + bctx->layout, 0, 5, write); //XXX glsl_Fog_GetColor (fog); //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; @@ -1296,20 +1293,16 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) for (size_t i = 0; i < layouts->size; i++) { layouts->a[i] = QFV_GetDescriptorSetLayout (ctx, "quakebsp"); } - __auto_type pool = QFV_GetDescriptorPool (ctx, "quakebsp"); __auto_type cmdBuffers = QFV_AllocCommandBufferSet (3 * frames, alloca); QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); - __auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); for (size_t i = 0; i < frames; i++) { __auto_type bframe = &bctx->frames.a[i]; - bframe->descriptors = sets->a[i]; bframe->bsp_cmd = cmdBuffers->a[i]; bframe->turb_cmd = cmdBuffers->a[i]; bframe->sky_cmd = cmdBuffers->a[i]; } - free (sets); } void diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 3d317f52c..d9220307b 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -132,11 +132,13 @@ Vulkan_Init_Cvars (void) static const char *instance_extensions[] = { VK_KHR_SURFACE_EXTENSION_NAME, + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 0, }; static const char *device_extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, 0, }; From eb9807576dedd70cc64396e31ee427007200176a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Jan 2021 14:37:39 +0900 Subject: [PATCH 267/435] [vulkan] Fix the bsp vertex index list creation There's still a problem with the vertex data itself not getting sent to the GPU properly, but vulkan is now happy with my tiny test map (which required disabling skies entirely until I get null textures working). --- libs/video/renderer/vulkan/qfpipeline.plist | 4 +-- libs/video/renderer/vulkan/quakebsp.frag | 18 ++++++------- libs/video/renderer/vulkan/vulkan_bsp.c | 29 +++++++-------------- 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index fee54e446..26c3965ac 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -108,13 +108,13 @@ descriptorCount = 1; stageFlags = fragment; }, - { + /*{ binding = 4; descriptorType = combined_image_sampler; descriptorCount = 1; stageFlags = fragment; }, - /*{ + { binding = 5; descriptorType = combined_image_sampler; descriptorCount = 1; diff --git a/libs/video/renderer/vulkan/quakebsp.frag b/libs/video/renderer/vulkan/quakebsp.frag index 24745fba0..21c26dfaa 100644 --- a/libs/video/renderer/vulkan/quakebsp.frag +++ b/libs/video/renderer/vulkan/quakebsp.frag @@ -3,7 +3,7 @@ layout (set = 0, binding = 1) uniform sampler2D Texture; layout (set = 0, binding = 2) uniform sampler2D Glowmap; layout (set = 0, binding = 3) uniform sampler2D Lightmap; -layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; +//layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; //layout (set = 0, binding = 5) uniform samplerCube SkyCube; layout (push_constant) uniform PushConstants { @@ -46,7 +46,7 @@ fogBlend (vec4 color) return vec4 (mix (fog_color.rgb, color.rgb, fog_factor), color.a); } - +/* vec4 sky_sheet (vec3 dir, float time) { @@ -71,7 +71,7 @@ sky_sheet (vec3 dir, float time) return c; } -/* + vec4 sky_cube (vec3 dir, float time) { @@ -81,7 +81,7 @@ sky_cube (vec3 dir, float time) // to do here is swizzle the Y and Z coordinates return texture (SkyCube, dir.xzy); } -*/ + vec4 sky_color (vec3 dir, float time) { @@ -91,15 +91,15 @@ sky_color (vec3 dir, float time) } if (!doSkyCube) { return sky_sheet (dir, time); } else { - /*// can see through the sheet (may look funny when looking down) + // can see through the sheet (may look funny when looking down) // maybe have 4 sheet layers instead of 2? vec4 c1 = sky_sheet (dir, time); vec4 c2 = sky_cube (dir, time); - return vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a));*/ + return vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); return vec4 (1, 0, 1, 1); } } - +*/ void main (void) { @@ -110,11 +110,11 @@ main (void) if (doWarp) { t_st = warp_st (t_st, time); } - if (doSkyCube || doSkySheet) { + /*if (doSkyCube || doSkySheet) { c = sky_color (direction, time); } else { c = texture (Texture, t_st); - } + }*/ if (doLight) { c *= texture (Lightmap, l_st); } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 5d7c9efc2..cf6e6dda2 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -33,9 +33,6 @@ # include "config.h" #endif -#define NH_DEFINE -//#include "namehack.h" - #ifdef HAVE_STRING_H # include #endif @@ -337,7 +334,7 @@ build_surf_displist (model_t **models, msurface_t *fa, int base, numverts = fa->numedges; numindices = numverts + 1; verts = *vert_list; - // surf->polys is set to the next slow before the call + // surf->polys is set to the next slot before the call poly = (bsppoly_t *) fa->polys; poly->count = numindices; for (i = 0, ind = poly->indices; i < numverts; i++) { @@ -474,7 +471,6 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) vulktex_t *tex; instsurf_t *is; elechain_t *ec = 0; - //elements_t *el = 0; tex = bctx->texture_chains.a[i]; @@ -482,20 +478,10 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) msurface_t *surf = is->surface; if (!tex->elechain) { ec = add_elechain (tex, surf->ec_index, bctx); - //el = ec->elements; - vertex_index_base = 0; } if (surf->ec_index != ec->index) { // next sub-model ec = add_elechain (tex, surf->ec_index, bctx); - //el = ec->elements; - vertex_index_base = 0; } - /*if (vertex_index_base + surf->numedges > 65535) { - // elements index overflow - el->next = get_elements (bctx); - el = el->next; - vertex_index_base = 0; - }*/ surf->polys = (glpoly_t *) poly; poly = build_surf_displist (models, surf, vertex_index_base, @@ -534,6 +520,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) uint32_t offset = index_count * i; bctx->frames.a[i].index_data = index_data + offset; bctx->frames.a[i].index_offset = offset * sizeof (uint32_t); + bctx->frames.a[i].index_count = 0; } } if (vertex_buffer_size > bctx->vertex_buffer_size) { @@ -884,7 +871,7 @@ bsp_begin (vulkan_ctx_t *ctx) VK_INDEX_TYPE_UINT32); dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - bctx->layout, 0, 5, write); + bctx->layout, 0, 4, write); //XXX glsl_Fog_GetColor (fog); //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; @@ -1063,18 +1050,19 @@ add_surf_elements (vulktex_t *tex, instsurf_t *is, (*ec)->transform = is->transform; (*ec)->color = is->color; (*el) = (*ec)->elements; - (*el)-> first_index = bframe->index_count; + (*el)->first_index = bframe->index_count; } if (is->transform != (*ec)->transform || is->color != (*ec)->color) { (*ec) = add_elechain (tex, surf->ec_index, bctx); (*ec)->transform = is->transform; (*ec)->color = is->color; (*el) = (*ec)->elements; - (*el)-> first_index = bframe->index_count; + (*el)->first_index = bframe->index_count; } memcpy (bframe->index_data + bframe->index_count, poly->indices, poly->count * sizeof (poly->indices[0])); (*el)->index_count += poly->count; + bframe->index_count += poly->count; } static void @@ -1105,12 +1093,13 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) entity_t worldent; clear_texture_chains (bctx); // do this first for water and skys + bframe->index_count = 0; memset (&worldent, 0, sizeof (worldent)); worldent.model = r_worldentity.model; - vulktex_t *tex = r_worldentity.model->skytexture->render; - bctx->skysheet_tex = tex->tex; + //vulktex_t *tex = r_worldentity.model->skytexture->render; + //bctx->skysheet_tex = tex->tex; currententity = &worldent; From 94b589567b7ec36c94a1ba40ab0307481424ec62 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Jan 2021 16:39:11 +0900 Subject: [PATCH 268/435] [vulkan] Rename texture.c to scrap.c I had originally planned on mixing the stage management with general texture support code like I did in glsl, but I think that was a mistake and I did keep looking for scrap.[ch] when I wanted to edit something to do with the scrap... --- include/QF/Vulkan/{texture.h => scrap.h} | 6 +++--- libs/video/renderer/Makemodule.am | 2 +- libs/video/renderer/vulkan/{texture.c => scrap.c} | 6 +++--- libs/video/renderer/vulkan/vulkan_bsp.c | 2 +- libs/video/renderer/vulkan/vulkan_draw.c | 2 +- libs/video/renderer/vulkan/vulkan_lightmap.c | 2 +- libs/video/renderer/vulkan/vulkan_texture.c | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) rename include/QF/Vulkan/{texture.h => scrap.h} (87%) rename libs/video/renderer/vulkan/{texture.c => scrap.c} (99%) diff --git a/include/QF/Vulkan/texture.h b/include/QF/Vulkan/scrap.h similarity index 87% rename from include/QF/Vulkan/texture.h rename to include/QF/Vulkan/scrap.h index 35aaf5bb5..563a46cc2 100644 --- a/include/QF/Vulkan/texture.h +++ b/include/QF/Vulkan/scrap.h @@ -1,5 +1,5 @@ -#ifndef __QF_Vulkan_texture_h -#define __QF_Vulkan_texture_h +#ifndef __QF_Vulkan_scrap_h +#define __QF_Vulkan_scrap_h #include "QF/image.h" @@ -21,4 +21,4 @@ void *QFV_SubpicBatch (subpic_t *subpic, struct qfv_stagebuf_s *stage); void QFV_ScrapFlush (scrap_t *scrap); -#endif//__QF_Vulkan_texture_h +#endif//__QF_Vulkan_scrap_h diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index a200747ff..5a30c9f0c 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -229,10 +229,10 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/namehack.h \ libs/video/renderer/vulkan/pipeline.c \ libs/video/renderer/vulkan/renderpass.c \ + libs/video/renderer/vulkan/scrap.c \ libs/video/renderer/vulkan/shader.c \ libs/video/renderer/vulkan/staging.c \ libs/video/renderer/vulkan/swapchain.c \ - libs/video/renderer/vulkan/texture.c \ libs/video/renderer/vulkan/util.c \ libs/video/renderer/vulkan/util.h \ libs/video/renderer/vulkan/vkparse.c \ diff --git a/libs/video/renderer/vulkan/texture.c b/libs/video/renderer/vulkan/scrap.c similarity index 99% rename from libs/video/renderer/vulkan/texture.c rename to libs/video/renderer/vulkan/scrap.c index 112c71a92..6e17e786c 100644 --- a/libs/video/renderer/vulkan/texture.c +++ b/libs/video/renderer/vulkan/scrap.c @@ -1,7 +1,7 @@ /* - texuture.c + scrap.c - Vulkan texuture manager + Vulkan scrap manager Copyright (C) 2021 Bill Currie @@ -54,8 +54,8 @@ #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" +#include "QF/Vulkan/scrap.h" #include "QF/Vulkan/staging.h" -#include "QF/Vulkan/texture.h" #include "r_scrap.h" #include "vid_vulkan.h" diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index cf6e6dda2..d8c45d556 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -59,8 +59,8 @@ #include "QF/Vulkan/command.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" +#include "QF/Vulkan/scrap.h" #include "QF/Vulkan/staging.h" -#include "QF/Vulkan/texture.h" #include "r_internal.h" #include "vid_vulkan.h" diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index cca17f727..7345fccd5 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -59,8 +59,8 @@ #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" +#include "QF/Vulkan/scrap.h" #include "QF/Vulkan/staging.h" -#include "QF/Vulkan/texture.h" #include "r_internal.h" #include "vid_vulkan.h" diff --git a/libs/video/renderer/vulkan/vulkan_lightmap.c b/libs/video/renderer/vulkan/vulkan_lightmap.c index 495864d9f..01025e110 100644 --- a/libs/video/renderer/vulkan/vulkan_lightmap.c +++ b/libs/video/renderer/vulkan/vulkan_lightmap.c @@ -49,7 +49,7 @@ #include "QF/Vulkan/qf_bsp.h" #include "QF/Vulkan/qf_lightmap.h" #include "QF/Vulkan/qf_main.h" -#include "QF/Vulkan/texture.h" +#include "QF/Vulkan/scrap.h" #include "compat.h" #include "r_internal.h" diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index bc95431b0..a35498fef 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -56,8 +56,8 @@ #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" +#include "QF/Vulkan/scrap.h" #include "QF/Vulkan/staging.h" -#include "QF/Vulkan/texture.h" #include "r_scrap.h" #include "vid_vulkan.h" From dc79a8a935cfb3d2fffe2705a379b7fa82f70892 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Jan 2021 17:13:17 +0900 Subject: [PATCH 269/435] [vulkan] Clear scrap image on creation And fix the transitions in ScrapFlush. --- include/QF/Vulkan/barrier.h | 1 + include/QF/Vulkan/scrap.h | 2 +- libs/video/renderer/vulkan/barrier.c | 12 ++++++++ libs/video/renderer/vulkan/scrap.c | 35 +++++++++++++++++++++--- libs/video/renderer/vulkan/vulkan_bsp.c | 2 +- libs/video/renderer/vulkan/vulkan_draw.c | 2 +- 6 files changed, 47 insertions(+), 7 deletions(-) diff --git a/include/QF/Vulkan/barrier.h b/include/QF/Vulkan/barrier.h index 12cea49ab..56438aeba 100644 --- a/include/QF/Vulkan/barrier.h +++ b/include/QF/Vulkan/barrier.h @@ -11,6 +11,7 @@ typedef struct { enum { qfv_LT_Undefined_to_TransferDst, qfv_LT_TransferDst_to_ShaderReadOnly, + qfv_LT_ShaderReadOnly_to_TransferDst, qfv_LT_Undefined_to_DepthStencil, qfv_LT_Undefined_to_Color, }; diff --git a/include/QF/Vulkan/scrap.h b/include/QF/Vulkan/scrap.h index 563a46cc2..80c95bd96 100644 --- a/include/QF/Vulkan/scrap.h +++ b/include/QF/Vulkan/scrap.h @@ -9,7 +9,7 @@ struct qfv_stagebuf_s; struct qfv_device_s; scrap_t *QFV_CreateScrap (struct qfv_device_s *device, int size, - QFFormat format); + QFFormat format, struct qfv_stagebuf_s *stage); size_t QFV_ScrapSize (scrap_t *scrap); void QFV_ScrapClear (scrap_t *scrap); void QFV_DestroyScrap (scrap_t *scrap); diff --git a/libs/video/renderer/vulkan/barrier.c b/libs/video/renderer/vulkan/barrier.c index e257eb990..935b370e0 100644 --- a/libs/video/renderer/vulkan/barrier.c +++ b/libs/video/renderer/vulkan/barrier.c @@ -50,6 +50,15 @@ const VkImageMemoryBarrier imageLayoutTransitionBarriers[] = { VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } }, + // shader read only optimal -> transfer dst optimal + { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_SHADER_READ_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }, // undefined -> depth stencil attachment optimal { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, 0, @@ -80,6 +89,9 @@ const qfv_pipelinestagepair_t imageLayoutTransitionStages[] = { // transfer dst optimal -> shader read only optimal { VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT }, + // shader read only optimal -> transfer dst optimal + { VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT }, // undefined -> depth stencil attachment optimal { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT }, diff --git a/libs/video/renderer/vulkan/scrap.c b/libs/video/renderer/vulkan/scrap.c index 6e17e786c..bc5efeda5 100644 --- a/libs/video/renderer/vulkan/scrap.c +++ b/libs/video/renderer/vulkan/scrap.c @@ -76,8 +76,10 @@ struct scrap_s { }; scrap_t * -QFV_CreateScrap (qfv_device_t *device, int size, QFFormat format) +QFV_CreateScrap (qfv_device_t *device, int size, QFFormat format, + qfv_stagebuf_t *stage) { + qfv_devfuncs_t *dfunc = device->funcs; int bpp = 0; VkFormat fmt = VK_FORMAT_UNDEFINED; @@ -132,6 +134,32 @@ QFV_CreateScrap (qfv_device_t *device, int size, QFFormat format) scrap->batch_tail = &scrap->batch; scrap->batch_free = 0; scrap->batch_count = 0; + + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + + qfv_packet_t *packet = QFV_PacketAcquire (stage); + // no data for the packet + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.image = scrap->image; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + VkClearColorValue color = { + float32:{0xde/255.0, 0xad/255.0, 0xbe/255.0, 0xef/255.0}, + }; + VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + dfunc->vkCmdClearColorImage (packet->cmd, scrap->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &color, 1, &range); + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = scrap->image; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + QFV_PacketSubmit (packet); return scrap; } @@ -286,12 +314,11 @@ QFV_ScrapFlush (scrap_t *scrap) copy->a[i].imageExtent.depth = 1; } - VkImageMemoryBarrier barrier; qfv_pipelinestagepair_t stages; - stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; - barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + stages = imageLayoutTransitionStages[qfv_LT_ShaderReadOnly_to_TransferDst]; + barrier=imageLayoutTransitionBarriers[qfv_LT_ShaderReadOnly_to_TransferDst]; barrier.image = scrap->image; dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index d8c45d556..f485b0259 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -1262,7 +1262,7 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bctx->elementss_tail = &bctx->elementss; bctx->instsurfs_tail = &bctx->instsurfs; - bctx->light_scrap = QFV_CreateScrap (device, 2048, tex_frgba); + bctx->light_scrap = QFV_CreateScrap (device, 2048, tex_frgba, ctx->staging); size_t size = QFV_ScrapSize (bctx->light_scrap); bctx->light_stage = QFV_CreateStagingBuffer (device, size, 3, ctx->cmdpool); diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 7345fccd5..2e41e2252 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -367,9 +367,9 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) 0, 0); create_quad_buffers (ctx); - dctx->scrap = QFV_CreateScrap (device, 2048, tex_rgba); dctx->stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024, 4, ctx->cmdpool); + dctx->scrap = QFV_CreateScrap (device, 2048, tex_rgba, dctx->stage); dctx->sampler = QFV_GetSampler (ctx, "quakepic"); qpic_t *charspic = Draw_Font8x8Pic (); From 2acdaa02525f3c13dcf93d32540f3e7ebb618806 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Jan 2021 21:24:54 +0900 Subject: [PATCH 270/435] [vulkan] Fix a pile of data upload issues Copying data from the wrong buffer was the cause of the corrupted brush model vertices, and then lots of little errors (mostly forgetting to multiply by bpp) for textures. --- libs/models/brush/vulkan_model_brush.c | 10 ++++++---- libs/video/renderer/vulkan/qfpipeline.plist | 2 +- libs/video/renderer/vulkan/vulkan_bsp.c | 2 +- libs/video/renderer/vulkan/vulkan_lightmap.c | 7 ++++--- libs/video/renderer/vulkan/vulkan_texture.c | 4 ++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index 2b5ed2021..e40a76e28 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -114,7 +114,7 @@ transfer_mips (byte *dst, const void *_src, const texture_t *tx) offset = tx->offsets[i] - sizeof (texture_t); count = width * height; Vulkan_ExpandPalette (dst, src + offset, vid.palette, 1, count); - dst += count; + dst += count * 4; width >>= 1; height >>= 1; } @@ -126,7 +126,7 @@ copy_mips (qfv_packet_t *packet, texture_t *tx, qfv_tex_t *tex, { // base copy VkBufferImageCopy copy = { - tex->offset, tx->width, 0, + tex->offset, tx->width, tx->height, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, {tx->width, tx->height, 1}, }; @@ -153,14 +153,16 @@ copy_mips (qfv_packet_t *packet, texture_t *tx, qfv_tex_t *tex, if (is_sky) { __auto_type c = &copies->a[copies->size++]; *c = copy; - c->bufferOffset += sky_offset * 4; + c->bufferOffset += sky_offset; c->imageSubresource.baseArrayLayer = 1; } copy.bufferOffset += size; size >>= 2; copy.bufferRowLength >>= 1; + copy.bufferImageHeight >>= 1; copy.imageExtent.width >>= 1; copy.imageExtent.height >>= 1; + copy.imageSubresource.mipLevel++; sky_offset >>= 1; } dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer, @@ -322,7 +324,7 @@ Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx) vulktex_t *tex = tx->render; tex->texture = tx; - tex->tex = (qfv_tex_t *) (tx + 1); + tex->tex = (qfv_tex_t *) (tex + 1); VkExtent3D extent = { tx->width, tx->height, 1 }; int layers = 1; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 26c3965ac..094f49948 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -43,7 +43,7 @@ compareEnable = false; compareOp = always; minLod = 0; - maxLod = 1; + maxLod = 4; borderColor = float_transparent_black; unnormalizedCoordinates = false; }; diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index f485b0259..b0b4c2162 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -552,7 +552,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, 1, &wr_barrier, 0, 0); VkBufferCopy copy_region = { packet->offset, 0, vertex_buffer_size }; - dfunc->vkCmdCopyBuffer (packet->cmd, ctx->staging->buffer, + dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer, bctx->vertex_buffer, 1, ©_region); VkBufferMemoryBarrier rd_barrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, diff --git a/libs/video/renderer/vulkan/vulkan_lightmap.c b/libs/video/renderer/vulkan/vulkan_lightmap.c index 01025e110..30118e484 100644 --- a/libs/video/renderer/vulkan/vulkan_lightmap.c +++ b/libs/video/renderer/vulkan/vulkan_lightmap.c @@ -164,9 +164,10 @@ Vulkan_BuildLightMap (msurface_t *surf, vulkan_ctx_t *ctx) surf->cached_light[maps] = scale; // 8.8 fraction out = block; for (i = 0; i < smax * tmax; i++) { - *out++ += *lightmap++ * scale / 256.0; - *out++ += *lightmap++ * scale / 256.0; - *out++ += *lightmap++ * scale / 256.0; + *out++ += *lightmap++ * scale / 65536.0; + *out++ += *lightmap++ * scale / 65536.0; + *out++ += *lightmap++ * scale / 65536.0; + *out++ = 1; } } } diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index a35498fef..295d1a89d 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -92,7 +92,7 @@ Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, if (alpha) { while (count-- > 0) { byte pix = *src++; - const byte *col = palette + pix; + const byte *col = palette + pix * 3; *dst++ = *col++; *dst++ = *col++; *dst++ = *col++; @@ -101,7 +101,7 @@ Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, } else { while (count-- > 0) { byte pix = *src++; - const byte *col = palette + pix; + const byte *col = palette + pix * 3; *dst++ = *col++; *dst++ = *col++; *dst++ = *col++; From f96d7109af39e5b1f5bf0becd197d70ccc9c3dbc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 22 Jan 2021 02:13:58 +0900 Subject: [PATCH 271/435] [vulkan] Fix a pure warning Need to do more testing with optimized builds, but... --- include/QF/Vulkan/scrap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/Vulkan/scrap.h b/include/QF/Vulkan/scrap.h index 80c95bd96..b4818d558 100644 --- a/include/QF/Vulkan/scrap.h +++ b/include/QF/Vulkan/scrap.h @@ -10,7 +10,7 @@ struct qfv_device_s; scrap_t *QFV_CreateScrap (struct qfv_device_s *device, int size, QFFormat format, struct qfv_stagebuf_s *stage); -size_t QFV_ScrapSize (scrap_t *scrap); +size_t QFV_ScrapSize (scrap_t *scrap) __attribute__((pure)); void QFV_ScrapClear (scrap_t *scrap); void QFV_DestroyScrap (scrap_t *scrap); VkImageView QFV_ScrapImageView (scrap_t *scrap) __attribute__((pure)); From 7e7b82086cf6384bebec038f9a8d7cacdd688b6c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 22 Jan 2021 02:18:39 +0900 Subject: [PATCH 272/435] [vulkan] Round up the staging buffer size Vulkan validation (quite rightly) doesn't like it when the flush range goes past the end of the buffer, but also doesn't like it when the flush range isn't cache-line aligned, so align the size of the buffer, too. --- include/QF/Vulkan/staging.h | 1 + libs/video/renderer/vulkan/staging.c | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/QF/Vulkan/staging.h b/include/QF/Vulkan/staging.h index aaac5d749..e8cf18ae7 100644 --- a/include/QF/Vulkan/staging.h +++ b/include/QF/Vulkan/staging.h @@ -17,6 +17,7 @@ typedef struct qfv_stagebuf_s { size_t num_packets;///< number of packets in array size_t next_packet;///< index of the next packet to be used size_t size; ///< actual size of the buffer + size_t atom_mask; ///< for flush size rounding size_t end; ///< effective end of the buffer due to early wrap size_t head; size_t tail; diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c index 68bf6a9aa..613422b2b 100644 --- a/libs/video/renderer/vulkan/staging.c +++ b/libs/video/renderer/vulkan/staging.c @@ -58,10 +58,13 @@ qfv_stagebuf_t * QFV_CreateStagingBuffer (qfv_device_t *device, size_t size, int num_packets, VkCommandPool cmdPool) { + size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; qfv_devfuncs_t *dfunc = device->funcs; qfv_stagebuf_t *stage = malloc (sizeof (qfv_stagebuf_t) + num_packets * sizeof (qfv_packet_t)); + stage->atom_mask = atom - 1; + size = (size + stage->atom_mask) & ~stage->atom_mask; stage->device = device; stage->buffer = QFV_CreateBuffer (device, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); @@ -119,9 +122,8 @@ QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size) qfv_device_t *device = stage->device; qfv_devfuncs_t *dfunc = device->funcs; - size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; - offset &= ~(atom - 1); - size = (size + atom - 1) & ~ (atom - 1); + offset &= ~stage->atom_mask; + size = (size + stage->atom_mask) & ~stage->atom_mask; VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, stage->memory, offset, size From c75568c1cf11c9c1ea457bf95c72cdbb5fb0ba47 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 22 Jan 2021 02:20:32 +0900 Subject: [PATCH 273/435] [vulkan] Get wall rendering partially working Many surfaces are missing (I suspect it's due to transform stage management in the index emitter), and currently only the light maps are rendered (still not binding the correct textures), but the basics are working. --- libs/video/renderer/vulkan/qfpipeline.plist | 2 +- libs/video/renderer/vulkan/quakebsp.frag | 5 +++-- libs/video/renderer/vulkan/quakebsp.vert | 2 +- libs/video/renderer/vulkan/scrap.c | 2 +- libs/video/renderer/vulkan/vulkan_bsp.c | 20 ++++++++++++++++++++ libs/video/renderer/vulkan/vulkan_main.c | 7 ++++--- libs/video/renderer/vulkan/vulkan_matrices.c | 6 +++--- 7 files changed, 33 insertions(+), 11 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 094f49948..9b0a6a1d7 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -195,7 +195,7 @@ location = 1; binding = 0; format = r32g32b32a32_sfloat; - offset = 8; + offset = 16; }, ); }; diff --git a/libs/video/renderer/vulkan/quakebsp.frag b/libs/video/renderer/vulkan/quakebsp.frag index 21c26dfaa..d79408bf9 100644 --- a/libs/video/renderer/vulkan/quakebsp.frag +++ b/libs/video/renderer/vulkan/quakebsp.frag @@ -115,10 +115,11 @@ main (void) } else { c = texture (Texture, t_st); }*/ + c = texture (Texture, t_st); if (doLight) { c *= texture (Lightmap, l_st); } c += texture (Glowmap, t_st); - - frag_color = vec4(t_st, 1, 1);//fogBlend (c); + c = texture (Lightmap, l_st); + frag_color = c;//fogBlend (c); } diff --git a/libs/video/renderer/vulkan/quakebsp.vert b/libs/video/renderer/vulkan/quakebsp.vert index bb9e87e4a..efc03bac8 100644 --- a/libs/video/renderer/vulkan/quakebsp.vert +++ b/libs/video/renderer/vulkan/quakebsp.vert @@ -20,6 +20,6 @@ void main (void) { gl_Position = Projection * (View * (Model * vertex)); - direction = (Sky * vertex).xyz; + direction = vertex.xyz;//(Sky * vertex).xyz; tl_st = tl_uv; } diff --git a/libs/video/renderer/vulkan/scrap.c b/libs/video/renderer/vulkan/scrap.c index bc5efeda5..27c2ea3bd 100644 --- a/libs/video/renderer/vulkan/scrap.c +++ b/libs/video/renderer/vulkan/scrap.c @@ -270,7 +270,7 @@ QFV_SubpicBatch (subpic_t *subpic, qfv_stagebuf_t *stage) dest = QFV_PacketExtend (scrap->packet, size); } if (!dest) { - printf ("could not get space for update\n"); + printf ("scrap: could not get space for update\n"); return 0; } } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index b0b4c2162..18e7d2c49 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -59,6 +59,7 @@ #include "QF/Vulkan/command.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" #include "QF/Vulkan/scrap.h" #include "QF/Vulkan/staging.h" @@ -450,9 +451,13 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) } } + size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; + size_t atom_mask = atom - 1; size_t frames = bctx->frames.size; size_t index_buffer_size = index_count * frames * sizeof (uint32_t); size_t vertex_buffer_size = vertex_count * sizeof (bspvert_t); + + index_buffer_size = (index_buffer_size + atom_mask) & ~atom_mask; stage = QFV_CreateStagingBuffer (device, vertex_buffer_size, 1, ctx->cmdpool); qfv_packet_t *packet = QFV_PacketAcquire (stage); @@ -1144,6 +1149,21 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) tex->elechain_tail = &tex->elechain; } bsp_end (ctx); + + size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; + size_t atom_mask = atom - 1; + size_t offset = bframe->index_offset; + size_t size = bframe->index_count * sizeof (uint32_t); + + offset &= ~atom_mask; + size = (size + atom_mask) & ~atom_mask; + + //FIXME this needs to come at the end of the frame after all passes + VkMappedMemoryRange range = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + bctx->index_memory, offset, size + }; + dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); } void diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index 1e1913de9..f31558e7b 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -78,7 +78,8 @@ setup_frame (vulkan_ctx_t *ctx) static void setup_view (vulkan_ctx_t *ctx) { - float *mat = ctx->matrices.view_3d; + mat4_t mat; + float *view = ctx->matrices.view_3d; static mat4_t z_up = { 0, 0, -1, 0, -1, 0, 0, 0, @@ -98,11 +99,11 @@ setup_view (vulkan_ctx_t *ctx) VectorCopy (vup, mat + 8); mat[15] = 1; Mat4Transpose (mat, mat);//AngleVectors gives the transpose of what we want - Mat4Mult (z_up, mat, glsl_view); + Mat4Mult (z_up, mat, view); Mat4Identity (mat); VectorNegate (r_refdef.vieworg, mat + 12); - Mat4Mult (glsl_view, mat, glsl_view); + Mat4Mult (view, mat, view); } static void diff --git a/libs/video/renderer/vulkan/vulkan_matrices.c b/libs/video/renderer/vulkan/vulkan_matrices.c index 62eb16c1d..e1a1dd13e 100644 --- a/libs/video/renderer/vulkan/vulkan_matrices.c +++ b/libs/video/renderer/vulkan/vulkan_matrices.c @@ -96,14 +96,14 @@ persp_mat (float *proj, float xmin, float xmax, float ymin, float ymax, proj[12] = 0; proj[1] = 0; - proj[5] = (2 * neard) / (ymax - ymin); + proj[5] = -(2 * neard) / (ymax - ymin); proj[9] = (ymax + ymin) / (ymax - ymin); proj[13] = 0; proj[2] = 0; proj[6] = 0; - proj[10] = (fard + neard) / (neard - fard); - proj[14] = (2 * fard * neard) / (neard - fard); + proj[10] = (fard) / (neard - fard); + proj[14] = (fard * neard) / (neard - fard); proj[3] = 0; proj[7] = 0; From 55badea1aedc30a1ae3a1b1cde45dad7fe9260bd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 22 Jan 2021 02:42:58 +0900 Subject: [PATCH 274/435] [vulkan] Reset model transform for world surfaces Fixes the misplaced walls. --- libs/video/renderer/vulkan/vulkan_bsp.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 18e7d2c49..fe7c001f4 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -67,6 +67,13 @@ #include "vid_vulkan.h" #include "vkparse.h" +static float identity[] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, +}; + #define ALLOC_CHUNK 64 typedef struct bsppoly_s { @@ -764,6 +771,10 @@ draw_elechain (elechain_t *ec, VkPipelineLayout layout, qfv_devfuncs_t *dfunc, if (ec->transform) { dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 16 * sizeof (float), ec->transform); + } else { + //FIXME should cache current transform + dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_VERTEX_BIT, + 0, 16 * sizeof (float), identity); } for (el = ec->elements; el; el = el->next) { //FIXME check if these are contiguous and if so merge into one @@ -1085,12 +1096,6 @@ build_tex_elechain (vulktex_t *tex, bspctx_t *bctx, bspframe_t *bframe) void Vulkan_DrawWorld (vulkan_ctx_t *ctx) { - static float identity[] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, - }; qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; bspctx_t *bctx = ctx->bsp_context; From c016ad9f5586d520e01546709047c5cbff5559cc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 22 Jan 2021 13:08:33 +0900 Subject: [PATCH 275/435] [vulkan] Ignore light map alpha Needed to use an rgba format to use floats (and optimal layout), but having to set the alpha to 1 even for full-dark luxels is not very efficient. Better to just ignore the alpha in the shader. Fixes the occasional transparent surface in shadowed areas. --- libs/video/renderer/vulkan/quakebsp.frag | 4 ++-- libs/video/renderer/vulkan/vulkan_lightmap.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/video/renderer/vulkan/quakebsp.frag b/libs/video/renderer/vulkan/quakebsp.frag index d79408bf9..916581292 100644 --- a/libs/video/renderer/vulkan/quakebsp.frag +++ b/libs/video/renderer/vulkan/quakebsp.frag @@ -117,9 +117,9 @@ main (void) }*/ c = texture (Texture, t_st); if (doLight) { - c *= texture (Lightmap, l_st); + c *= vec4 (texture (Lightmap, l_st).xyz, 1); } c += texture (Glowmap, t_st); - c = texture (Lightmap, l_st); + c = vec4(texture (Lightmap, l_st).xyz, 1); frag_color = c;//fogBlend (c); } diff --git a/libs/video/renderer/vulkan/vulkan_lightmap.c b/libs/video/renderer/vulkan/vulkan_lightmap.c index 30118e484..6c74ab802 100644 --- a/libs/video/renderer/vulkan/vulkan_lightmap.c +++ b/libs/video/renderer/vulkan/vulkan_lightmap.c @@ -167,7 +167,7 @@ Vulkan_BuildLightMap (msurface_t *surf, vulkan_ctx_t *ctx) *out++ += *lightmap++ * scale / 65536.0; *out++ += *lightmap++ * scale / 65536.0; *out++ += *lightmap++ * scale / 65536.0; - *out++ = 1; + out++; } } } From baf25f089107292f707b6357be91e4aa7640a3b0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 22 Jan 2021 15:22:04 +0900 Subject: [PATCH 276/435] Document the ring buffer macros --- include/QF/ringbuffer.h | 88 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/include/QF/ringbuffer.h b/include/QF/ringbuffer.h index cc289640e..3ec4a3407 100644 --- a/include/QF/ringbuffer.h +++ b/include/QF/ringbuffer.h @@ -28,6 +28,16 @@ #ifndef __QF_ringbuffer_h #define __QF_ringbuffer_h +/** Type declaration for a type-safe ring buffer. + * + * While not in itself thread-safe, the buffer is designed (and tested) to be + * used in a threaded environment using sutable locking mechanisms. + * + * \param type The type of data element stored in the ring buffer. + * \param size The number of objects in the ring buffer. Note that the + * actual capacity of the buffer is `size - 1` due to the + * way ring buffers work. + */ #define RING_BUFFER(type, size) \ struct { \ type buffer[size]; \ @@ -40,16 +50,46 @@ sizeof (rb->buffer) / sizeof (rb->buffer[0]); \ }) +/** Return the amount of space available for writing in the ring buffer. + * + * Use this to know how much data can be written (RB_WRITE_DATA()), or just + * to see if any space is available. + * + * \note Does NOT affect buffer state. + * + * \param ring_buffer The ring buffer to check for available space. + */ #define RB_SPACE_AVAILABLE(ring_buffer) \ ({ __auto_type rb = &(ring_buffer); \ (rb->tail + RB_buffer_size(rb) - rb->head - 1) % RB_buffer_size(rb);\ }) +/** Return the number of objects available in the ring buffer. + * + * Use this to know how much data can be read (RB_READ_DATA()) or discarded + * (RB_DROP_DATA()), or just to see if any data is available. + * + * \note Does NOT affect buffer state. + * + * \param ring_buffer The ring buffer to check for available data. + */ #define RB_DATA_AVAILABLE(ring_buffer) \ ({ __auto_type rb = &(ring_buffer); \ (rb->head + RB_buffer_size (rb) - rb->tail) % RB_buffer_size (rb); \ }) +/** Write \a count objects from \a data to the buffer, wrapping if necessary. + * + * \note Affects buffer state (advances the head). + * + * \note Does NOT check that the space is available. It is the caller's + * responsitiblity to do so using RB_SPACE_AVAILABLE(). + * + * \param ring_buffer The ring buffer to which the data will be written. + * \param data Pointer to the data to be copied into the ring buffer. + * \param count unsigned int. The number of objects to copy from + * \a data + */ #define RB_WRITE_DATA(ring_buffer, data, count) \ ({ __auto_type rb = &(ring_buffer); \ const typeof (rb->buffer[0]) *d = (data); \ @@ -66,6 +106,19 @@ memcpy (rb->buffer + h, d, c * sizeof (rb->buffer[0])); \ }) +/** Read \a count objects from the buffer to \a data, wrapping if necessary. + * + * \note Affects buffer state (advances the tail). + * + * \note Does NOT check that the data is available. It is the caller's + * responsitiblity to do so using RB_DATA_AVAILABLE(). + * + * \param ring_buffer The ring buffer from which the data will be read. + * \param data Pointer to the location into which data will be copied + * from the ring buffer. + * \param count unsigned int. The number of objects to copy from + * the buffer into \a data + */ #define RB_READ_DATA(ring_buffer, data, count) \ ({ __auto_type rb = &(ring_buffer); \ typeof (&rb->buffer[0]) d = (data); \ @@ -83,6 +136,17 @@ rb->tail = (t + oc) % RB_buffer_size (rb); \ }) +/** Discard \a count objects from the ring buffer. + * + * \note Affects buffer state (advances the tail). + * + * \note Does NOT check that the data is available. It is the caller's + * responsitiblity to do so using RB_DATA_AVAILABLE(). + * + * \param ring_buffer The ring buffer from which the objects will be + * discarded. + * \param count The number of objects to discard. + */ #define RB_DROP_DATA(ring_buffer, count) \ ({ __auto_type rb = &(ring_buffer); \ unsigned c = (count); \ @@ -90,11 +154,35 @@ rb->tail = (t + c) % RB_buffer_size (rb); \ }) +/** Read a single item from the buffer without affecting buffer state. + * + * \note Does NOT affect buffer state. + * + * \note Does NOT check that the data is available. It is the caller's + * responsitiblity to do so using RB_DATA_AVAILABLE(). + * + * \param ring_buffer The ring buffer from which to read the object. + * \param ahead The tail-relative index of the object to read from + * the buffer. Valid range is 0 to + * `RB_DATA_AVAILABLE() - 1` + */ #define RB_PEEK_DATA(ring_buffer, ahead) \ ({ __auto_type rb = &(ring_buffer); \ rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)]; \ }) +/** WRite a single item to the buffer without affecting buffer state. + * + * \note Does NOT affect buffer state. + * + * \note Does NOT check that the data is available. It is the caller's + * responsitiblity to do so using RB_DATA_AVAILABLE(). + * + * \param ring_buffer The ring buffer from which to read the object. + * \param ahead The tail-relative index of the buffer object to write. + * Valid range is 0 to `RB_DATA_AVAILABLE() - 1` + * \param data The data to write to the buffer. + */ #define RB_POKE_DATA(ring_buffer, ahead, data) \ ({ __auto_type rb = &(ring_buffer); \ rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)] = (data); \ From 07b869d1bfb12d8127ae1f0cb867de9e035d30c6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 22 Jan 2021 15:23:04 +0900 Subject: [PATCH 277/435] Fix some doxygen warnings --- doc/quakeforge.dox.conf.in | 7 ------- include/snd_internal.h | 3 ++- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/doc/quakeforge.dox.conf.in b/doc/quakeforge.dox.conf.in index 1e925e354..3d22be413 100644 --- a/doc/quakeforge.dox.conf.in +++ b/doc/quakeforge.dox.conf.in @@ -1116,13 +1116,6 @@ CLANG_DATABASE_PATH = ALPHABETICAL_INDEX = YES -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 4 - # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored diff --git a/include/snd_internal.h b/include/snd_internal.h index ca4dc76c6..7978c4307 100644 --- a/include/snd_internal.h +++ b/include/snd_internal.h @@ -58,7 +58,8 @@ typedef struct sfxstream_s sfxstream_t; \param buffer sound data \param count number of frames to paint */ -typedef void sfxpaint_t (int, channel_t *, float *, unsigned); +typedef void sfxpaint_t (int offset, channel_t *ch, float *buffer, + unsigned count); /** Represent a sound sample in the mixer. */ From e6704b85e107fc00457759b04e67032c0c2ab64e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 22 Jan 2021 18:29:35 +0900 Subject: [PATCH 278/435] Make RB_PEEK_DATA return the address of the data This makes it a little more generally useful. --- include/QF/ringbuffer.h | 9 +- ruamoko/qwaq/builtins/curses.c | 154 ++++++++++++++++----------------- ruamoko/qwaq/builtins/input.c | 2 +- 3 files changed, 83 insertions(+), 82 deletions(-) diff --git a/include/QF/ringbuffer.h b/include/QF/ringbuffer.h index 3ec4a3407..4c7e95e74 100644 --- a/include/QF/ringbuffer.h +++ b/include/QF/ringbuffer.h @@ -154,21 +154,22 @@ rb->tail = (t + c) % RB_buffer_size (rb); \ }) -/** Read a single item from the buffer without affecting buffer state. +/** Access a single item from the buffer without affecting buffer state. * * \note Does NOT affect buffer state. * * \note Does NOT check that the data is available. It is the caller's * responsitiblity to do so using RB_DATA_AVAILABLE(). * - * \param ring_buffer The ring buffer from which to read the object. - * \param ahead The tail-relative index of the object to read from + * \param ring_buffer The ring buffer from which to access the object. + * \param ahead The tail-relative index of the object to access from * the buffer. Valid range is 0 to * `RB_DATA_AVAILABLE() - 1` + * \return Address of the accessed element */ #define RB_PEEK_DATA(ring_buffer, ahead) \ ({ __auto_type rb = &(ring_buffer); \ - rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)]; \ + &rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)]; \ }) /** WRite a single item to the buffer without affecting buffer state. diff --git a/ruamoko/qwaq/builtins/curses.c b/ruamoko/qwaq/builtins/curses.c index 4f2044cf7..c54721bca 100644 --- a/ruamoko/qwaq/builtins/curses.c +++ b/ruamoko/qwaq/builtins/curses.c @@ -273,7 +273,7 @@ qwaq_wait_result (qwaq_resources_t *res, int *result, int cmd, unsigned len) { pthread_mutex_lock (&res->results_cond.mut); while (RB_DATA_AVAILABLE (res->results) < len - || RB_PEEK_DATA (res->results, 0) != cmd) { + || *RB_PEEK_DATA (res->results, 0) != cmd) { pthread_cond_wait (&res->results_cond.rcond, &res->results_cond.mut); } @@ -285,7 +285,7 @@ qwaq_wait_result (qwaq_resources_t *res, int *result, int cmd, unsigned len) static void cmd_syncprint (qwaq_resources_t *res) { - int string_id = RB_PEEK_DATA (res->command_queue, 2); + int string_id = *RB_PEEK_DATA (res->command_queue, 2); Sys_Printf ("%s\n", res->strings[string_id].str); release_string (res, string_id); @@ -294,10 +294,10 @@ cmd_syncprint (qwaq_resources_t *res) static void cmd_newwin (qwaq_resources_t *res) { - int xpos = RB_PEEK_DATA (res->command_queue, 2); - int ypos = RB_PEEK_DATA (res->command_queue, 3); - int xlen = RB_PEEK_DATA (res->command_queue, 4); - int ylen = RB_PEEK_DATA (res->command_queue, 5); + int xpos = *RB_PEEK_DATA (res->command_queue, 2); + int ypos = *RB_PEEK_DATA (res->command_queue, 3); + int xlen = *RB_PEEK_DATA (res->command_queue, 4); + int ylen = *RB_PEEK_DATA (res->command_queue, 5); window_t *window = window_new (res); window->win = newwin (ylen, xlen, ypos, xpos); @@ -311,7 +311,7 @@ cmd_newwin (qwaq_resources_t *res) static void cmd_delwin (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); window_t *window = get_window (res, __FUNCTION__, window_id); delwin (window->win); @@ -321,7 +321,7 @@ cmd_delwin (qwaq_resources_t *res) static void cmd_getwrect (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); int xpos, ypos; int xlen, ylen; @@ -339,7 +339,7 @@ cmd_getwrect (qwaq_resources_t *res) static void cmd_new_panel (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); window_t *window = get_window (res, __FUNCTION__, window_id); panel_t *panel = panel_new (res); @@ -354,7 +354,7 @@ cmd_new_panel (qwaq_resources_t *res) static void cmd_del_panel (qwaq_resources_t *res) { - int panel_id = RB_PEEK_DATA (res->command_queue, 2); + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); panel_t *panel = get_panel (res, __FUNCTION__, panel_id); del_panel (panel->panel); @@ -364,7 +364,7 @@ cmd_del_panel (qwaq_resources_t *res) static void cmd_hide_panel (qwaq_resources_t *res) { - int panel_id = RB_PEEK_DATA (res->command_queue, 2); + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); panel_t *panel = get_panel (res, __FUNCTION__, panel_id); hide_panel (panel->panel); @@ -373,7 +373,7 @@ cmd_hide_panel (qwaq_resources_t *res) static void cmd_show_panel (qwaq_resources_t *res) { - int panel_id = RB_PEEK_DATA (res->command_queue, 2); + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); panel_t *panel = get_panel (res, __FUNCTION__, panel_id); show_panel (panel->panel); @@ -382,7 +382,7 @@ cmd_show_panel (qwaq_resources_t *res) static void cmd_top_panel (qwaq_resources_t *res) { - int panel_id = RB_PEEK_DATA (res->command_queue, 2); + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); panel_t *panel = get_panel (res, __FUNCTION__, panel_id); top_panel (panel->panel); @@ -391,7 +391,7 @@ cmd_top_panel (qwaq_resources_t *res) static void cmd_bottom_panel (qwaq_resources_t *res) { - int panel_id = RB_PEEK_DATA (res->command_queue, 2); + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); panel_t *panel = get_panel (res, __FUNCTION__, panel_id); bottom_panel (panel->panel); @@ -400,9 +400,9 @@ cmd_bottom_panel (qwaq_resources_t *res) static void cmd_move_panel (qwaq_resources_t *res) { - int panel_id = RB_PEEK_DATA (res->command_queue, 2); - int x = RB_PEEK_DATA (res->command_queue, 3); - int y = RB_PEEK_DATA (res->command_queue, 4); + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); panel_t *panel = get_panel (res, __FUNCTION__, panel_id); move_panel (panel->panel, y, x); @@ -411,7 +411,7 @@ cmd_move_panel (qwaq_resources_t *res) static void cmd_panel_window (qwaq_resources_t *res) { - int panel_id = RB_PEEK_DATA (res->command_queue, 2); + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); panel_t *panel = get_panel (res, __FUNCTION__, panel_id); @@ -423,8 +423,8 @@ cmd_panel_window (qwaq_resources_t *res) static void cmd_replace_panel (qwaq_resources_t *res) { - int panel_id = RB_PEEK_DATA (res->command_queue, 2); - int window_id = RB_PEEK_DATA (res->command_queue, 3); + int panel_id = *RB_PEEK_DATA (res->command_queue, 2); + int window_id = *RB_PEEK_DATA (res->command_queue, 3); panel_t *panel = get_panel (res, __FUNCTION__, panel_id); window_t *window = get_window (res, __FUNCTION__, window_id); @@ -447,10 +447,10 @@ cmd_doupdate (qwaq_resources_t *res) static void cmd_mvwaddstr (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); - int x = RB_PEEK_DATA (res->command_queue, 3); - int y = RB_PEEK_DATA (res->command_queue, 4); - int string_id = RB_PEEK_DATA (res->command_queue, 5); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); + int string_id = *RB_PEEK_DATA (res->command_queue, 5); window_t *window = get_window (res, __FUNCTION__, window_id); mvwaddstr (window->win, y, x, res->strings[string_id].str); @@ -460,8 +460,8 @@ cmd_mvwaddstr (qwaq_resources_t *res) static void cmd_waddstr (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); - int string_id = RB_PEEK_DATA (res->command_queue, 3); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int string_id = *RB_PEEK_DATA (res->command_queue, 3); window_t *window = get_window (res, __FUNCTION__, window_id); waddstr (window->win, res->strings[string_id].str); @@ -471,10 +471,10 @@ cmd_waddstr (qwaq_resources_t *res) static void cmd_mvwaddch (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); - int x = RB_PEEK_DATA (res->command_queue, 3); - int y = RB_PEEK_DATA (res->command_queue, 4); - int ch = RB_PEEK_DATA (res->command_queue, 5); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); + int ch = *RB_PEEK_DATA (res->command_queue, 5); window_t *window = get_window (res, __FUNCTION__, window_id); mvwaddch (window->win, y, x, ch); @@ -483,8 +483,8 @@ cmd_mvwaddch (qwaq_resources_t *res) static void cmd_waddch (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); - int ch = RB_PEEK_DATA (res->command_queue, 3); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int ch = *RB_PEEK_DATA (res->command_queue, 3); window_t *window = get_window (res, __FUNCTION__, window_id); waddch (window->win, ch); @@ -493,7 +493,7 @@ cmd_waddch (qwaq_resources_t *res) static void cmd_wrefresh (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); window_t *window = get_window (res, __FUNCTION__, window_id); wrefresh (window->win); @@ -502,9 +502,9 @@ cmd_wrefresh (qwaq_resources_t *res) static void cmd_init_pair (qwaq_resources_t *res) { - int pair = RB_PEEK_DATA (res->command_queue, 2); - int f = RB_PEEK_DATA (res->command_queue, 3); - int b = RB_PEEK_DATA (res->command_queue, 4); + int pair = *RB_PEEK_DATA (res->command_queue, 2); + int f = *RB_PEEK_DATA (res->command_queue, 3); + int b = *RB_PEEK_DATA (res->command_queue, 4); init_pair (pair, f, b); } @@ -512,8 +512,8 @@ cmd_init_pair (qwaq_resources_t *res) static void cmd_wbkgd (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); - int ch = RB_PEEK_DATA (res->command_queue, 3); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int ch = *RB_PEEK_DATA (res->command_queue, 3); window_t *window = get_window (res, __FUNCTION__, window_id); wbkgd (window->win, ch); @@ -522,7 +522,7 @@ cmd_wbkgd (qwaq_resources_t *res) static void cmd_werase (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); window_t *window = get_window (res, __FUNCTION__, window_id); werase (window->win); @@ -531,8 +531,8 @@ cmd_werase (qwaq_resources_t *res) static void cmd_scrollok (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); - int flag = RB_PEEK_DATA (res->command_queue, 3); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int flag = *RB_PEEK_DATA (res->command_queue, 3); window_t *window = get_window (res, __FUNCTION__, window_id); scrollok (window->win, flag); @@ -541,8 +541,8 @@ cmd_scrollok (qwaq_resources_t *res) static void cmd_move (qwaq_resources_t *res) { - int x = RB_PEEK_DATA (res->command_queue, 2); - int y = RB_PEEK_DATA (res->command_queue, 3); + int x = *RB_PEEK_DATA (res->command_queue, 2); + int y = *RB_PEEK_DATA (res->command_queue, 3); move (y, x); } @@ -550,7 +550,7 @@ cmd_move (qwaq_resources_t *res) static void cmd_curs_set (qwaq_resources_t *res) { - int visibility = RB_PEEK_DATA (res->command_queue, 2); + int visibility = *RB_PEEK_DATA (res->command_queue, 2); curs_set (visibility); } @@ -558,15 +558,15 @@ cmd_curs_set (qwaq_resources_t *res) static void cmd_wborder (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); - int ls = RB_PEEK_DATA (res->command_queue, 3); - int rs = RB_PEEK_DATA (res->command_queue, 4); - int ts = RB_PEEK_DATA (res->command_queue, 5); - int bs = RB_PEEK_DATA (res->command_queue, 6); - int tl = RB_PEEK_DATA (res->command_queue, 7); - int tr = RB_PEEK_DATA (res->command_queue, 8); - int bl = RB_PEEK_DATA (res->command_queue, 9); - int br = RB_PEEK_DATA (res->command_queue, 10); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int ls = *RB_PEEK_DATA (res->command_queue, 3); + int rs = *RB_PEEK_DATA (res->command_queue, 4); + int ts = *RB_PEEK_DATA (res->command_queue, 5); + int bs = *RB_PEEK_DATA (res->command_queue, 6); + int tl = *RB_PEEK_DATA (res->command_queue, 7); + int tr = *RB_PEEK_DATA (res->command_queue, 8); + int bl = *RB_PEEK_DATA (res->command_queue, 9); + int br = *RB_PEEK_DATA (res->command_queue, 10); window_t *window = get_window (res, __FUNCTION__, window_id); wborder (window->win, ls, rs, ts, bs, tl, tr, bl, br); @@ -575,11 +575,11 @@ cmd_wborder (qwaq_resources_t *res) static void cmd_mvwblit_line (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); - int x = RB_PEEK_DATA (res->command_queue, 3); - int y = RB_PEEK_DATA (res->command_queue, 4); - int chs_id = RB_PEEK_DATA (res->command_queue, 5); - int len = RB_PEEK_DATA (res->command_queue, 6); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); + int chs_id = *RB_PEEK_DATA (res->command_queue, 5); + int len = *RB_PEEK_DATA (res->command_queue, 6); int *chs = (int *) res->strings[chs_id].str; int save_x; int save_y; @@ -598,9 +598,9 @@ cmd_mvwblit_line (qwaq_resources_t *res) static void cmd_wresize (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); - int width = RB_PEEK_DATA (res->command_queue, 3); - int height = RB_PEEK_DATA (res->command_queue, 4); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int width = *RB_PEEK_DATA (res->command_queue, 3); + int height = *RB_PEEK_DATA (res->command_queue, 4); window_t *window = get_window (res, __FUNCTION__, window_id); wresize (window->win, height, width); @@ -609,8 +609,8 @@ cmd_wresize (qwaq_resources_t *res) static void cmd_resizeterm (qwaq_resources_t *res) { - int width = RB_PEEK_DATA (res->command_queue, 2); - int height = RB_PEEK_DATA (res->command_queue, 3); + int width = *RB_PEEK_DATA (res->command_queue, 2); + int height = *RB_PEEK_DATA (res->command_queue, 3); resizeterm (height, width); } @@ -618,11 +618,11 @@ cmd_resizeterm (qwaq_resources_t *res) static void cmd_mvwhline (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); - int x = RB_PEEK_DATA (res->command_queue, 3); - int y = RB_PEEK_DATA (res->command_queue, 4); - int ch = RB_PEEK_DATA (res->command_queue, 5); - int n = RB_PEEK_DATA (res->command_queue, 6); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); + int ch = *RB_PEEK_DATA (res->command_queue, 5); + int n = *RB_PEEK_DATA (res->command_queue, 6); window_t *window = get_window (res, __FUNCTION__, window_id); mvwhline (window->win, y, x, ch, n); @@ -631,11 +631,11 @@ cmd_mvwhline (qwaq_resources_t *res) static void cmd_mvwvline (qwaq_resources_t *res) { - int window_id = RB_PEEK_DATA (res->command_queue, 2); - int x = RB_PEEK_DATA (res->command_queue, 3); - int y = RB_PEEK_DATA (res->command_queue, 4); - int ch = RB_PEEK_DATA (res->command_queue, 5); - int n = RB_PEEK_DATA (res->command_queue, 6); + int window_id = *RB_PEEK_DATA (res->command_queue, 2); + int x = *RB_PEEK_DATA (res->command_queue, 3); + int y = *RB_PEEK_DATA (res->command_queue, 4); + int ch = *RB_PEEK_DATA (res->command_queue, 5); + int n = *RB_PEEK_DATA (res->command_queue, 6); window_t *window = get_window (res, __FUNCTION__, window_id); mvwvline (window->win, y, x, ch, n); @@ -645,13 +645,13 @@ static void dump_command (qwaq_resources_t *res, int len) { if (0) { - qwaq_commands cmd = RB_PEEK_DATA (res->command_queue, 0); + qwaq_commands cmd = *RB_PEEK_DATA (res->command_queue, 0); Sys_Printf ("%s[%d]", qwaq_command_names[cmd], len); if (cmd == qwaq_cmd_syncprint) { Sys_Printf (" "); } else { for (int i = 2; i < len; i++) { - Sys_Printf (" %d", RB_PEEK_DATA (res->command_queue, i)); + Sys_Printf (" %d", *RB_PEEK_DATA (res->command_queue, i)); } Sys_Printf ("\n"); } @@ -692,10 +692,10 @@ process_commands (qwaq_resources_t *res) // as the mutex is not released until after the data has been written to // the buffer. while ((avail = RB_DATA_AVAILABLE (res->command_queue)) >= 2 - && avail >= (len = RB_PEEK_DATA (res->command_queue, 1))) { + && avail >= (len = *RB_PEEK_DATA (res->command_queue, 1))) { pthread_mutex_unlock (&res->command_cond.mut); dump_command (res, len); - qwaq_commands cmd = RB_PEEK_DATA (res->command_queue, 0); + qwaq_commands cmd = *RB_PEEK_DATA (res->command_queue, 0); switch (cmd) { case qwaq_cmd_syncprint: cmd_syncprint (res); diff --git a/ruamoko/qwaq/builtins/input.c b/ruamoko/qwaq/builtins/input.c index ce2caec46..ce47b1914 100644 --- a/ruamoko/qwaq/builtins/input.c +++ b/ruamoko/qwaq/builtins/input.c @@ -185,7 +185,7 @@ qwaq_add_event (qwaq_resources_t *res, qwaq_event_t *event) pthread_mutex_lock (&res->event_cond.mut); unsigned last = RB_DATA_AVAILABLE (res->event_queue); if (event->what == qe_mousemove && last > 1 - && RB_PEEK_DATA(res->event_queue, last - 1).what == qe_mousemove) { + && RB_PEEK_DATA(res->event_queue, last - 1)->what == qe_mousemove) { RB_POKE_DATA(res->event_queue, last - 1, *event); merged = 1; pthread_cond_broadcast (&res->event_cond.rcond); From 328a529a94d8153e6cd85e2126c627c34f06477d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Jan 2021 11:56:45 +0900 Subject: [PATCH 279/435] Create RB_ACQUIRE and RB_RELEASE RB_RELEASE is actually RB_DROP_DATA renamed, but RB_ACQUIRE and RB_RELEASE work well when working with more structured ring buffer contents. --- include/QF/ringbuffer.h | 28 ++++++++++++++++++++++++---- ruamoko/qwaq/builtins/curses.c | 2 +- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/include/QF/ringbuffer.h b/include/QF/ringbuffer.h index 4c7e95e74..ac339ea70 100644 --- a/include/QF/ringbuffer.h +++ b/include/QF/ringbuffer.h @@ -52,8 +52,8 @@ /** Return the amount of space available for writing in the ring buffer. * - * Use this to know how much data can be written (RB_WRITE_DATA()), or just - * to see if any space is available. + * Use this to know how much data can be written (RB_WRITE_DATA()) or acquired + * (RB_ACQUIRE()), or just to see if any space is available. * * \note Does NOT affect buffer state. * @@ -67,7 +67,7 @@ /** Return the number of objects available in the ring buffer. * * Use this to know how much data can be read (RB_READ_DATA()) or discarded - * (RB_DROP_DATA()), or just to see if any data is available. + * (RB_RELEASE()), or just to see if any data is available. * * \note Does NOT affect buffer state. * @@ -106,6 +106,26 @@ memcpy (rb->buffer + h, d, c * sizeof (rb->buffer[0])); \ }) +/** Acquire \a count objects from the buffer, wrapping if necessary. + * + * \note Affects buffer state (advances the head). + * + * \note Does NOT check that the space is available. It is the caller's + * responsitiblity to do so using RB_SPACE_AVAILABLE(). + * + * \param ring_buffer The ring buffer to which the data will be written. + * \param count unsigned int. The number of objects to copy from + * \a data. + * \return Address of the first object acquired. + */ +#define RB_ACQUIRE(ring_buffer, count) \ + ({ __auto_type rb = &(ring_buffer); \ + unsigned c = (count); \ + unsigned h = rb->head; \ + rb->head = (h + c) % RB_buffer_size (rb); \ + &rb->buffer[h]; \ + }) + /** Read \a count objects from the buffer to \a data, wrapping if necessary. * * \note Affects buffer state (advances the tail). @@ -147,7 +167,7 @@ * discarded. * \param count The number of objects to discard. */ -#define RB_DROP_DATA(ring_buffer, count) \ +#define RB_RELEASE(ring_buffer, count) \ ({ __auto_type rb = &(ring_buffer); \ unsigned c = (count); \ unsigned t = rb->tail; \ diff --git a/ruamoko/qwaq/builtins/curses.c b/ruamoko/qwaq/builtins/curses.c index c54721bca..0848158f7 100644 --- a/ruamoko/qwaq/builtins/curses.c +++ b/ruamoko/qwaq/builtins/curses.c @@ -795,7 +795,7 @@ process_commands (qwaq_resources_t *res) break; } pthread_mutex_lock (&res->command_cond.mut); - RB_DROP_DATA (res->command_queue, len); + RB_RELEASE (res->command_queue, len); pthread_cond_broadcast (&res->command_cond.wcond); // unlocked at top of top if there's more data, otherwise just after // the loop From c989c8a6b631bec3cb9440f7723938b710cd8a3e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Jan 2021 12:01:52 +0900 Subject: [PATCH 280/435] [vulkan] Rewrite staging buffer packet handling It now uses the ring buffer code I wrote for qwaq (and forgot about, oops) to handle the packets themselves, and the logic for allocating and freeing space from the buffer is a bit simpler and seems to be more reliable. The automated test is a bit of a joke now, though, but coming up with good tests for it... However, nq now cycles through the demos without obvious issue under the same conditions that caused the light map update code to segfault. --- include/QF/Vulkan/staging.h | 15 +- libs/models/brush/vulkan_model_brush.c | 2 +- libs/video/renderer/vulkan/staging.c | 202 +++++++------ .../video/renderer/vulkan/test/test-staging.c | 279 +++--------------- libs/video/renderer/vulkan/vulkan_bsp.c | 6 +- libs/video/renderer/vulkan/vulkan_draw.c | 2 +- .../video/renderer/vulkan/vulkan_vid_common.c | 2 +- 7 files changed, 159 insertions(+), 349 deletions(-) diff --git a/include/QF/Vulkan/staging.h b/include/QF/Vulkan/staging.h index e8cf18ae7..ee3678625 100644 --- a/include/QF/Vulkan/staging.h +++ b/include/QF/Vulkan/staging.h @@ -1,6 +1,8 @@ #ifndef __QF_Vulkan_staging_h #define __QF_Vulkan_staging_h +#include "QF/ringbuffer.h" + typedef struct qfv_packet_s { struct qfv_stagebuf_s *stage; ///< staging buffer that owns this packet VkCommandBuffer cmd; @@ -13,21 +15,18 @@ typedef struct qfv_stagebuf_s { struct qfv_device_s *device; VkBuffer buffer; VkDeviceMemory memory; - qfv_packet_t *packet; ///< array of packets for controlling access - size_t num_packets;///< number of packets in array - size_t next_packet;///< index of the next packet to be used - size_t size; ///< actual size of the buffer + RING_BUFFER(qfv_packet_t, 4) packets; ///< packets for controlling access size_t atom_mask; ///< for flush size rounding + size_t size; ///< actual size of the buffer size_t end; ///< effective end of the buffer due to early wrap - size_t head; - size_t tail; + size_t space_start;///< beginning of available space + size_t space_end; ///< end of available space void *data; } qfv_stagebuf_t; qfv_stagebuf_t *QFV_CreateStagingBuffer (struct qfv_device_s *device, - size_t size, int num_packets, - VkCommandPool cmdPool); + size_t size, VkCommandPool cmdPool); void QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage); void QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size); qfv_packet_t *QFV_PacketAcquire (qfv_stagebuf_t *stage); diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index e40a76e28..b64e8c11f 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -211,7 +211,7 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) memsize, 0); mctx->texture_memory = mem; - qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, memsize, 1, + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, memsize, ctx->cmdpool); qfv_packet_t *packet = QFV_PacketAcquire (stage); buffer = QFV_PacketExtend (packet, memsize); diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c index 613422b2b..836a08e5e 100644 --- a/libs/video/renderer/vulkan/staging.c +++ b/libs/video/renderer/vulkan/staging.c @@ -55,14 +55,13 @@ #include "vid_vulkan.h" qfv_stagebuf_t * -QFV_CreateStagingBuffer (qfv_device_t *device, size_t size, int num_packets, +QFV_CreateStagingBuffer (qfv_device_t *device, size_t size, VkCommandPool cmdPool) { size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; qfv_devfuncs_t *dfunc = device->funcs; - qfv_stagebuf_t *stage = malloc (sizeof (qfv_stagebuf_t) - + num_packets * sizeof (qfv_packet_t)); + qfv_stagebuf_t *stage = calloc (1, sizeof (qfv_stagebuf_t)); stage->atom_mask = atom - 1; size = (size + stage->atom_mask) & ~stage->atom_mask; stage->device = device; @@ -71,25 +70,23 @@ QFV_CreateStagingBuffer (qfv_device_t *device, size_t size, int num_packets, stage->memory = QFV_AllocBufferMemory (device, stage->buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, size, 0); - stage->packet = (qfv_packet_t *) (stage + 1); - stage->num_packets = num_packets; - stage->next_packet = 0; stage->size = size; stage->end = size; - stage->head = 0; - stage->tail = 0; dfunc->vkMapMemory (device->dev, stage->memory, 0, size, 0, &stage->data); QFV_BindBufferMemory (device, stage->buffer, stage->memory, 0); - __auto_type bufferset = QFV_AllocCommandBufferSet (num_packets, alloca); + int count = RB_buffer_size (&stage->packets); + + __auto_type bufferset = QFV_AllocCommandBufferSet (count, alloca); QFV_AllocateCommandBuffers (device, cmdPool, 0, bufferset); - for (int i = 0; i < num_packets; i++) { - stage->packet[i].stage = stage; - stage->packet[i].cmd = bufferset->a[i]; - stage->packet[i].fence = QFV_CreateFence (device, 1); - stage->packet[i].offset = 0; - stage->packet[i].length = 0; + for (int i = 0; i < count; i++) { + qfv_packet_t *packet = &stage->packets.buffer[i]; + packet->stage = stage; + packet->cmd = bufferset->a[i]; + packet->fence = QFV_CreateFence (device, 1); + packet->offset = 0; + packet->length = 0; } return stage; } @@ -100,14 +97,15 @@ QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage) qfv_device_t *device = stage->device; qfv_devfuncs_t *dfunc = device->funcs; - __auto_type fences = QFV_AllocFenceSet (stage->num_packets, alloca); - for (size_t i = 0; i < stage->num_packets; i++) { - fences->a[i] = stage->packet[i].fence; + int count = RB_buffer_size (&stage->packets); + __auto_type fences = QFV_AllocFenceSet (count, alloca); + for (int i = 0; i < count; i++) { + fences->a[i] = stage->packets.buffer[i].fence; } dfunc->vkWaitForFences (device->dev, fences->size, fences->a, VK_TRUE, - ~0ull); - for (size_t i = 0; i < stage->num_packets; i++) { - dfunc->vkDestroyFence (device->dev, stage->packet[i].fence, 0); + 500000000ull); + for (int i = 0; i < count; i++) { + dfunc->vkDestroyFence (device->dev, fences->a[i], 0); } dfunc->vkUnmapMemory (device->dev, stage->memory); @@ -132,44 +130,87 @@ QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size) } static void -advance_tail (qfv_stagebuf_t *stage, qfv_packet_t *packet) +release_space (qfv_stagebuf_t *stage, size_t offset, size_t length) { + if (stage->space_end != offset + && offset != 0 + && stage->space_end != stage->end) { + Sys_Error ("staging: out of sequence packet release"); + } + if (stage->space_end == stage->end) { + stage->space_end = 0; + stage->end = stage->size; + } + stage->space_end += length; +} + +static void * +acquire_space (qfv_packet_t *packet, size_t size) +{ + qfv_stagebuf_t *stage = packet->stage; qfv_device_t *device = stage->device; qfv_devfuncs_t *dfunc = device->funcs; - qfv_packet_t *start = packet; - - while (1) { - if ((size_t) (++packet - stage->packet) >= stage->num_packets) { - packet = stage->packet; + // clean up after any completed packets + while (RB_DATA_AVAILABLE (stage->packets) > 1) { + qfv_packet_t *p = RB_PEEK_DATA (stage->packets, 0); + if (dfunc->vkGetFenceStatus (device->dev, p->fence) != VK_SUCCESS) { + break; } - if (packet != start - && (dfunc->vkGetFenceStatus (device->dev, packet->fence) - == VK_SUCCESS)) { - if (packet->length == 0) { - continue; - } - if ((stage->tail == stage->end && packet->offset == 0) - || stage->tail == packet->offset) { - stage->tail = packet->offset + packet->length; - packet->length = 0; - if (stage->tail >= stage->end) { - stage->end = stage->size; - stage->tail = stage->size; - } - } - continue; - } - // Packets are always aquired in sequence and thus the first busy - // packet after the start packet marks the end of available space. - // Alternatively, there is only one packet and we've looped around - // back to the start packet. Must ensure the tail is updated - if (stage->tail >= stage->end && packet->offset == 0) { - stage->end = stage->size; - stage->tail = packet->offset; - } - break; + release_space (stage, p->offset, p->length); + RB_RELEASE (stage->packets, 1); } + + if (size > stage->size) { + // utterly impossible allocation + return 0; + } + + // if the staging buffer has been freed up and no data is assigned to the + // single existing packet, then ensure the packet starts at the beginning + // of the staging buffer in order to maximize the space available to it + // (some of the tests are redundant since if any space is assigned to a + // packet, the buffer cannot be fully freed up) + if (stage->space_end == stage->space_start + && RB_DATA_AVAILABLE (stage->packets) == 1 + && packet->length == 0) { + stage->space_end = 0; + stage->space_start = 0; + packet->offset = 0; + } + if (stage->space_start >= stage->space_end) { + // all the space to the actual end of the buffer is free + if (stage->space_start + size <= stage->size) { + void *data = (byte *) stage->data + stage->space_start; + stage->space_start += size; + return data; + } + // doesn't fit at the end of the buffer, try the beginning but only + // if the packet can be moved (no spaced has been allocated to it yet) + if (packet->length > 0) { + // can't move it + return 0; + } + // mark the unused end of the buffer such that it gets reclaimed + // properly when the preceeding packet is freed + stage->end = stage->space_start; + stage->space_start = 0; + packet->offset = 0; + } + while (stage->space_start + size > stage->space_end + && RB_DATA_AVAILABLE (stage->packets) > 1) { + packet = RB_PEEK_DATA (stage->packets, 0); + dfunc->vkWaitForFences (device->dev, 1, &packet->fence, VK_TRUE, + ~0ull); + release_space (stage, packet->offset, packet->length); + RB_RELEASE (stage->packets, 1); + } + if (stage->space_start + size > stage->space_end) { + return 0; + } + void *data = (byte *) stage->data + stage->space_start; + stage->space_start += size; + return data; } qfv_packet_t * @@ -177,16 +218,19 @@ QFV_PacketAcquire (qfv_stagebuf_t *stage) { qfv_device_t *device = stage->device; qfv_devfuncs_t *dfunc = device->funcs; - qfv_packet_t *packet = &stage->packet[stage->next_packet++]; - stage->next_packet %= stage->num_packets; - dfunc->vkWaitForFences (device->dev, 1, &packet->fence, VK_TRUE, ~0ull); - - advance_tail (stage, packet); - if (stage->head == stage->size) { - stage->head = 0; + qfv_packet_t *packet = 0; + if (!RB_SPACE_AVAILABLE (stage->packets)) { + // need to wait for a packet to become available + packet = RB_PEEK_DATA (stage->packets, 0); + dfunc->vkWaitForFences (device->dev, 1, &packet->fence, VK_TRUE, + ~0ull); + release_space (stage, packet->offset, packet->length); + RB_RELEASE (stage->packets, 1); } - packet->offset = stage->head; + packet = RB_ACQUIRE (stage->packets, 1); + + packet->offset = stage->space_start; packet->length = 0; dfunc->vkResetFences (device->dev, 1, &packet->fence); @@ -203,40 +247,10 @@ QFV_PacketAcquire (qfv_stagebuf_t *stage) void * QFV_PacketExtend (qfv_packet_t *packet, size_t size) { - qfv_stagebuf_t *stage = packet->stage; - if (!size || size > stage->size) { - return 0; + void *data = acquire_space (packet, size); + if (data) { + packet->length += size; } - - //FIXME extra logic may be needed to wait wait for space to become - //available when the requested size should fit but can't due to in-flight - //packets - advance_tail (stage, packet); - - size_t head = stage->head; - size_t end = stage->end; - if (head + size > stage->end) { - if (packet->length) { - // packets cannot wrap around the buffer (must use separate - // packets) - return 0; - } - if (stage->tail == 0) { - // the beginning of the the staging buffer is occupied - return 0; - } - packet->offset = 0; - head = 0; - end = stage->head; - } - if (head < stage->tail && head + size > stage->tail) { - // not enough room for the sub-packet - return 0; - } - void *data = (byte *) stage->data + head; - stage->end = end; - stage->head = head + size; - packet->length += size; return data; } diff --git a/libs/video/renderer/vulkan/test/test-staging.c b/libs/video/renderer/vulkan/test/test-staging.c index bb5361cec..020af9ab2 100644 --- a/libs/video/renderer/vulkan/test/test-staging.c +++ b/libs/video/renderer/vulkan/test/test-staging.c @@ -66,12 +66,17 @@ vkCreateFence (VkDevice device, const VkFenceCreateInfo *info, return VK_SUCCESS; } +int wait_count = 0; + static VkResult vkWaitForFences (VkDevice device, uint32_t fenceCount, const VkFence *fences, VkBool32 waitAll, uint64_t timeout) { for (uint32_t i = 0; i < fenceCount; i++) { int *f = (int *)fences[i]; + if (*f) { + wait_count++; + } *f = 0; } return VK_SUCCESS; @@ -145,7 +150,13 @@ qfv_devfuncs_t dfuncs = { vkFlushMappedMemoryRanges:vkFlushMappedMemoryRanges, vkQueueSubmit:vkQueueSubmit, }; -qfv_physdev_t physDev; +qfv_physdev_t physDev = { + properties:{ + limits:{ + nonCoherentAtomSize:256, + }, + }, +}; qfv_device_t device = { physDev:&physDev, funcs:&dfuncs, @@ -168,271 +179,59 @@ _error (int line, const char *fmt, ...) int main (void) { - qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (&device, 1024, 4, 0); + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (&device, 1024, 0); - if (stage->num_packets != 4) { - error ("stage has incorrect packet count: %zd\n", stage->num_packets); - } - if (stage->next_packet != 0) { - error ("stage has incorrect next_packet: %zd\n", stage->next_packet); - } if (stage->size != 1024) { - error ("stage has incorrect size: %zd\n", stage->size); + error ("stage has incorrect size: %zd", stage->size); } if (stage->end != stage->size) { - error ("stage has incorrect end: %zd\n", stage->end); - } - if (stage->head || stage->tail != stage->head) { - error ("stage ring buffer not initialized: h:%zd t:%zd\n", - stage->head, stage->tail); + error ("stage has incorrect end: %zd", stage->end); } if (!stage->data || stage->data != stage_memory) { - error ("stage memory not mapped: d:%p, m:%p\n", + error ("stage memory not mapped: d:%p, m:%p", stage->data, stage_memory); } - for (size_t i = 0; i < stage->num_packets; i++) { - qfv_packet_t *p = &stage->packet[i]; + for (size_t i = 0; i < RB_buffer_size (&stage->packets); i++) { + qfv_packet_t *p = &stage->packets.buffer[i]; if (p->stage != stage) { - error ("packet[%zd] stage not set: ps:%p s:%p\n", i, + error ("packet[%zd] stage not set: ps:%p s:%p", i, p->stage, stage); } if (!p->cmd) { - error ("packet[%zd] has no command buffer\n", i); + error ("packet[%zd] has no command buffer", i); } if (!p->fence) { - error ("packet[%zd] has no fence\n", i); - } - for (size_t j = 0; j < i; j++) { - qfv_packet_t *q = &stage->packet[j]; - if (q->cmd == p->cmd || q->fence == p->fence) { - error ("packet[%zd] has dup fence or cmd buf\n", i); - } + error ("packet[%zd] has no fence", i); } if (vkGetFenceStatus (device.dev, p->fence) != VK_SUCCESS) { - error ("packet[%zd].fence is not signaled\n", i); + error ("packet[%zd].fence is not signaled", i); } if (p->offset || p->length) { - error ("packet[%zd] size/length not initialized: o:%zd l:%zd\n", + error ("packet[%zd] size/length not initialized: o:%zd l:%zd", i, p->offset, p->length); } } qfv_packet_t *packet = QFV_PacketAcquire (stage); + if (!packet) { + error ("could not get a packet"); + } + if (RB_DATA_AVAILABLE (stage->packets) != 1) { + error ("in flight packet count incorrect"); + } if (vkGetFenceStatus (device.dev, packet->fence) != VK_NOT_READY) { - error ("packet.fence is signaled\n"); + error ("packet.fence is signaled"); + } + if (QFV_PacketExtend (packet, 2048)) { + error ("2048 byte request did not return null"); + } + if (!QFV_PacketExtend (packet, 1024)) { + error ("1024 byte request returned null"); + } + if (QFV_PacketExtend (packet, 1)) { + error ("1 byte request did not return null"); } - void *data; - size_t old_head, old_tail; - - old_head = stage->head; - old_tail = stage->tail; - data = QFV_PacketExtend (packet, 0); - if (data) { - error ("0 byte extend did not return null\n"); - } - if (stage->head != old_head || stage->tail != old_tail) { - error ("0 byte extend moved head or tail\n"); - } - - data = QFV_PacketExtend (packet, 2048); - if (data) { - error ("2048 byte extend did not return null\n"); - } - if (stage->head != old_head || stage->tail != old_tail) { - error ("2048 byte extend moved head or tail\n"); - } - - data = QFV_PacketExtend (packet, 1024); - if (!data) { - error ("1024 byte extend failed\n"); - } - if (stage->head == old_head) { - error ("1024 byte extend did not move head\n"); - } - if (stage->tail != old_tail) { - error ("1024 byte extend moved tail\n"); - } - if (stage->head > stage->size) { - error ("stage head out of bounds: %zd\n", stage->head); - } - if (packet->offset != old_head || packet->length != 1024) { - error ("packet offset/size incorrect: p:%zd,%zd h:%zd\n", - packet->offset, packet->length, old_head); - } - if (stage->head < packet->offset + packet->length) { - error ("stage head before end of packet: %zd, pe:%zd\n", - stage->head, packet->offset + packet->length); - } - - old_head = stage->head; - old_tail = stage->tail; - data = QFV_PacketExtend (packet, 16); - if (data) { - error ("16 byte extend in full stage did not return null\n"); - } - if (stage->head != old_head || stage->tail != old_tail) { - error ("16 byte extend moved head or tail\n"); - } - QFV_PacketSubmit (packet); - if (vkGetFenceStatus (device.dev, packet->fence) != VK_SUCCESS) { - error ("packet.fence is not signaled\n"); - } - - if (stage->head != 1024 || stage->tail != 0) { - error ("stage head or tail not as expected: h: %zd t:%zd\n", - stage->head, stage->tail); - } - - qfv_packet_t *packet2 = QFV_PacketAcquire (stage); - if (!packet2 || packet2 == packet) { - error ("did not get new packet: n:%p o:%p\n", packet2, packet); - } - packet = packet2; - if (packet->offset != 0 || stage->head != 0 || stage->tail != 0) { - error ("new packet did not wrap: p:%zd h:%zd t:%zd\n", - packet2->offset, stage->head, stage->tail); - } - - old_head = stage->head; - old_tail = stage->tail; - data = QFV_PacketExtend (packet, 768); - if (!data) { - error ("768 byte extend failed\n"); - } - if (stage->head == old_head) { - error ("768 byte extend did not move head\n"); - } - if (stage->tail != 0) { - error ("768 byte extend dit not wrap tail: %zd\n", stage->tail); - } - if (stage->head > stage->size) { - error ("stage head out of bounds: %zd\n", stage->head); - } - if (packet->offset != old_head || packet->length != 768) { - error ("packet offset/size incorrect: p:%zd,%zd h:%zd\n", - packet->offset, packet->length, old_head); - } - if (stage->head < packet->offset + packet->length) { - error ("stage head before end of packet: %zd, pe:%zd\n", - stage->head, packet->offset + packet->length); - } - - // test attempting to wrap the packet (without needed space) - old_head = stage->head; - old_tail = stage->tail; - data = QFV_PacketExtend (packet, 512); - if (data) { - error ("512 byte extend in partially full stage succeeded\n"); - } - if (stage->head != old_head || stage->tail != old_tail) { - error ("512 byte extend moved head or tail\n"); - } - QFV_PacketSubmit (packet); - - if (stage->head != 768 || stage->tail != 0) { - error ("stage head or tail not as expected: h: %zd t:%zd\n", - stage->head, stage->tail); - } - - packet = QFV_PacketAcquire (stage); - - // test wrapping a new packet - data = QFV_PacketExtend (packet, 512); - if (!data) { - error ("512 byte extend failed\n"); - } - if (packet->offset != 0 || packet->length != 512) { - error ("packet offset/size incorrect: p:%zd,%zd\n", - packet->offset, packet->length); - } - if (stage->head != 512 || stage->tail != stage->end || stage->end !=768) { - error ("stage head or tail not as expected: h: %zd t:%zd\n", - stage->head, stage->tail); - } - data = QFV_PacketExtend (packet, 512); - if (!data) { - error ("second 512 byte extend failed\n"); - } - if (packet->offset != 0 || packet->length != 1024) { - error ("packet offset/size incorrect: p:%zd,%zd\n", - packet->offset, packet->length); - } - if (stage->head != 1024 || stage->tail != 0 || stage->end != 1024) { - error ("stage head or tail not as expected: h: %zd t:%zd\n", - stage->head, stage->tail); - } - QFV_PacketSubmit (packet); - - packet = QFV_PacketAcquire (stage); - data = QFV_PacketExtend (packet, 512); - if (!data) { - error ("512 byte extend failed\n"); - } - if (packet->offset != 0 || packet->length != 512) { - error ("packet offset/size incorrect: p:%zd,%zd\n", - packet->offset, packet->length); - } - QFV_PacketSubmit (packet); - - if (stage->head != 512 || stage->tail != 0 || stage->end != 1024) { - error ("stage head or tail not as expected: h: %zd t:%zd\n", - stage->head, stage->tail); - } - - packet = QFV_PacketAcquire (stage); - data = QFV_PacketExtend (packet, 256); - if (!data) { - error ("256 byte extend failed\n"); - } - if (packet->offset != 512 || packet->length != 256) { - error ("packet offset/size incorrect: p:%zd,%zd\n", - packet->offset, packet->length); - } - if (stage->head != 768 || stage->tail != 512 || stage->end != 1024) { - error ("stage head or tail not as expected: h: %zd t:%zd\n", - stage->head, stage->tail); - } - // don't submit yet. Normally, it would be an error, but the test harness - // needs to keep the packet on hand for the following tests to work - packet2 = QFV_PacketAcquire (stage); - old_head = stage->head; - old_tail = stage->tail; - data = QFV_PacketExtend (packet2, 768); - if (data) { - error ("768 byte extend did not return null\n"); - } - if (stage->head != old_head || stage->tail != old_tail) { - error ("768 byte extend moved head or tail\n"); - } - - //should wrap - data = QFV_PacketExtend (packet2, 512); - if (!data) { - error ("512 byte extend failed\n"); - } - if (packet2->offset != 0 || packet2->length != 512) { - error ("packet offset/size incorrect: p:%zd,%zd\n", - packet2->offset, packet2->length); - } - if (stage->head != 512 || stage->tail != 512 || stage->end != 768) { - error ("stage head or tail not as expected: h: %zd t:%zd\n", - stage->head, stage->tail); - } - - //submit the first packet - QFV_PacketSubmit (packet); - - packet = QFV_PacketAcquire (stage); - old_head = stage->head; - old_tail = stage->tail; - data = QFV_PacketExtend (packet, 768); - if (data) { - error ("768 byte extend did not return null\n"); - } - if (stage->head != old_head || stage->tail != old_tail) { - error ("768 byte extend moved head or tail\n"); - } return 0; } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index fe7c001f4..27c2b724a 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -465,8 +465,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) size_t vertex_buffer_size = vertex_count * sizeof (bspvert_t); index_buffer_size = (index_buffer_size + atom_mask) & ~atom_mask; - stage = QFV_CreateStagingBuffer (device, vertex_buffer_size, 1, - ctx->cmdpool); + stage = QFV_CreateStagingBuffer (device, vertex_buffer_size, ctx->cmdpool); qfv_packet_t *packet = QFV_PacketAcquire (stage); vertices = QFV_PacketExtend (packet, vertex_buffer_size); vertex_index_base = 0; @@ -1289,8 +1288,7 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bctx->light_scrap = QFV_CreateScrap (device, 2048, tex_frgba, ctx->staging); size_t size = QFV_ScrapSize (bctx->light_scrap); - bctx->light_stage = QFV_CreateStagingBuffer (device, size, 3, - ctx->cmdpool); + bctx->light_stage = QFV_CreateStagingBuffer (device, size, ctx->cmdpool); DARRAY_INIT (&bctx->texture_chains, 64); diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 2e41e2252..6ec67b227 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -367,7 +367,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) 0, 0); create_quad_buffers (ctx); - dctx->stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024, 4, + dctx->stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024, ctx->cmdpool); dctx->scrap = QFV_CreateScrap (device, 2048, tex_rgba, dctx->stage); dctx->sampler = QFV_GetSampler (ctx, "quakepic"); diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index d9220307b..4e5f338cc 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -204,7 +204,7 @@ Vulkan_CreateDevice (vulkan_ctx_t *ctx) void Vulkan_CreateStagingBuffers (vulkan_ctx_t *ctx) { - ctx->staging = QFV_CreateStagingBuffer (ctx->device, 4*1024*1024, 1, + ctx->staging = QFV_CreateStagingBuffer (ctx->device, 4*1024*1024, ctx->cmdpool); } From 68b734142990aa5be9246e35e9b89610a2a9f226 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Jan 2021 13:51:09 +0900 Subject: [PATCH 281/435] [vulkan] Set main texture image view Glow map and sky sheet and cube need to wait until I can get some default textures going, but the world is rendering correctly otherwise (though a tad dark: need to do a gamma setting). --- include/QF/Vulkan/qf_bsp.h | 8 ++ libs/video/renderer/vulkan/quakebsp.frag | 11 ++- libs/video/renderer/vulkan/vulkan_bsp.c | 111 +++++++++++++---------- 3 files changed, 76 insertions(+), 54 deletions(-) diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index 5b01da407..92c63b034 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -57,6 +57,11 @@ typedef struct elechain_s { float *color; } elechain_t; +// view matrix +#define BSP_BUFFER_INFOS 1 +// Texture, GlowMap, LightMap, SkySheet, SkyCube +#define BSP_IMAGE_INFOS 5 + typedef struct bspframe_s { uint32_t *index_data; // pointer into mega-buffer for this frame (c) uint32_t index_offset; // offset of index_data within mega-buffer (c) @@ -64,6 +69,9 @@ typedef struct bspframe_s { VkCommandBuffer bsp_cmd; VkCommandBuffer turb_cmd; VkCommandBuffer sky_cmd; + VkDescriptorBufferInfo bufferInfo[BSP_BUFFER_INFOS]; + VkDescriptorImageInfo imageInfo[BSP_IMAGE_INFOS]; + VkWriteDescriptorSet descriptors[BSP_BUFFER_INFOS + BSP_IMAGE_INFOS]; } bspframe_t; typedef struct bspframeset_s diff --git a/libs/video/renderer/vulkan/quakebsp.frag b/libs/video/renderer/vulkan/quakebsp.frag index 916581292..73270557e 100644 --- a/libs/video/renderer/vulkan/quakebsp.frag +++ b/libs/video/renderer/vulkan/quakebsp.frag @@ -1,8 +1,8 @@ #version 450 layout (set = 0, binding = 1) uniform sampler2D Texture; -layout (set = 0, binding = 2) uniform sampler2D Glowmap; -layout (set = 0, binding = 3) uniform sampler2D Lightmap; +layout (set = 0, binding = 2) uniform sampler2D GlowMap; +layout (set = 0, binding = 3) uniform sampler2D LightMap; //layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; //layout (set = 0, binding = 5) uniform samplerCube SkyCube; @@ -117,9 +117,10 @@ main (void) }*/ c = texture (Texture, t_st); if (doLight) { - c *= vec4 (texture (Lightmap, l_st).xyz, 1); + c *= vec4 (texture (LightMap, l_st).xyz, 1); } - c += texture (Glowmap, t_st); - c = vec4(texture (Lightmap, l_st).xyz, 1); + //c += texture (GlowMap, t_st); + //c = vec4(texture (LightMap, l_st).xyz, 1); + //c = vec4(texture (Texture, t_st).xyz, 1); frag_color = c;//fogBlend (c); } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 27c2b724a..a7fab14ab 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -788,12 +788,12 @@ draw_elechain (elechain_t *ec, VkPipelineLayout layout, qfv_devfuncs_t *dfunc, } static VkImageView -get_view (qfv_tex_t *tex) +get_view (qfv_tex_t *tex, VkImageView default_view) { if (tex) { return tex->view; } - return 0; + return default_view; } static void @@ -812,52 +812,13 @@ bsp_begin (vulkan_ctx_t *ctx) VkCommandBuffer cmd = bframe->bsp_cmd; DARRAY_APPEND (cframe->subCommand, cmd); - VkDescriptorBufferInfo bufferInfo = { - ctx->matrices.buffer_3d, 0, VK_WHOLE_SIZE - }; - VkDescriptorImageInfo imageInfo[] = { - { bctx->sampler, - QFV_ScrapImageView (bctx->light_scrap), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, - { bctx->sampler, - QFV_ScrapImageView (bctx->light_scrap), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, - { bctx->sampler, - QFV_ScrapImageView (bctx->light_scrap), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, - { bctx->sampler, - get_view (bctx->skysheet_tex), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, - { bctx->sampler, - get_view (bctx->skybox_tex), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, - }; - VkWriteDescriptorSet write[] = { - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, - 0, 0, 1, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 0, &bufferInfo, 0 }, - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, - 1, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - &imageInfo[0], 0, 0 }, - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, - 2, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - &imageInfo[1], 0, 0 }, - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, - 3, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - &imageInfo[2], 0, 0 }, - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, - 4, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - &imageInfo[3], 0, 0 }, - { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, - 5, 0, 1, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - &imageInfo[4], 0, 0 }, - }; + //FIXME need per frame matrices + bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; + bframe->imageInfo[0].imageView = 0; // set by tex chain loop + bframe->imageInfo[1].imageView = 0; // set by tex chain loop + bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap); + bframe->imageInfo[3].imageView = get_view (bctx->skysheet_tex, 0); + bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, 0); dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { @@ -885,8 +846,15 @@ bsp_begin (vulkan_ctx_t *ctx) dfunc->vkCmdBindIndexBuffer (cmd, bctx->index_buffer, bframe->index_offset, VK_INDEX_TYPE_UINT32); + // push VP matrices dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - bctx->layout, 0, 4, write); + bctx->layout, + 0, 1, bframe->descriptors + 0); + // push static images + // XXX sky sheet and box not pushed yet + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + bctx->layout, + 0, 1, bframe->descriptors + 3); //XXX glsl_Fog_GetColor (fog); //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; @@ -1140,11 +1108,22 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) elechain_t *ec = 0; tex = bctx->texture_chains.a[i]; + if (!tex->tex) { + //FIXME bind to whit + continue; + } build_tex_elechain (tex, bctx, bframe); //XXX if (tex->elechain) //XXX qfeglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum); + bframe->imageInfo[0].imageView = get_view (tex->tex, 0); + bframe->imageInfo[1].imageView = get_view (tex->glow, 0); + //XXX glow map + dfunc->vkCmdPushDescriptorSetKHR (bframe->bsp_cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, + bctx->layout, + 0, 1, bframe->descriptors + 1); for (ec = tex->elechain; ec; ec = ec->next) { draw_elechain (ec, bctx->layout, dfunc, bframe->bsp_cmd); @@ -1271,6 +1250,25 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) bctx->sky_chain_tail = &bctx->sky_chain; } +static VkDescriptorBufferInfo base_buffer_info = { + 0, 0, VK_WHOLE_SIZE +}; +static VkDescriptorImageInfo base_image_info = { + 0, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL +}; +static VkWriteDescriptorSet base_buffer_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, 0, 0 +}; +static VkWriteDescriptorSet base_image_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 0, 0, 0 +}; + void Vulkan_Bsp_Init (vulkan_ctx_t *ctx) { @@ -1314,6 +1312,21 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bframe->bsp_cmd = cmdBuffers->a[i]; bframe->turb_cmd = cmdBuffers->a[i]; bframe->sky_cmd = cmdBuffers->a[i]; + + for (int j = 0; j < BSP_BUFFER_INFOS; j++) { + bframe->bufferInfo[j] = base_buffer_info; + bframe->descriptors[j] = base_buffer_write; + bframe->descriptors[j].dstBinding = j; + bframe->descriptors[j].pBufferInfo = &bframe->bufferInfo[j]; + } + for (int j = 0; j < BSP_IMAGE_INFOS; j++) { + bframe->imageInfo[j] = base_image_info; + bframe->imageInfo[j].sampler = bctx->sampler; + int k = j + BSP_BUFFER_INFOS; + bframe->descriptors[k] = base_image_write; + bframe->descriptors[k].dstBinding = k; + bframe->descriptors[k].pImageInfo = &bframe->imageInfo[j]; + } } } From 93e9f89bd38b9a900eae83da8d2f67f3deb512e3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Jan 2021 15:40:31 +0900 Subject: [PATCH 282/435] [vulkan] Create some default textures Black, white and magenta. This gets glow (full bright) maps working. --- include/QF/Vulkan/qf_texture.h | 2 ++ include/vid_vulkan.h | 6 ++++ libs/video/renderer/vid_render_vulkan.c | 2 ++ libs/video/renderer/vulkan/quakebsp.frag | 4 +-- libs/video/renderer/vulkan/vulkan_bsp.c | 28 +++++++++--------- libs/video/renderer/vulkan/vulkan_texture.c | 32 ++++++++++++++++++++- 6 files changed, 56 insertions(+), 18 deletions(-) diff --git a/include/QF/Vulkan/qf_texture.h b/include/QF/Vulkan/qf_texture.h index a2ffbd38e..d08fc0a46 100644 --- a/include/QF/Vulkan/qf_texture.h +++ b/include/QF/Vulkan/qf_texture.h @@ -16,5 +16,7 @@ void Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, qfv_tex_t *Vulkan_LoadTex (struct vulkan_ctx_s *ctx, tex_t *tex, int mip); VkImageView Vulkan_TexImageView (qfv_tex_t *tex) __attribute__((pure)); void Vulkan_UnloadTex (struct vulkan_ctx_s *ctx, qfv_tex_t *tex); +void Vulkan_Texture_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Texture_Shutdown (struct vulkan_ctx_s *ctx); #endif//__QF_Vulkan_qf_texture_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 92208425e..3a234c0d2 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -75,6 +75,12 @@ typedef struct vulkan_ctx_s { size_t curFrame; vulkan_framebufferset_t framebuffers; + struct qfv_tex_s *default_black; + struct qfv_tex_s *default_white; + struct qfv_tex_s *default_magenta; + struct qfv_tex_s *default_skysheet; + struct qfv_tex_s *default_skybox; + // projection and view matrices (model is push constant) vulkan_matrices_t matrices; diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 85d090b37..a54962b52 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -96,6 +96,7 @@ vulkan_R_Init (void) // FIXME this should be staged so screen updates can begin while pipelines // are being built vulkan_ctx->pipeline = Vulkan_CreatePipeline (vulkan_ctx, "pipeline"); + Vulkan_Texture_Init (vulkan_ctx); Vulkan_Bsp_Init (vulkan_ctx); Vulkan_Draw_Init (vulkan_ctx); Vulkan_Particles_Init (vulkan_ctx); @@ -607,6 +608,7 @@ vulkan_vid_render_shutdown (void) Vulkan_Draw_Shutdown (vulkan_ctx); Vulkan_Bsp_Shutdown (vulkan_ctx); Mod_ClearAll (); + Vulkan_Texture_Shutdown (vulkan_ctx); Vulkan_Shutdown_Common (vulkan_ctx); } diff --git a/libs/video/renderer/vulkan/quakebsp.frag b/libs/video/renderer/vulkan/quakebsp.frag index 73270557e..872c97893 100644 --- a/libs/video/renderer/vulkan/quakebsp.frag +++ b/libs/video/renderer/vulkan/quakebsp.frag @@ -119,8 +119,6 @@ main (void) if (doLight) { c *= vec4 (texture (LightMap, l_st).xyz, 1); } - //c += texture (GlowMap, t_st); - //c = vec4(texture (LightMap, l_st).xyz, 1); - //c = vec4(texture (Texture, t_st).xyz, 1); + c += texture (GlowMap, t_st); frag_color = c;//fogBlend (c); } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index a7fab14ab..552ea075f 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -788,12 +788,15 @@ draw_elechain (elechain_t *ec, VkPipelineLayout layout, qfv_devfuncs_t *dfunc, } static VkImageView -get_view (qfv_tex_t *tex, VkImageView default_view) +get_view (qfv_tex_t *tex, qfv_tex_t *default_tex) { if (tex) { return tex->view; } - return default_view; + if (default_tex) { + return default_tex->view; + } + return 0; } static void @@ -817,8 +820,10 @@ bsp_begin (vulkan_ctx_t *ctx) bframe->imageInfo[0].imageView = 0; // set by tex chain loop bframe->imageInfo[1].imageView = 0; // set by tex chain loop bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap); - bframe->imageInfo[3].imageView = get_view (bctx->skysheet_tex, 0); - bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, 0); + bframe->imageInfo[3].imageView = get_view (bctx->skysheet_tex, + ctx->default_skysheet); + bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, + ctx->default_skybox); dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { @@ -1108,22 +1113,17 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) elechain_t *ec = 0; tex = bctx->texture_chains.a[i]; - if (!tex->tex) { - //FIXME bind to whit - continue; - } build_tex_elechain (tex, bctx, bframe); - //XXX if (tex->elechain) - //XXX qfeglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum); - bframe->imageInfo[0].imageView = get_view (tex->tex, 0); - bframe->imageInfo[1].imageView = get_view (tex->glow, 0); - //XXX glow map + bframe->imageInfo[0].imageView = get_view (tex->tex, + ctx->default_white); + bframe->imageInfo[1].imageView = get_view (tex->glow, + ctx->default_black); dfunc->vkCmdPushDescriptorSetKHR (bframe->bsp_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, bctx->layout, - 0, 1, bframe->descriptors + 1); + 0, 2, bframe->descriptors + 1); for (ec = tex->elechain; ec; ec = ec->next) { draw_elechain (ec, bctx->layout, dfunc, bframe->bsp_cmd); diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index 295d1a89d..86bd890ab 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -170,6 +170,10 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); QFV_BindImageMemory (device, qtex->image, qtex->memory, 0); + qtex->view = QFV_CreateImageView (device, qtex->image, + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); size_t bytes = bpp * tex->width * tex->height; qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); @@ -241,8 +245,14 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) blit.dstOffsets[1].y = (blit.dstOffsets[1].y + 1) >> 1; barrier.subresourceRange.baseMipLevel++; } + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = qtex->image; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); QFV_PacketSubmit (packet); - return 0; + return qtex; } VkImageView @@ -262,3 +272,23 @@ Vulkan_UnloadTex (vulkan_ctx_t *ctx, qfv_tex_t *tex) dfunc->vkFreeMemory (device->dev, tex->memory, 0); free (tex); } + +static tex_t default_black_tex = {1, 1, tex_rgba, 1, 0, {0, 0, 0, 0 }}; +static tex_t default_white_tex = {1, 1, tex_rgba, 1, 0, {255, 255, 255, 255 }}; +static tex_t default_magenta_tex = {1, 1, tex_rgba, 1, 0, {255, 0, 255, 255 }}; + +void +Vulkan_Texture_Init (vulkan_ctx_t *ctx) +{ + ctx->default_black = Vulkan_LoadTex (ctx, &default_black_tex, 1); + ctx->default_white = Vulkan_LoadTex (ctx, &default_white_tex, 1); + ctx->default_magenta = Vulkan_LoadTex (ctx, &default_magenta_tex, 1); +} + +void +Vulkan_Texture_Shutdown (vulkan_ctx_t *ctx) +{ + Vulkan_UnloadTex (ctx, ctx->default_black); + Vulkan_UnloadTex (ctx, ctx->default_white); + Vulkan_UnloadTex (ctx, ctx->default_magenta); +} From 82241693947ef9a271f65e1ddb36f73cec495411 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Jan 2021 18:56:15 +0900 Subject: [PATCH 283/435] [util] Make plist parse errors a little more useful Particularly the "unexpected character" ones. --- libs/util/qfplist.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 273148657..3fa64b9d0 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -85,11 +85,11 @@ struct plbinary_s { typedef struct plbinary_s plbinary_t; typedef struct pldata_s { // Unparsed property list string - const char *ptr; - unsigned int end; - unsigned int pos; - unsigned int line; - const char *error; + const char *ptr; + unsigned end; + unsigned pos; + unsigned line; + plitem_t *error; } pldata_t; // Ugly defines for fast checking and conversion from char to number @@ -454,7 +454,7 @@ PL_SkipSpace (pldata_t *pl) pl->pos++; } if (pl->pos >= pl->end) { - pl->error = "Reached end of string in comment"; + pl->error = PL_NewString ("Reached end of string in comment"); return false; } } else if (pl->ptr[pl->pos + 1] == '*') { // "/*" comments @@ -473,7 +473,7 @@ PL_SkipSpace (pldata_t *pl) pl->pos++; } if (pl->pos >= pl->end) { - pl->error = "Reached end of string in comment"; + pl->error = PL_NewString ("Reached end of string in comment"); return false; } } else { @@ -488,7 +488,7 @@ PL_SkipSpace (pldata_t *pl) } pl->pos++; } - pl->error = "Reached end of string"; + pl->error = PL_NewString ("Reached end of string"); return false; } @@ -523,7 +523,7 @@ PL_ParseData (pldata_t *pl, int *len) } if (c == '>') { if (nibbles & 1) { - pl->error = "invalid data, missing nibble"; + pl->error = PL_NewString ("invalid data, missing nibble"); return NULL; } *len = nibbles / 2; @@ -533,10 +533,10 @@ PL_ParseData (pldata_t *pl, int *len) pl->ptr[start + i * 2 + 1]); return str; } - pl->error = "invalid character in data"; + pl->error = PL_NewString (va ("invalid character in data: %02x", c)); return NULL; } - pl->error = "Reached end of string while parsing data"; + pl->error = PL_NewString ("Reached end of string while parsing data"); return NULL; } @@ -603,7 +603,7 @@ PL_ParseQuotedString (pldata_t *pl) } if (pl->pos >= pl->end) { - pl->error = "Reached end of string while parsing quoted string"; + pl->error = PL_NewString ("Reached end of string while parsing quoted string"); return NULL; } @@ -741,14 +741,14 @@ PL_ParsePropertyListItem (pldata_t *pl) } if (key->type != QFString) { - pl->error = "Key is not a string"; + pl->error = PL_NewString ("Key is not a string"); PL_Free (key); PL_Free (item); return NULL; } if (pl->ptr[pl->pos] != '=') { - pl->error = "Unexpected character (expected '=')"; + pl->error = PL_NewString (va ("Unexpected character %c (expected '=')", pl->ptr[pl->pos])); PL_Free (key); PL_Free (item); return NULL; @@ -772,7 +772,7 @@ PL_ParsePropertyListItem (pldata_t *pl) if (pl->ptr[pl->pos] == ';') { pl->pos++; } else if (pl->ptr[pl->pos] != '}') { - pl->error = "Unexpected character (wanted ';' or '}')"; + pl->error = PL_NewString (va ("Unexpected character %c (wanted ';' or '}')", pl->ptr[pl->pos])); PL_Free (key); PL_Free (value); PL_Free (item); @@ -790,7 +790,7 @@ PL_ParsePropertyListItem (pldata_t *pl) } if (pl->pos >= pl->end) { // Catch the error - pl->error = "Unexpected end of string when parsing dictionary"; + pl->error = PL_NewString ("Unexpected end of string when parsing dictionary"); PL_Free (item); return NULL; } @@ -822,14 +822,14 @@ PL_ParsePropertyListItem (pldata_t *pl) if (pl->ptr[pl->pos] == ',') { pl->pos++; } else if (pl->ptr[pl->pos] != ')') { - pl->error = "Unexpected character (wanted ',' or ')')"; + pl->error = PL_NewString (va ("Unexpected character %c (wanted ',' or ')')", pl->ptr[pl->pos])); PL_Free (value); PL_Free (item); return NULL; } if (!PL_A_AddObject (item, value)) { - pl->error = "Unexpected character (too many items in array)"; + pl->error = PL_NewString ("Unexpected character (too many items in array)"); PL_Free (value); PL_Free (item); return NULL; @@ -896,8 +896,13 @@ PL_GetPropertyList (const char *string) free (pl); return newpl; } else { - if (pl && pl->error && pl->error[0]) - Sys_Printf ("plist: %d,%d: %s", pl->line, pl->pos, pl->error); + if (pl && pl->error) { + const char *error = PL_String (pl->error); + if (error[0]) { + Sys_Printf ("plist: %d,%d: %s", pl->line, pl->pos, error); + } + PL_Free (pl->error); + } free (pl); return NULL; } From 4283d690ad892cb36ba682aaf9e3e3c6d8933bcc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Jan 2021 20:39:09 +0900 Subject: [PATCH 284/435] [vulkan] Generate correct parse data for size_t Fixes a segfault when parsing specialization map data. --- libs/video/renderer/vulkan/vkgen/vkalias.r | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/vkgen/vkalias.r b/libs/video/renderer/vulkan/vkgen/vkalias.r index cde6eb270..e0aad2943 100644 --- a/libs/video/renderer/vulkan/vkgen/vkalias.r +++ b/libs/video/renderer/vulkan/vkgen/vkalias.r @@ -137,9 +137,12 @@ id enumObj = [(id) Hash_Find (available_types, name) resolveType]; return [enumObj parseData]; } - if (name == "uint32_t" || name == "size_t") { + if (name == "uint32_t") { return "0"; } + if (name == "size_t") { + return "&cexpr_size_t"; + } return [alias parseData]; } @end From 77a8f901133a35e7dfd6e527cae0b4c347407dff Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Jan 2021 20:40:11 +0900 Subject: [PATCH 285/435] [vulkan] Fix array parsing size error The size was not getting written if it was the first value in the structure. --- libs/video/renderer/vulkan/vkparse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 0fc00b835..3c2447702 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -282,7 +282,7 @@ parse_array (const plfield_t *field, const plitem_t *item, } *value = malloc (array->stride * arr->size); memcpy (*value, arr->a, array->stride * arr->size); - if ((void *) size > data) { + if ((void *) size >= data) { *size = arr->size; } free (arr); From 49408c695dcfa063691ad1437cc83addb512723d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Jan 2021 20:42:53 +0900 Subject: [PATCH 286/435] [vulkan] Get sky sheets mostly working They render (incorrectly because the images weren't translated correctly), but aren't animated (haven't pushed the time constant) --- include/QF/Vulkan/qf_bsp.h | 11 + include/vid_vulkan.h | 2 - libs/video/renderer/vulkan/qfpipeline.plist | 106 ++++++- libs/video/renderer/vulkan/quakebsp.frag | 19 +- libs/video/renderer/vulkan/quakebsp.vert | 2 +- libs/video/renderer/vulkan/vulkan_bsp.c | 297 ++++++++++++++------ 6 files changed, 341 insertions(+), 96 deletions(-) diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index 92c63b034..969fdd92c 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -57,6 +57,13 @@ typedef struct elechain_s { float *color; } elechain_t; +typedef enum { + qfv_bsp_texture, + qfv_bsp_glowmap, + qfv_bsp_lightmap, + qfv_bsp_skysheet, + qfv_bsp_skycube, +} qfv_bsp_tex; // view matrix #define BSP_BUFFER_INFOS 1 // Texture, GlowMap, LightMap, SkySheet, SkyCube @@ -104,7 +111,10 @@ typedef struct bspctx_s { instsurf_t **instsurfs_tail; instsurf_t *free_instsurfs; + struct qfv_tex_s *default_skysheet; struct qfv_tex_s *skysheet_tex; + + struct qfv_tex_s *default_skybox; struct qfv_tex_s *skybox_tex; quat_t sky_rotation[2]; quat_t sky_velocity; @@ -122,6 +132,7 @@ typedef struct bspctx_s { VkSampler sampler; VkDeviceMemory texture_memory; VkPipeline main; + VkPipeline sky; VkPipelineLayout layout; size_t vertex_buffer_size; size_t index_buffer_size; diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 3a234c0d2..f4642afb1 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -78,8 +78,6 @@ typedef struct vulkan_ctx_s { struct qfv_tex_s *default_black; struct qfv_tex_s *default_white; struct qfv_tex_s *default_magenta; - struct qfv_tex_s *default_skysheet; - struct qfv_tex_s *default_skybox; // projection and view matrices (model is push constant) vulkan_matrices_t matrices; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 9b0a6a1d7..b5f5cd6cb 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -108,7 +108,7 @@ descriptorCount = 1; stageFlags = fragment; }, - /*{ + { binding = 4; descriptorType = combined_image_sampler; descriptorCount = 1; @@ -119,7 +119,7 @@ descriptorType = combined_image_sampler; descriptorCount = 1; stageFlags = fragment; - },*/ + }, ); }; something = { @@ -260,6 +260,108 @@ layout = quakebsp; //renderPass = renderpass; }; + quakebsp.skysheet = { + stages = ( + { stage = vertex; name = main; module = quakebspv; }, + { + stage = fragment; + name = main; + module = quakebspf; + specializationInfo = { + mapEntries = ( + { size = 4; offset = 0; constantID = 0; }, + { size = 4; offset = 0; constantID = 1; }, + { size = 4; offset = 0; constantID = 2; }, + { size = 4; offset = 4; constantID = 3; }, + ); + data = <00000000ffffffff>; + }; + }, + ); + vertexInput = { + bindings = ( + { + binding = 0; + stride = "2 * 4 * 4"; + inputRate = vertex; + }, + ); + attributes = ( + { + location = 0; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 0; + }, + { + location = 1; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 16; + }, + ); + }; + inputAssembly = { + topology = triangle_fan; + primitiveRestartEnable = true; + }; + viewport = { + viewports = ( + { + x = 0; y = 0; + width = 640; height = 480; + minDepth = 0; maxDepth = 1; + } + ); + scissors = ( + { + offset = { x = 0; y = 0 }; + extent = { width = 640; height = 480; }; + }, + ); + }; + rasterization = { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = fill; + cullMode = back; + frontFace = clockwise; + depthBiasEnable = false; + lineWidth = 1; + }; + multisample = { + rasterizationSamples = $msaaSamples; + sampleShadingEnable = false; + minSampleShading = 0.5f; + alphaToCoverageEnable = false; + alphaToOneEnable = false; + }; + depthStencil = { + depthTestEnable = true; + depthWriteEnable = true; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + colorBlend = { + logicOpEnable = false; + attachments = ({ + blendEnable = true; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }); + }; + dynamic = { + dynamicState = ( viewport, scissor, blend_constants ); + }; + layout = quakebsp; + //renderPass = renderpass; + }; twod = { stages = ( { stage = vertex; name = main; module = twodv; }, diff --git a/libs/video/renderer/vulkan/quakebsp.frag b/libs/video/renderer/vulkan/quakebsp.frag index 872c97893..483a3887e 100644 --- a/libs/video/renderer/vulkan/quakebsp.frag +++ b/libs/video/renderer/vulkan/quakebsp.frag @@ -3,8 +3,8 @@ layout (set = 0, binding = 1) uniform sampler2D Texture; layout (set = 0, binding = 2) uniform sampler2D GlowMap; layout (set = 0, binding = 3) uniform sampler2D LightMap; -//layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; -//layout (set = 0, binding = 5) uniform samplerCube SkyCube; +layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; +layout (set = 0, binding = 5) uniform samplerCube SkyCube; layout (push_constant) uniform PushConstants { layout (offset = 64) @@ -46,7 +46,7 @@ fogBlend (vec4 color) return vec4 (mix (fog_color.rgb, color.rgb, fog_factor), color.a); } -/* + vec4 sky_sheet (vec3 dir, float time) { @@ -99,7 +99,7 @@ sky_color (vec3 dir, float time) return vec4 (1, 0, 1, 1); } } -*/ + void main (void) { @@ -110,15 +110,14 @@ main (void) if (doWarp) { t_st = warp_st (t_st, time); } - /*if (doSkyCube || doSkySheet) { + if (doSkyCube || doSkySheet) { c = sky_color (direction, time); } else { c = texture (Texture, t_st); - }*/ - c = texture (Texture, t_st); - if (doLight) { - c *= vec4 (texture (LightMap, l_st).xyz, 1); + if (doLight) { + c *= vec4 (texture (LightMap, l_st).xyz, 1); + } + c += texture (GlowMap, t_st); } - c += texture (GlowMap, t_st); frag_color = c;//fogBlend (c); } diff --git a/libs/video/renderer/vulkan/quakebsp.vert b/libs/video/renderer/vulkan/quakebsp.vert index efc03bac8..bb9e87e4a 100644 --- a/libs/video/renderer/vulkan/quakebsp.vert +++ b/libs/video/renderer/vulkan/quakebsp.vert @@ -20,6 +20,6 @@ void main (void) { gl_Position = Projection * (View * (Model * vertex)); - direction = vertex.xyz;//(Sky * vertex).xyz; + direction = (Sky * vertex).xyz; tl_st = tl_uv; } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 552ea075f..bfd54f9e8 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -56,9 +56,11 @@ #include "QF/Vulkan/qf_lightmap.h" #include "QF/Vulkan/qf_texture.h" #include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/barrier.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/scrap.h" #include "QF/Vulkan/staging.h" @@ -751,6 +753,17 @@ R_VisitWorldNodes (model_t *model, vulkan_ctx_t *ctx) visit_leaf ((mleaf_t *) node); } +static void +bind_view (qfv_bsp_tex tex, VkImageView view, bspframe_t *bframe, + VkCommandBuffer cmd, VkPipelineLayout layout, qfv_devfuncs_t *dfunc) +{ + bframe->imageInfo[tex].imageView = view; + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + layout, 0, 1, + bframe->descriptors + tex + + BSP_BUFFER_INFOS); +} + static void draw_elechain (elechain_t *ec, VkPipelineLayout layout, qfv_devfuncs_t *dfunc, VkCommandBuffer cmd) @@ -821,9 +834,9 @@ bsp_begin (vulkan_ctx_t *ctx) bframe->imageInfo[1].imageView = 0; // set by tex chain loop bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap); bframe->imageInfo[3].imageView = get_view (bctx->skysheet_tex, - ctx->default_skysheet); + bctx->default_skysheet); bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, - ctx->default_skybox); + bctx->default_skybox); dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { @@ -856,10 +869,9 @@ bsp_begin (vulkan_ctx_t *ctx) bctx->layout, 0, 1, bframe->descriptors + 0); // push static images - // XXX sky sheet and box not pushed yet dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, bctx->layout, - 0, 1, bframe->descriptors + 3); + 0, 3, bframe->descriptors + 3); //XXX glsl_Fog_GetColor (fog); //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; @@ -926,7 +938,7 @@ turb_end (bspctx_t *bctx) qfeglBindBuffer (GL_ARRAY_BUFFER, 0); }*/ -/*XXX static void +static void spin (mat4_t mat, bspctx_t *bctx) { quat_t q; @@ -947,82 +959,88 @@ spin (mat4_t mat, bspctx_t *bctx) VectorNegate (r_origin, mat + 12); QuatToMatrix (q, m, 1, 1); Mat4Mult (m, mat, mat); -}*/ +} static void -sky_begin (bspctx_t *bctx) +sky_begin (vulkan_ctx_t *ctx) { - //XXX mat4_t mat; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; //XXX quat_t fog; bctx->default_color[3] = 1; QuatCopy (bctx->default_color, bctx->last_color); -/* qfeglVertexAttrib4fv (quake_bsp.color.location, bctx->default_color); - Mat4Mult (glsl_projection, glsl_view, bsp_vp); + //XXX glsl_Fog_GetColor (fog); + //fog[3] = glsl_Fog_GetDensity () / 64.0; + //qfeglUniform4fv (sky_params.fog->location, 1, fog); - if (bctx->skybox_tex) { - sky_params.mvp_matrix = &quake_skybox.mvp_matrix; - sky_params.vertex = &quake_skybox.vertex; - sky_params.sky_matrix = &quake_skybox.sky_matrix; - sky_params.fog = &quake_skybox.fog; + spin (ctx->matrices.sky_3d, bctx); - qfeglUseProgram (quake_skybox.program); - qfeglEnableVertexAttribArray (quake_skybox.vertex.location); + __auto_type cframe = &ctx->framebuffers.a[ctx->curFrame]; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + VkCommandBuffer cmd = bframe->sky_cmd; + DARRAY_APPEND (cframe->subCommand, cmd); - qfeglUniform1i (quake_skybox.sky.location, 0); - qfeglActiveTexture (GL_TEXTURE0 + 0); - qfeglEnable (GL_TEXTURE_CUBE_MAP); - qfeglBindTexture (GL_TEXTURE_CUBE_MAP, skybox_tex); - } else { - sky_params.mvp_matrix = &quake_skyid.mvp_matrix; - sky_params.sky_matrix = &quake_skyid.sky_matrix; - sky_params.vertex = &quake_skyid.vertex; - sky_params.fog = &quake_skyid.fog; + //FIXME need per frame matrices + bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; + bframe->imageInfo[0].imageView = ctx->default_magenta->view; + bframe->imageInfo[1].imageView = ctx->default_magenta->view; + bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap); + bframe->imageInfo[3].imageView = get_view (bctx->skysheet_tex, + bctx->default_skysheet); + bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, + bctx->default_skybox); - qfeglUseProgram (quake_skyid.program); - qfeglEnableVertexAttribArray (quake_skyid.vertex.location); + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + ctx->renderpass.renderpass, 0, + cframe->framebuffer, + 0, 0, 0, + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); - qfeglUniform1i (quake_skyid.palette.location, 2); - qfeglActiveTexture (GL_TEXTURE0 + 2); - qfeglEnable (GL_TEXTURE_2D); - qfeglBindTexture (GL_TEXTURE_2D, glsl_palette); + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + bctx->sky); + VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; + VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; + dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); - qfeglUniform1f (quake_skyid.time.location, vr_data.realtime); + VkDeviceSize offsets[] = { 0 }; + dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &bctx->vertex_buffer, offsets); + dfunc->vkCmdBindIndexBuffer (cmd, bctx->index_buffer, bframe->index_offset, + VK_INDEX_TYPE_UINT32); - qfeglUniform1i (quake_skyid.trans.location, 0); - qfeglActiveTexture (GL_TEXTURE0 + 0); - qfeglEnable (GL_TEXTURE_2D); + // push VP matrices + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + bctx->layout, + 0, 1, bframe->descriptors + 0); + // push static images + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + bctx->layout, + 0, 5, bframe->descriptors + 1); - qfeglUniform1i (quake_skyid.solid.location, 1); - qfeglActiveTexture (GL_TEXTURE0 + 1); - qfeglEnable (GL_TEXTURE_2D); - } - - glsl_Fog_GetColor (fog); - fog[3] = glsl_Fog_GetDensity () / 64.0; - qfeglUniform4fv (sky_params.fog->location, 1, fog); - - spin (mat); - qfeglUniformMatrix4fv (sky_params.sky_matrix->location, 1, false, mat); - - qfeglBindBuffer (GL_ARRAY_BUFFER, bsp_vbo);*/ + //XXX glsl_Fog_GetColor (fog); + //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; } static void -sky_end (bspctx_t *bctx) +sky_end (vulkan_ctx_t *ctx) { - /*XXX qfeglDisableVertexAttribArray (sky_params.vertex->location); + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; - qfeglActiveTexture (GL_TEXTURE0 + 0); - qfeglDisable (GL_TEXTURE_2D); - qfeglDisable (GL_TEXTURE_CUBE_MAP); - qfeglActiveTexture (GL_TEXTURE0 + 1); - qfeglDisable (GL_TEXTURE_2D); - qfeglActiveTexture (GL_TEXTURE0 + 2); - qfeglDisable (GL_TEXTURE_2D); - - qfeglBindBuffer (GL_ARRAY_BUFFER, 0);*/ + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + dfunc->vkEndCommandBuffer (bframe->sky_cmd); } static inline void @@ -1199,6 +1217,8 @@ Vulkan_DrawWaterSurfaces (vulkan_ctx_t *ctx) void Vulkan_DrawSky (vulkan_ctx_t *ctx) { + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; bspctx_t *bctx = ctx->bsp_context; bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; instsurf_t *is; @@ -1210,20 +1230,24 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) if (!bctx->sky_chain) return; - sky_begin (bctx); + sky_begin (ctx); + dfunc->vkCmdPushConstants (bframe->sky_cmd, bctx->layout, + VK_SHADER_STAGE_VERTEX_BIT, + 0, 16 * sizeof (float), identity); + float frag_pc[8] = { }; + dfunc->vkCmdPushConstants (bframe->sky_cmd, bctx->layout, + VK_SHADER_STAGE_FRAGMENT_BIT, + 64, 8 * sizeof (float), &frag_pc); for (is = bctx->sky_chain; is; is = is->tex_chain) { surf = is->surface; if (tex != surf->texinfo->texture->render) { if (tex) { - if (!bctx->skybox_tex) { - //XXX qfeglActiveTexture (GL_TEXTURE0 + 0); - //qfeglBindTexture (GL_TEXTURE_2D, tex->sky_tex[0]); - //qfeglActiveTexture (GL_TEXTURE0 + 1); - //qfeglBindTexture (GL_TEXTURE_2D, tex->sky_tex[1]); + bind_view (qfv_bsp_skysheet, + get_view (tex->tex, ctx->default_black), + bframe, bframe->sky_cmd, bctx->layout, dfunc); + for (ec = tex->elechain; ec; ec = ec->next) { + draw_elechain (ec, bctx->layout, dfunc, bframe->sky_cmd); } - //for (ec = tex->elechain; ec; ec = ec->next) - // draw_elechain (ec, sky_params.mvp_matrix->location, - // sky_params.vertex->location, -1, -1); tex->elechain = 0; tex->elechain_tail = &tex->elechain; } @@ -1232,24 +1256,123 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) add_surf_elements (tex, is, &ec, &el, bctx, bframe); } if (tex) { - if (!bctx->skybox_tex) { - //XXX qfeglActiveTexture (GL_TEXTURE0 + 0); - //qfeglBindTexture (GL_TEXTURE_2D, tex->sky_tex[0]); - //qfeglActiveTexture (GL_TEXTURE0 + 1); - //qfeglBindTexture (GL_TEXTURE_2D, tex->sky_tex[1]); + bind_view (qfv_bsp_skysheet, + get_view (tex->tex, ctx->default_black), + bframe, bframe->sky_cmd, bctx->layout, dfunc); + for (ec = tex->elechain; ec; ec = ec->next) { + draw_elechain (ec, bctx->layout, dfunc, bframe->sky_cmd); } - //for (ec = tex->elechain; ec; ec = ec->next) - // draw_elechain (ec, sky_params.mvp_matrix->location, - // sky_params.vertex->location, -1, -1); tex->elechain = 0; tex->elechain_tail = &tex->elechain; } - sky_end (bctx); + sky_end (ctx); bctx->sky_chain = 0; bctx->sky_chain_tail = &bctx->sky_chain; } +static void +create_default_skys (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + VkImage skybox; + VkImage skysheet; + VkDeviceMemory memory; + VkImageView boxview; + VkImageView sheetview; + + bctx->default_skybox = calloc (2, sizeof (qfv_tex_t)); + bctx->default_skysheet = bctx->default_skybox + 1; + + VkExtent3D extents = { 1, 1, 1 }; + skybox = QFV_CreateImage (device, 1, VK_IMAGE_TYPE_2D, + VK_FORMAT_B8G8R8A8_UNORM, extents, 1, 1, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + + skysheet = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, + VK_FORMAT_B8G8R8A8_UNORM, extents, 1, 2, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + VkMemoryRequirements requirements; + dfunc->vkGetImageMemoryRequirements (device->dev, skybox, &requirements); + size_t boxsize = requirements.size; + dfunc->vkGetImageMemoryRequirements (device->dev, skysheet, &requirements); + size_t sheetsize = requirements.size; + + memory = QFV_AllocImageMemory (device, skybox, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + boxsize + sheetsize, + VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT); + + QFV_BindImageMemory (device, skybox, memory, 0); + QFV_BindImageMemory (device, skysheet, memory, boxsize); + + boxview = QFV_CreateImageView (device, skybox, VK_IMAGE_VIEW_TYPE_CUBE, + VK_FORMAT_B8G8R8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); + + sheetview = QFV_CreateImageView (device, skysheet, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + VK_FORMAT_B8G8R8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); + + bctx->default_skybox->image = skybox; + bctx->default_skybox->view = boxview; + bctx->default_skybox->memory = memory; + bctx->default_skysheet->image = skysheet; + bctx->default_skysheet->view = sheetview; + + // temporarily commandeer the light map's staging buffer + qfv_packet_t *packet = QFV_PacketAcquire (bctx->light_stage); + VkImageMemoryBarrier barrier; + VkImageMemoryBarrier barriers[2]; + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + barriers[0] = barrier; + barriers[1] = barrier; + barriers[0].image = skybox; + barriers[1].image = skysheet; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 2, barriers); + + VkClearColorValue color = {}; + VkImageSubresourceRange range = { + VK_IMAGE_ASPECT_COLOR_BIT, + 0, VK_REMAINING_MIP_LEVELS, + 0, VK_REMAINING_ARRAY_LAYERS + }; + dfunc->vkCmdClearColorImage (packet->cmd, skybox, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &color, 1, &range); + dfunc->vkCmdClearColorImage (packet->cmd, skysheet, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &color, 1, &range); + + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + barriers[0] = barrier; + barriers[1] = barrier; + barriers[0].image = skybox; + barriers[1].image = skysheet; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 2, barriers); + QFV_PacketSubmit (packet); +} + static VkDescriptorBufferInfo base_buffer_info = { 0, 0, VK_WHOLE_SIZE }; @@ -1288,6 +1411,8 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) size_t size = QFV_ScrapSize (bctx->light_scrap); bctx->light_stage = QFV_CreateStagingBuffer (device, size, ctx->cmdpool); + create_default_skys (ctx); + DARRAY_INIT (&bctx->texture_chains, 64); size_t frames = ctx->framebuffers.size; @@ -1296,6 +1421,7 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bctx->frames.grow = 0; bctx->main = Vulkan_CreatePipeline (ctx, "quakebsp.main"); + bctx->sky = Vulkan_CreatePipeline (ctx, "quakebsp.skysheet"); bctx->layout = QFV_GetPipelineLayout (ctx, "quakebsp"); bctx->sampler = QFV_GetSampler (ctx, "quakebsp"); @@ -1309,9 +1435,9 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) for (size_t i = 0; i < frames; i++) { __auto_type bframe = &bctx->frames.a[i]; - bframe->bsp_cmd = cmdBuffers->a[i]; - bframe->turb_cmd = cmdBuffers->a[i]; - bframe->sky_cmd = cmdBuffers->a[i]; + bframe->bsp_cmd = cmdBuffers->a[i * 3 + 0]; + bframe->turb_cmd = cmdBuffers->a[i * 3 + 1]; + bframe->sky_cmd = cmdBuffers->a[i * 3 + 2]; for (int j = 0; j < BSP_BUFFER_INFOS; j++) { bframe->bufferInfo[j] = base_buffer_info; @@ -1338,6 +1464,7 @@ Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx) bspctx_t *bctx = ctx->bsp_context; dfunc->vkDestroyPipeline (device->dev, bctx->main, 0); + dfunc->vkDestroyPipeline (device->dev, bctx->sky, 0); DARRAY_CLEAR (&bctx->texture_chains); DARRAY_CLEAR (&bctx->frames); QFV_DestroyStagingBuffer (bctx->light_stage); @@ -1350,6 +1477,14 @@ Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx) dfunc->vkDestroyBuffer (device->dev, bctx->index_buffer, 0); dfunc->vkFreeMemory (device->dev, bctx->index_memory, 0); } + + dfunc->vkDestroyImageView (device->dev, bctx->default_skysheet->view, 0); + dfunc->vkDestroyImage (device->dev, bctx->default_skysheet->image, 0); + + dfunc->vkDestroyImageView (device->dev, bctx->default_skybox->view, 0); + dfunc->vkDestroyImage (device->dev, bctx->default_skybox->image, 0); + dfunc->vkFreeMemory (device->dev, bctx->default_skybox->memory, 0); + free (bctx->default_skybox); } static inline __attribute__((const)) int From 145e7478a748e6df680403bbdbdcb15b24c83c93 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Jan 2021 23:56:33 +0900 Subject: [PATCH 287/435] [vid] Create a 32-bit version of the palette The 32-bit palette includes the alpha channel, with color 255's alpha set to 0. --- include/QF/vid.h | 1 + libs/video/targets/vid.c | 29 +++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/include/QF/vid.h b/include/QF/vid.h index 19618f66c..430e775ab 100644 --- a/include/QF/vid.h +++ b/include/QF/vid.h @@ -43,6 +43,7 @@ typedef struct { byte *gammatable; // 256 byte *basepal; // 256 * 3 byte *palette; // 256 * 3 + byte *palette32; // 256 * 4 includes alpha byte *colormap8; // 256 * VID_GRADES size unsigned short *colormap16; // 256 * VID_GRADES size unsigned int *colormap32; // 256 * VID_GRADES size diff --git a/libs/video/targets/vid.c b/libs/video/targets/vid.c index 651101539..b656b5a22 100644 --- a/libs/video/targets/vid.c +++ b/libs/video/targets/vid.c @@ -200,6 +200,10 @@ void VID_UpdateGamma (cvar_t *vid_gamma) { double gamma = bound (0.1, vid_gamma->value, 9.9); + byte *p24; + byte *p32; + byte *col; + int i; viddef.recalc_refdef = 1; // force a surface cache flush @@ -207,13 +211,29 @@ VID_UpdateGamma (cvar_t *vid_gamma) Sys_MaskPrintf (SYS_VID, "Setting hardware gamma to %g\n", gamma); VID_BuildGammaTable (1.0); // hardware gamma wants a linear palette VID_SetGamma (gamma); - memcpy (viddef.palette, viddef.basepal, 256 * 3); + p24 = viddef.palette; + p32 = viddef.palette32; + col = viddef.basepal; + for (i = 0; i < 256; i++) { + *p32++ = *p24++ = *col++; + *p32++ = *p24++ = *col++; + *p32++ = *p24++ = *col++; + *p32++ = 255; + } + p32[-1] = 0; // color 255 is transparent } else { // We have to hack the palette - int i; Sys_MaskPrintf (SYS_VID, "Setting software gamma to %g\n", gamma); VID_BuildGammaTable (gamma); - for (i = 0; i < 256 * 3; i++) - viddef.palette[i] = viddef.gammatable[viddef.basepal[i]]; + p24 = viddef.palette; + p32 = viddef.palette32; + col = viddef.basepal; + for (i = 0; i < 256; i++) { + *p32++ = *p24++ = viddef.gammatable[*col++]; + *p32++ = *p24++ = viddef.gammatable[*col++]; + *p32++ = *p24++ = viddef.gammatable[*col++]; + *p32++ = 255; + } + p32[-1] = 0; // color 255 is transparent viddef.vid_internal->set_palette (viddef.palette); // update with the new palette } } @@ -232,6 +252,7 @@ VID_InitGamma (unsigned char *pal) viddef.gammatable = malloc (256); viddef.basepal = pal; viddef.palette = malloc (256 * 3); + viddef.palette32 = malloc (256 * 4); if ((i = COM_CheckParm ("-gamma"))) { gamma = atof (com_argv[i + 1]); } From 3132aa91a82f4d205cc38cb7b0f357077e6fa498 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 23 Jan 2021 23:58:34 +0900 Subject: [PATCH 288/435] [vulkan] Get sky sheets working The sky texture is loaded with black's alpha set to 0. While this does hit both layers, the screen is cleared to black so it shouldn't be a problem (and will allow having a skybox behind the sheets). --- include/QF/Vulkan/qf_bsp.h | 5 +++++ libs/models/brush/vulkan_model_brush.c | 16 ++++++++++++---- libs/video/renderer/vulkan/quakebsp.frag | 2 +- libs/video/renderer/vulkan/vulkan_bsp.c | 16 +++++++--------- libs/video/renderer/vulkan/vulkan_texture.c | 11 ++++++++++- 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index 969fdd92c..151e6e7be 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -81,6 +81,11 @@ typedef struct bspframe_s { VkWriteDescriptorSet descriptors[BSP_BUFFER_INFOS + BSP_IMAGE_INFOS]; } bspframe_t; +typedef struct fragconst_s { + quat_t fog; + float time; +} fragconst_t; + typedef struct bspframeset_s DARRAY_TYPE (bspframe_t) bspframeset_t; diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index b64e8c11f..c9b336f0f 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -101,7 +101,7 @@ get_image_size (VkImage image, qfv_device_t *device) } static void -transfer_mips (byte *dst, const void *_src, const texture_t *tx) +transfer_mips (byte *dst, const void *_src, const texture_t *tx, byte *palette) { const byte *src = _src; unsigned width = tx->width; @@ -113,7 +113,7 @@ transfer_mips (byte *dst, const void *_src, const texture_t *tx) // end of the texture struct offset = tx->offsets[i] - sizeof (texture_t); count = width * height; - Vulkan_ExpandPalette (dst, src + offset, vid.palette, 1, count); + Vulkan_ExpandPalette (dst, src + offset, palette, 2, count); dst += count * 4; width >>= 1; height >>= 1; @@ -218,6 +218,7 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) for (int i = 0; i < model->numtextures; i++) { texture_t *tx = model->textures[i]; + byte *palette = vid.palette32; if (!tx) { continue; } @@ -227,12 +228,18 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) tex->tex->offset); VkImageViewType type = VK_IMAGE_VIEW_TYPE_2D; if (strncmp (tx->name, "sky", 3) == 0) { + palette = alloca (256 * 4); + memcpy (palette, vid.palette32, 256 * 4); + // sky's black is transparent + // this hits both layers, but so long as the screen is cleared + // to black, no one should notice :) + palette[3] = 0; type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; } tex->tex->view = QFV_CreateImageView (device, tex->tex->image, type, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); - transfer_mips (buffer + tex->tex->offset, tx + 1, tx); + transfer_mips (buffer + tex->tex->offset, tx + 1, tx, palette); if (tex->glow) { dfunc->vkBindImageMemory (device->dev, tex->glow->image, mem, tex->glow->offset); @@ -242,7 +249,8 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); - transfer_mips (buffer + tex->glow->offset, tex->glow->memory, tx); + transfer_mips (buffer + tex->glow->offset, tex->glow->memory, tx, + palette); } } diff --git a/libs/video/renderer/vulkan/quakebsp.frag b/libs/video/renderer/vulkan/quakebsp.frag index 483a3887e..fe596246e 100644 --- a/libs/video/renderer/vulkan/quakebsp.frag +++ b/libs/video/renderer/vulkan/quakebsp.frag @@ -8,8 +8,8 @@ layout (set = 0, binding = 5) uniform samplerCube SkyCube; layout (push_constant) uniform PushConstants { layout (offset = 64) - float time; vec4 fog; + float time; }; layout (location = 0) in vec4 tl_st; diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index bfd54f9e8..6da253bea 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -908,6 +908,9 @@ turb_begin (bspctx_t *bctx) glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; + fragconst_t frag_constants = { time: vr_data.realtime }; + dfunc->vkCmdPushConstants (cmd, bctx->layout, VK_SHADER_STAGE_FRAGMENT_BIT, + 64, sizeof (fragconst_t), &frag_constants); qfeglUniform4fv (quake_turb.fog.location, 1, fog); qfeglUniform1i (quake_turb.palette.location, 1); @@ -967,15 +970,10 @@ sky_begin (vulkan_ctx_t *ctx) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; bspctx_t *bctx = ctx->bsp_context; - //XXX quat_t fog; bctx->default_color[3] = 1; QuatCopy (bctx->default_color, bctx->last_color); - //XXX glsl_Fog_GetColor (fog); - //fog[3] = glsl_Fog_GetDensity () / 64.0; - //qfeglUniform4fv (sky_params.fog->location, 1, fog); - spin (ctx->matrices.sky_3d, bctx); __auto_type cframe = &ctx->framebuffers.a[ctx->curFrame]; @@ -1121,10 +1119,10 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) dfunc->vkCmdPushConstants (bframe->bsp_cmd, bctx->layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 16 * sizeof (float), identity); - float frag_pc[8] = { }; + fragconst_t frag_constants = { time: vr_data.realtime }; dfunc->vkCmdPushConstants (bframe->bsp_cmd, bctx->layout, VK_SHADER_STAGE_FRAGMENT_BIT, - 64, 8 * sizeof (float), &frag_pc); + 64, sizeof (fragconst_t), &frag_constants); //XXX qfeglActiveTexture (GL_TEXTURE0 + 0); for (size_t i = 0; i < bctx->texture_chains.size; i++) { vulktex_t *tex; @@ -1234,10 +1232,10 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) dfunc->vkCmdPushConstants (bframe->sky_cmd, bctx->layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 16 * sizeof (float), identity); - float frag_pc[8] = { }; + fragconst_t frag_constants = { time: vr_data.realtime }; dfunc->vkCmdPushConstants (bframe->sky_cmd, bctx->layout, VK_SHADER_STAGE_FRAGMENT_BIT, - 64, 8 * sizeof (float), &frag_pc); + 64, sizeof (fragconst_t), &frag_constants); for (is = bctx->sky_chain; is; is = is->tex_chain) { surf = is->surface; if (tex != surf->texinfo->texture->render) { diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index 86bd890ab..c1a4e28f0 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -89,7 +89,16 @@ void Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, int alpha, int count) { - if (alpha) { + if (alpha > 1) { + while (count-- > 0) { + int pix = *src++; + const byte *col = palette + pix * 4; + *dst++ = *col++; + *dst++ = *col++; + *dst++ = *col++; + *dst++ = *col++; + } + } else if (alpha) { while (count-- > 0) { byte pix = *src++; const byte *col = palette + pix * 3; From ada4f37b9d574d67e015b614d8149a68cf3a3395 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 24 Jan 2021 00:26:38 +0900 Subject: [PATCH 289/435] [vulkan] Fix the over-bright dynamic lights I doubt they're anywhere near right, but they're much better. At least they're not just solid blocks of white. --- libs/video/renderer/vulkan/vulkan_lightmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/vulkan_lightmap.c b/libs/video/renderer/vulkan/vulkan_lightmap.c index 6c74ab802..0eeed8546 100644 --- a/libs/video/renderer/vulkan/vulkan_lightmap.c +++ b/libs/video/renderer/vulkan/vulkan_lightmap.c @@ -114,7 +114,7 @@ add_dynamic_lights (msurface_t *surf, float *block) } if (dist < minlight) { float *out = block + (t * smax + s) * LUXEL_SIZE; - float l = (rad - dist) * 256; + float l = (rad - dist); VectorMultAdd (out, l, light->color, out); out[3] = 1; out += LUXEL_SIZE; From af5415010afeb1ed34f0a44f1ece1136e36c9c68 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 24 Jan 2021 00:54:26 +0900 Subject: [PATCH 290/435] [vulkan] Clamp the conback lines to the texture height Fixes the bad background (with deadbeef scrap) --- libs/video/renderer/vulkan/vulkan_draw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 6ec67b227..f4bf8c19e 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -613,6 +613,7 @@ Vulkan_Draw_ConsoleBackground (int lines, byte alpha, vulkan_ctx_t *ctx) qpic_t *cpic; cpic = Vulkan_Draw_CachePic ("gfx/conback.lmp", false, ctx); int ofs = max (0, cpic->height - lines); + lines = min (lines, cpic->height); draw_pic (0, 0, vid.conwidth, lines, cpic, 0, ofs, cpic->width, lines, color, frame); } From 7a19be7265f7396f26c3ecdcc198fff28fe52aaa Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 25 Jan 2021 00:54:41 +0900 Subject: [PATCH 291/435] [image] Change tex_t data from array to pointer This makes tex_t more generally useable and probably more portable. The goal was to be able to use tex_t with data that is in a separate chunk of memory. --- include/QF/image.h | 2 +- libs/image/pcx.c | 6 ++++-- libs/image/png.c | 6 ++++-- libs/image/tga.c | 3 ++- libs/models/gl_skin.c | 6 ++++-- libs/models/iqm/sw_model_iqm.c | 8 ++++---- libs/models/skin.c | 3 ++- libs/video/renderer/gl/gl_screen.c | 6 ++++-- libs/video/renderer/glsl/glsl_bsp.c | 3 ++- libs/video/renderer/glsl/glsl_screen.c | 3 ++- libs/video/renderer/r_dyn_textures.c | 9 ++++++--- libs/video/renderer/sw/screen.c | 6 ++++-- libs/video/renderer/sw32/screen.c | 3 ++- libs/video/renderer/vulkan/vulkan_texture.c | 9 ++++++--- 14 files changed, 47 insertions(+), 26 deletions(-) diff --git a/include/QF/image.h b/include/QF/image.h index 62d57dd35..c7830c832 100644 --- a/include/QF/image.h +++ b/include/QF/image.h @@ -48,7 +48,7 @@ typedef struct tex_s { QFFormat format; int loaded; // 0 if size info only, otherwise data loaded byte *palette; // 0 = 32 bit, otherwise 8 - byte data[4]; // variable length + byte *data; } tex_t; tex_t *LoadImage (const char *imageFile, int load); diff --git a/libs/image/pcx.c b/libs/image/pcx.c index 495b1b1d5..bfa4fc88d 100644 --- a/libs/image/pcx.c +++ b/libs/image/pcx.c @@ -93,11 +93,13 @@ LoadPCX (QFile *f, qboolean convert, byte *pal, int load) count = load ? (pcx->xmax + 1) * (pcx->ymax + 1) : 0; if (convert) { - tex = Hunk_TempAlloc (field_offset (tex_t, data[count * 3])); + tex = Hunk_TempAlloc (sizeof (tex_t) + count * 3); + tex->data = (byte *) (tex + 1); tex->format = tex_rgb; tex->palette = 0; } else { - tex = Hunk_TempAlloc (field_offset (tex_t, data[count])); + tex = Hunk_TempAlloc (sizeof (tex_t) + count); + tex->data = (byte *) (tex + 1); tex->format = tex_palette; if (pal) tex->palette = pal; diff --git a/libs/image/png.c b/libs/image/png.c index 9e81ca138..ddf9066a9 100644 --- a/libs/image/png.c +++ b/libs/image/png.c @@ -162,9 +162,11 @@ LoadPNG (QFile *infile, int load) /* Allocate tex_t structure */ rowbytes = png_get_rowbytes(png_ptr, info_ptr); - tex = Hunk_TempAlloc (field_offset (tex_t, data[height * rowbytes])); + tex = Hunk_TempAlloc (sizeof (tex_t) + height * rowbytes); + tex->data = (byte *) (tex + 1); } else { - tex = Hunk_TempAlloc (field_offset (tex_t, data[0])); + tex = Hunk_TempAlloc (sizeof (tex_t)); + tex->data = 0; } tex->width = width; diff --git a/libs/image/tga.c b/libs/image/tga.c index 1a4dad133..1f72e2687 100644 --- a/libs/image/tga.c +++ b/libs/image/tga.c @@ -655,7 +655,8 @@ LoadTGA (QFile *fin, int load) } else { numPixels = 0; } - tex = Hunk_TempAlloc (field_offset (tex_t, data[numPixels * 4])); + tex = Hunk_TempAlloc (sizeof (tex_t) + numPixels * 4); + tex->data = (byte *) (tex + 1); tex->width = targa->width; tex->height = targa->height; tex->palette = 0; diff --git a/libs/models/gl_skin.c b/libs/models/gl_skin.c index 442def004..e88fbf2d6 100644 --- a/libs/models/gl_skin.c +++ b/libs/models/gl_skin.c @@ -72,7 +72,8 @@ do_fb_skin (glskin_t *s) { int size = s->tex->width * s->tex->height; - s->fb_tex = realloc (s->fb_tex, field_offset(tex_t, data[size])); + s->fb_tex = realloc (s->fb_tex, sizeof (tex_t) + size); + s->fb_tex->data = (byte *) (s->fb_tex + 1); s->fb_tex->width = s->tex->width; s->fb_tex->height = s->tex->height; s->fb_tex->format = tex_palette; @@ -87,7 +88,8 @@ gl_Skin_SetPlayerSkin (int width, int height, const byte *data) glskin_t *s; s = &player_skin; - s->tex = realloc (s->tex, field_offset(tex_t, data[size])); + s->tex = realloc (s->tex, sizeof (tex_t) + size); + s->tex->data = (byte *) (s->tex + 1); s->tex->width = width; s->tex->height = height; s->tex->format = tex_palette; diff --git a/libs/models/iqm/sw_model_iqm.c b/libs/models/iqm/sw_model_iqm.c index 582109a73..274a6f0a9 100644 --- a/libs/models/iqm/sw_model_iqm.c +++ b/libs/models/iqm/sw_model_iqm.c @@ -53,9 +53,8 @@ #include "mod_internal.h" #include "r_internal.h" -static tex_t null_texture = { - 2, 2, tex_palette, 1, 0, {15, 15, 15, 15} -}; +static byte null_data[] = {15, 15, 15, 15}; +static tex_t null_texture = { 2, 2, tex_palette, 1, 0, null_data }; static void sw_iqm_clear (model_t *mod, void *data) @@ -109,7 +108,8 @@ convert_tex (tex_t *tex) int i; pixels = tex->width * tex->height; - new = malloc (field_offset (tex_t, data[pixels])); + new = malloc (sizeof (tex_t) + pixels); + new->data = (byte *) (new + 1); new->width = tex->width; new->height = tex->height; new->format = tex_palette; diff --git a/libs/models/skin.c b/libs/models/skin.c index 5e1fe0d85..9897a4143 100644 --- a/libs/models/skin.c +++ b/libs/models/skin.c @@ -193,7 +193,8 @@ Skin_SetSkin (skin_t *skin, int cmap, const char *skinname) tex = 0; break; } - out = malloc (field_offset (tex_t, data[PLAYER_WIDTH*PLAYER_HEIGHT])); + out = malloc (sizeof (tex_t) + PLAYER_WIDTH*PLAYER_HEIGHT); + out->data = (byte *) (out + 1); out->width = PLAYER_WIDTH; out->height = PLAYER_HEIGHT; out->format = tex_palette; diff --git a/libs/video/renderer/gl/gl_screen.c b/libs/video/renderer/gl/gl_screen.c index 5758b5941..f8b0e6546 100644 --- a/libs/video/renderer/gl/gl_screen.c +++ b/libs/video/renderer/gl/gl_screen.c @@ -70,7 +70,8 @@ gl_SCR_CaptureBGR (void) tex_t *tex; count = vid.width * vid.height; - tex = malloc (field_offset (tex_t, data[count * 3])); + tex = malloc (sizeof (tex_t) + count * 3); + tex->data = (byte *) (tex + 1); SYS_CHECKMEM (tex); tex->width = vid.width; tex->height = vid.height; @@ -100,7 +101,8 @@ gl_SCR_ScreenShot (int width, int height) fracw = (float) vid.width / (float) w; frach = (float) vid.height / (float) h; - tex = malloc (field_offset (tex_t, data[w * h])); + tex = malloc (sizeof (tex_t) + w * h); + tex->data = (byte *) (tex + 1); if (!tex) return 0; diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index 409450901..144f8094c 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -1409,7 +1409,8 @@ glsl_R_LoadSkys (const char *sky) int size = tex->height / 2; skybox_loaded = true; - sub = malloc (field_offset (tex_t, data[size * size * tex->format])); + sub = malloc (sizeof (tex_t) + size * size * tex->format); + sub->data = (byte *) (sub + 1); sub->width = size; sub->height = size; sub->format = tex->format; diff --git a/libs/video/renderer/glsl/glsl_screen.c b/libs/video/renderer/glsl/glsl_screen.c index 098f6a816..a19d3205a 100644 --- a/libs/video/renderer/glsl/glsl_screen.c +++ b/libs/video/renderer/glsl/glsl_screen.c @@ -201,7 +201,8 @@ glsl_SCR_CaptureBGR (void) tex_t *tex; count = vid.width * vid.height; - tex = malloc (field_offset (tex_t, data[count * 3])); + tex = malloc (sizeof (tex_t) + count * 3); + tex->data = (byte *) (tex + 1); SYS_CHECKMEM (tex); tex->width = vid.width; tex->height = vid.height; diff --git a/libs/video/renderer/r_dyn_textures.c b/libs/video/renderer/r_dyn_textures.c index 167027fad..67b0862c6 100644 --- a/libs/video/renderer/r_dyn_textures.c +++ b/libs/video/renderer/r_dyn_textures.c @@ -50,7 +50,8 @@ R_DotParticleTexture (void) int x, y, dx2, dy, d; tex_t *tex; - tex = malloc (field_offset (tex_t, data[sizeof (*data)])); + tex = malloc (sizeof (tex_t) + sizeof (*data)); + tex->data = (byte *) (tex + 1); tex->width = 32; tex->height = 32; tex->format = tex_la; @@ -79,7 +80,8 @@ R_SparkParticleTexture (void) int x, y, dx2, dy, d; tex_t *tex; - tex = malloc (field_offset (tex_t, data[sizeof (*data)])); + tex = malloc (sizeof (tex_t) + sizeof (*data)); + tex->data = (byte*) (tex + 1); tex->width = 32; tex->height = 32; tex->format = tex_la; @@ -113,7 +115,8 @@ R_SmokeParticleTexture (void) int x, y, c; tex_t *tex; - tex = malloc (field_offset (tex_t, data[sizeof (*data)])); + tex = malloc (sizeof (tex_t) + sizeof (*data)); + tex->data = (byte *) (tex + 1); tex->width = 32; tex->height = 32; tex->format = tex_la; diff --git a/libs/video/renderer/sw/screen.c b/libs/video/renderer/sw/screen.c index 4ab9302c1..125d8648f 100644 --- a/libs/video/renderer/sw/screen.c +++ b/libs/video/renderer/sw/screen.c @@ -64,7 +64,8 @@ SCR_CaptureBGR (void) byte *dst; count = vid.width * vid.height; - tex = malloc (field_offset (tex_t, data[count * 3])); + tex = malloc (sizeof (tex_t) + count * 3); + tex->data = (byte *) (tex + 1); SYS_CHECKMEM (tex); tex->width = vid.width; tex->height = vid.height; @@ -102,7 +103,8 @@ SCR_ScreenShot (int width, int height) fracw = (float) vid.width / (float) w; frach = (float) vid.height / (float) h; - tex = malloc (field_offset (tex_t, data[w * h])); + tex = malloc (sizeof (tex_t) + w * h); + tex->data = (byte *) (tex + 1); if (!tex) return 0; diff --git a/libs/video/renderer/sw32/screen.c b/libs/video/renderer/sw32/screen.c index 543c8602a..ce84cb08c 100644 --- a/libs/video/renderer/sw32/screen.c +++ b/libs/video/renderer/sw32/screen.c @@ -67,7 +67,8 @@ sw32_SCR_CaptureBGR (void) byte *dst; count = vid.width * vid.height; - tex = malloc (field_offset (tex_t, data[count * 3])); + tex = malloc (sizeof (tex_t) + count * 3); + tex->data = (byte *) (tex + 1); SYS_CHECKMEM (tex); tex->width = vid.width; tex->height = vid.height; diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index c1a4e28f0..07bcc7f0a 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -282,9 +282,12 @@ Vulkan_UnloadTex (vulkan_ctx_t *ctx, qfv_tex_t *tex) free (tex); } -static tex_t default_black_tex = {1, 1, tex_rgba, 1, 0, {0, 0, 0, 0 }}; -static tex_t default_white_tex = {1, 1, tex_rgba, 1, 0, {255, 255, 255, 255 }}; -static tex_t default_magenta_tex = {1, 1, tex_rgba, 1, 0, {255, 0, 255, 255 }}; +static byte black_data[] = {0, 0, 0, 0}; +static byte white_data[] = {255, 255, 255, 255}; +static byte magenta_data[] = {255, 0, 255, 255}; +static tex_t default_black_tex = {1, 1, tex_rgba, 1, 0, black_data}; +static tex_t default_white_tex = {1, 1, tex_rgba, 1, 0, white_data}; +static tex_t default_magenta_tex = {1, 1, tex_rgba, 1, 0, magenta_data}; void Vulkan_Texture_Init (vulkan_ctx_t *ctx) From d8b81e86787ec19a6d4dc1e92cecb5fb5768fbea Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 25 Jan 2021 13:31:41 +0900 Subject: [PATCH 292/435] [models] Remove MAXALIASFRAMES The dynamic array macros made this much easier than last time I looked at it, especially when it came to figuring out the bad memory accesses that I seem to remember from my last attempt 9 years ago. --- include/QF/model.h | 11 +++++---- libs/models/alias/gl_mesh.c | 32 ++++++++++++------------- libs/models/alias/glsl_model_alias.c | 6 ++--- libs/models/alias/model_alias.c | 36 ++++++++++------------------ libs/models/alias/sw_model_alias.c | 12 +++++----- 5 files changed, 44 insertions(+), 53 deletions(-) diff --git a/include/QF/model.h b/include/QF/model.h index 8d0129721..703d11227 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -28,6 +28,7 @@ #ifndef __QF_model_h #define __QF_model_h +#include "QF/darray.h" #include "QF/qtypes.h" #include "QF/bspfile.h" #include "QF/spritegn.h" @@ -320,11 +321,13 @@ typedef struct { maliasframedesc_t frames[1]; } aliashdr_t; -#define MAXALIASFRAMES 256 +typedef struct stvertset_s DARRAY_TYPE (stvert_t) stvertset_t; +typedef struct mtriangleset_s DARRAY_TYPE (mtriangle_t) mtriangleset_t; +typedef struct trivertxset_s DARRAY_TYPE (trivertx_t *) trivertxset_t; extern aliashdr_t *pheader; -extern stvert_t *stverts; -extern mtriangle_t *triangles; -extern trivertx_t *poseverts[MAXALIASFRAMES]; +extern stvertset_t stverts; +extern mtriangleset_t triangles; +extern trivertxset_t poseverts; extern int aliasbboxmins[3]; extern int aliasbboxmaxs[3]; diff --git a/libs/models/alias/gl_mesh.c b/libs/models/alias/gl_mesh.c index 22498ddea..c55225057 100644 --- a/libs/models/alias/gl_mesh.c +++ b/libs/models/alias/gl_mesh.c @@ -133,7 +133,7 @@ StripLength (int starttri, int startv) used[starttri] = 2; - last = &triangles[starttri]; + last = &triangles.a[starttri]; stripcount = 0; add_strip (last->vertindex[(startv) % 3], starttri); @@ -145,7 +145,7 @@ StripLength (int starttri, int startv) // look for a matching triangle nexttri: - for (j = starttri + 1, check = &triangles[starttri + 1]; + for (j = starttri + 1, check = &triangles.a[starttri + 1]; j < pheader->mdl.numtris; j++, check++) { if (check->facesfront != last->facesfront) continue; @@ -191,7 +191,7 @@ FanLength (int starttri, int startv) used[starttri] = 2; - last = &triangles[starttri]; + last = &triangles.a[starttri]; stripcount = 0; add_strip (last->vertindex[(startv) % 3], starttri); @@ -204,7 +204,7 @@ FanLength (int starttri, int startv) // look for a matching triangle nexttri: - for (j = starttri + 1, check = &triangles[starttri + 1]; + for (j = starttri + 1, check = &triangles.a[starttri + 1]; j < pheader->mdl.numtris; j++, check++) { if (check->facesfront != last->facesfront) continue; @@ -304,9 +304,9 @@ BuildTris (void) add_vertex (k); // emit s/t coords into the commands stream - s = stverts[k].s; - t = stverts[k].t; - if (!triangles[besttris[0]].facesfront && stverts[k].onseam) + s = stverts.a[k].s; + t = stverts.a[k].t; + if (!triangles.a[besttris[0]].facesfront && stverts.a[k].onseam) s += pheader->mdl.skinwidth / 2; // on back side s = (s + 0.5) / pheader->mdl.skinwidth; t = (t + 0.5) / pheader->mdl.skinheight; @@ -485,9 +485,9 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, numorder = 0; for (i=0; i < pheader->mdl.numtris; i++) { - add_vertex(triangles[i].vertindex[0]); - add_vertex(triangles[i].vertindex[1]); - add_vertex(triangles[i].vertindex[2]); + add_vertex(triangles.a[i].vertindex[0]); + add_vertex(triangles.a[i].vertindex[1]); + add_vertex(triangles.a[i].vertindex[2]); } paliashdr->poseverts = numorder; @@ -497,9 +497,9 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, float s, t; int k; k = vertexorder[i]; - s = stverts[k].s; - t = stverts[k].t; - if (!triangles[i/3].facesfront && stverts[k].onseam) + s = stverts.a[k].s; + t = stverts.a[k].t; + if (!triangles.a[i/3].facesfront && stverts.a[k].onseam) s += pheader->mdl.skinwidth / 2; // on back side s = (s + 0.5) / pheader->mdl.skinwidth; t = (t + 0.5) / pheader->mdl.skinheight; @@ -514,7 +514,7 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, * sizeof (trivertx16_t)); paliashdr->posedata = (byte *) verts - (byte *) paliashdr; for (i = 0; i < paliashdr->numposes; i++) { - trivertx_t *pv = poseverts[i]; + trivertx_t *pv = poseverts.a[i]; for (j = 0; j < numorder; j++) { trivertx16_t v; // convert MD16's split coordinates into something a little @@ -526,7 +526,7 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, VectorMultAdd (pv[vertexorder[j] + hdr->mdl.numverts].v, 256, pv[vertexorder[j]].v, v.v); v.lightnormalindex = - poseverts[i][vertexorder[j]].lightnormalindex; + poseverts.a[i][vertexorder[j]].lightnormalindex; *verts++ = v; } } @@ -537,7 +537,7 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, paliashdr->posedata = (byte *) verts - (byte *) paliashdr; for (i = 0; i < paliashdr->numposes; i++) { for (j = 0; j < numorder; j++) - *verts++ = poseverts[i][vertexorder[j]]; + *verts++ = poseverts.a[i][vertexorder[j]]; } } dstring_delete (cache); diff --git a/libs/models/alias/glsl_model_alias.c b/libs/models/alias/glsl_model_alias.c index 215c9d400..cb612e962 100644 --- a/libs/models/alias/glsl_model_alias.c +++ b/libs/models/alias/glsl_model_alias.c @@ -147,7 +147,7 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // copy triangles before editing them tris = malloc (numtris * sizeof (mtriangle_t)); - memcpy (tris, triangles, numtris * sizeof (mtriangle_t)); + memcpy (tris, triangles.a, numtris * sizeof (mtriangle_t)); // initialize indexmap to -1 (unduplicated). any other value indicates // both that the vertex has been duplicated and the index of the @@ -157,7 +157,7 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // copy stverts. need space for duplicates st = malloc (2 * numverts * sizeof (stvert_t)); - memcpy (st, stverts, numverts * sizeof (stvert_t)); + memcpy (st, stverts.a, numverts * sizeof (stvert_t)); // check for onseam verts, and duplicate any that are associated with // back-facing triangles. the s coordinate is shifted right by half @@ -182,7 +182,7 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, verts = malloc (vertexsize); for (i = 0, pose = 0; i < hdr->numposes; i++, pose += numverts) { for (j = 0; j < hdr->mdl.numverts; j++) { - pv = &poseverts[i][j]; + pv = &poseverts.a[i][j]; if (extra) { VectorMultAdd (pv[hdr->mdl.numverts].v, 256, pv->v, verts[pose + j].vertex); diff --git a/libs/models/alias/model_alias.c b/libs/models/alias/model_alias.c index 8a4784b2d..c5018f929 100644 --- a/libs/models/alias/model_alias.c +++ b/libs/models/alias/model_alias.c @@ -51,14 +51,12 @@ aliashdr_t *pheader; -stvert_t *stverts; -mtriangle_t *triangles; -int stverts_size = 0; -int triangles_size = 0; +stvertset_t stverts = { 0, 0, 256 }; +mtriangleset_t triangles = { 0, 0, 256 }; // a pose is a single set of vertexes. a frame may be an animating // sequence of poses -trivertx_t *poseverts[MAXALIASFRAMES]; +trivertxset_t poseverts = { 0, 0, 256 };; int posenum = 0; int aliasbboxmins[3], aliasbboxmaxs[3]; @@ -151,7 +149,7 @@ Mod_LoadAliasFrame (void *pin, int *posenum, maliasframedesc_t *frame, pinframe = (trivertx_t *) (pdaliasframe + 1); - poseverts[(*posenum)] = pinframe; + DARRAY_APPEND (&poseverts, pinframe); (*posenum)++; pinframe += pheader->mdl.numverts; @@ -264,30 +262,20 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) Sys_Error ("model %s has a skin taller than %d", mod->name, MAX_LBM_HEIGHT); + DARRAY_RESIZE (&poseverts, 0); pmodel->numverts = LittleLong (pinmodel->numverts); if (pmodel->numverts <= 0) Sys_Error ("model %s has no vertices", mod->name); - if (pmodel->numverts > stverts_size) { - stverts = realloc (stverts, pmodel->numverts * sizeof (stvert_t)); - if (!stverts) - Sys_Error ("model_alias: out of memory"); - stverts_size = pmodel->numverts; - } + DARRAY_RESIZE (&stverts, pmodel->numverts); pmodel->numtris = LittleLong (pinmodel->numtris); if (pmodel->numtris <= 0) Sys_Error ("model %s has no triangles", mod->name); - if (pmodel->numtris > triangles_size) { - triangles = realloc (triangles, - pmodel->numtris * sizeof (mtriangle_t)); - if (!triangles) - Sys_Error ("model_alias: out of memory"); - triangles_size = pmodel->numtris; - } + DARRAY_RESIZE (&triangles, pmodel->numtris); pmodel->numframes = LittleLong (pinmodel->numframes); numframes = pmodel->numframes; @@ -313,19 +301,19 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) pinstverts = (stvert_t *) pskintype; for (i = 0; i < pheader->mdl.numverts; i++) { - stverts[i].onseam = LittleLong (pinstverts[i].onseam); - stverts[i].s = LittleLong (pinstverts[i].s); - stverts[i].t = LittleLong (pinstverts[i].t); + stverts.a[i].onseam = LittleLong (pinstverts[i].onseam); + stverts.a[i].s = LittleLong (pinstverts[i].s); + stverts.a[i].t = LittleLong (pinstverts[i].t); } // load triangle lists pintriangles = (dtriangle_t *) &pinstverts[pheader->mdl.numverts]; for (i = 0; i < pheader->mdl.numtris; i++) { - triangles[i].facesfront = LittleLong (pintriangles[i].facesfront); + triangles.a[i].facesfront = LittleLong (pintriangles[i].facesfront); for (j = 0; j < 3; j++) { - triangles[i].vertindex[j] = + triangles.a[i].vertindex[j] = LittleLong (pintriangles[i].vertindex[j]); } } diff --git a/libs/models/alias/sw_model_alias.c b/libs/models/alias/sw_model_alias.c index b252ad474..e021278a4 100644 --- a/libs/models/alias/sw_model_alias.c +++ b/libs/models/alias/sw_model_alias.c @@ -79,7 +79,7 @@ process_frame (maliasframedesc_t *frame, int posenum, int extra) // from the high-order bits (see R_AliasTransformFinalVert16 in // sw_ralias.c), but in adjacant arrays. This means we can get away with // just one memcpy as there are no endian issues. - memcpy (frame_verts, poseverts[posenum], size); + memcpy (frame_verts, poseverts.a[posenum], size); } void @@ -101,14 +101,14 @@ sw_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, hdr->triangles = (byte *) ptri - (byte *) hdr; for (i = 0; i < numv; i++) { - pstverts[i].onseam = stverts[i].onseam; - pstverts[i].s = stverts[i].s << 16; - pstverts[i].t = stverts[i].t << 16; + pstverts[i].onseam = stverts.a[i].onseam; + pstverts[i].s = stverts.a[i].s << 16; + pstverts[i].t = stverts.a[i].t << 16; } for (i = 0; i < numt; i++) { - ptri[i].facesfront = triangles[i].facesfront; - VectorCopy (triangles[i].vertindex, ptri[i].vertindex); + ptri[i].facesfront = triangles.a[i].facesfront; + VectorCopy (triangles.a[i].vertindex, ptri[i].vertindex); } for (i = 0; i < pheader->mdl.numframes; i++) { From 3bbe33844ae76876aa7026be05566a8d365ef130 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Jan 2021 00:39:34 +0900 Subject: [PATCH 293/435] [util] Add component-wise vector mult-add/sub macros --- include/QF/math/vector.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/QF/math/vector.h b/include/QF/math/vector.h index 993cbaf08..630332907 100644 --- a/include/QF/math/vector.h +++ b/include/QF/math/vector.h @@ -74,6 +74,18 @@ extern const vec_t *const vec3_origin; (c)[1] = (a)[1] - (s) * (b)[1]; \ (c)[2] = (a)[2] - (s) * (b)[2]; \ } while (0) +#define VectorCompMultAdd(a,b,c,d) \ + do { \ + (d)[0] = (a)[0] + (b)[0] * (c)[0]; \ + (d)[1] = (a)[1] + (b)[1] * (c)[1]; \ + (d)[2] = (a)[2] + (b)[2] * (c)[2]; \ + } while (0) +#define VectorCompMultSub(a,b,c,d) \ + do { \ + (d)[0] = (a)[0] - (b)[0] * (c)[0]; \ + (d)[1] = (a)[1] - (b)[1] * (c)[1]; \ + (d)[2] = (a)[2] - (b)[2] * (c)[2]; \ + } while (0) #define VectorLength(a) sqrt(DotProduct(a, a)) #define VectorScale(a,b,c) \ From 57968249feb6ec0c8394148d75272909e54e967e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Jan 2021 00:55:45 +0900 Subject: [PATCH 294/435] [vulkan] Start work on the alias pipeline --- include/QF/Vulkan/qf_alias.h | 84 ++++++ include/QF/model.h | 13 +- libs/models/alias/vulkan_model_alias.c | 291 ++++++++++++++++++++ libs/video/renderer/Makemodule.am | 10 + libs/video/renderer/vid_render_vulkan.c | 6 +- libs/video/renderer/vulkan/alias.frag | 55 ++++ libs/video/renderer/vulkan/alias.vert | 38 +++ libs/video/renderer/vulkan/qfpipeline.plist | 201 +++++++++++++- libs/video/renderer/vulkan/shader.c | 6 + libs/video/renderer/vulkan/vulkan_bsp.c | 9 +- 10 files changed, 695 insertions(+), 18 deletions(-) create mode 100644 include/QF/Vulkan/qf_alias.h create mode 100644 libs/video/renderer/vulkan/alias.frag create mode 100644 libs/video/renderer/vulkan/alias.vert diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h new file mode 100644 index 000000000..efe3dd0dc --- /dev/null +++ b/include/QF/Vulkan/qf_alias.h @@ -0,0 +1,84 @@ +/* + qf_alias.h + + Vulkan specific brush model stuff + + Copyright (C) 2012 Bill Currie + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2012/1/7 + Date: 2021/1/18 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_qf_alias_h +#define __QF_Vulkan_qf_alias_h + +#include "QF/darray.h" +#include "QF/model.h" +#include "QF/modelgen.h" +#include "QF/Vulkan/qf_vid.h" + +typedef struct aliasvrt_s { + float vertex[4]; + float normal[4]; +} aliasvrt_t; + +typedef struct aliasuv_s { + float u, v; +} aliasuv_t; + +typedef struct qfv_alias_mesh_s { + VkBuffer vertex_buffer; + VkBuffer uv_buffer; + VkBuffer index_buffer; + VkDeviceMemory memory; +} qfv_alias_mesh_t; + +typedef struct qfv_light_s { + vec3_t color; + float dist; + vec3_t position; + int type; + vec3_t direction; + float cone; +} qfv_light_t; + +typedef struct qfv_light_buffer_s { + int light_count; + qfv_light_t lights[] __attribute__((aligned(16))); +} qfv_light_buffer_t; + +typedef struct alias_ctx_s { +} alias_ctx_t; + +struct vulkan_ctx_s; +void *Vulkan_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, + qboolean group, maliasskindesc_t *skindesc, + struct vulkan_ctx_s *ctx); +void Vulkan_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr, + struct vulkan_ctx_s *ctx); +void Vulkan_Mod_LoadExternalSkins (model_t *mod, struct vulkan_ctx_s *ctx); +void Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, + void *_m, int _s, int extra, + struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_alias_h diff --git a/include/QF/model.h b/include/QF/model.h index 703d11227..d1129bfce 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -277,10 +277,15 @@ typedef struct { } maliasframedesc_t; typedef struct { - aliasskintype_t type; - int skin; - int texnum; - int fb_texnum; + aliasskintype_t type; + int skin; + union { + struct { + int texnum; + int fb_texnum; + }; + void *tex; + }; } maliasskindesc_t; typedef struct { diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index e69de29bb..97801febc 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -0,0 +1,291 @@ +/* + vulkan_model_alais.c + + Alias model processing for Vulkan + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/1/24 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include + +#include "QF/va.h" + +#include "QF/modelgen.h" +#include "QF/vid.h" +#include "QF/Vulkan/qf_alias.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/staging.h" + +#include "mod_internal.h" +#include "r_internal.h" +#include "vid_vulkan.h" + +static vec3_t vertex_normals[NUMVERTEXNORMALS] = { +#include "anorms.h" +}; + +static void +vulkan_alias_clear (model_t *m, void *data) +{ +} + +void * +Vulkan_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, + qboolean group, maliasskindesc_t *skindesc, + vulkan_ctx_t *ctx) +{ + byte *tskin; + int w, h; + + w = pheader->mdl.skinwidth; + h = pheader->mdl.skinheight; + tskin = malloc (skinsize); + memcpy (tskin, skin, skinsize); + Mod_FloodFillSkin (tskin, w, h); + tex_t skin_tex = {w, h, tex_palette, 1, vid.palette, tskin}; + skindesc->tex = Vulkan_LoadTex (ctx, &skin_tex, 1); + free (tskin); + return skin + skinsize; +} + +void +Vulkan_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr, vulkan_ctx_t *ctx) +{ + if (hdr->mdl.ident == HEADER_MDL16) + VectorScale (hdr->mdl.scale, 1/256.0, hdr->mdl.scale); + m->clear = vulkan_alias_clear; +} + +void +Vulkan_Mod_LoadExternalSkins (model_t *mod, vulkan_ctx_t *ctx) +{ +} + +void +Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, + int _s, int extra, vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliasvrt_t *verts; + aliasuv_t *uv; + trivertx_t *pv; + int *indexmap; + uint32_t *indices; + int numverts; + int numtris; + int i, j; + int pose; + vec3_t pos; + + numverts = hdr->mdl.numverts; + numtris = hdr->mdl.numtris; + + // initialize indexmap to -1 (unduplicated). any other value indicates + // both that the vertex has been duplicated and the index of the + // duplicate vertex. + indexmap = malloc (numverts * sizeof (int)); + memset (indexmap, -1, numverts * sizeof (int)); + + // check for onseam verts, and duplicate any that are associated with + // back-facing triangles + for (i = 0; i < numtris; i++) { + for (j = 0; j < 3; j++) { + int vind = triangles.a[i].vertindex[j]; + if (stverts.a[vind].onseam && !triangles.a[i].facesfront) { + // duplicate the vertex if it has not alreaddy been + // duplicated + if (indexmap[vind] == -1) { + indexmap[vind] = numverts++; + } + } + } + } + + // we now know exactly how many vertices we need, so built the vertex + // and index data arrays + // The layout is: + // vbuf:{vertex, normal} * (numposes * numverts) + // uvbuf:{uv} * (numverts) + // ibuf:{index} * (numtris * 3) + // numverts includes the duplicated seam vertices. + // The vertex buffer will be bound with various offsets based on the + // current and previous pose, uvbuff "statically" bound as uvs are not + // animated by pose, and the same for ibuf: indices will never change for + // the mesh + size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; + size_t atom_mask = atom - 1; + size_t vert_count = numverts * hdr->numposes; + size_t vert_size = vert_count * sizeof (aliasvrt_t); + size_t uv_size = numverts * sizeof (aliasuv_t); + size_t ind_size = numverts * sizeof (uint32_t); + vert_size = (vert_size + atom_mask) & ~atom_mask; + uv_size = (uv_size + atom_mask) & ~atom_mask; + ind_size = (ind_size + atom_mask) & ~atom_mask; + size_t buff_size = vert_size + ind_size + uv_size; + + VkBuffer vbuff = QFV_CreateBuffer (device, buff_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + VkBuffer uvbuff = QFV_CreateBuffer (device, buff_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + VkBuffer ibuff = QFV_CreateBuffer (device, buff_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + VkDeviceMemory mem; + mem = QFV_AllocBufferMemory (device, vbuff, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + buff_size, 0); + QFV_BindBufferMemory (device, vbuff, mem, 0); + QFV_BindBufferMemory (device, uvbuff, mem, vert_size); + QFV_BindBufferMemory (device, ibuff, mem, vert_size + uv_size); + + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, buff_size, + ctx->cmdpool); + qfv_packet_t *packet = QFV_PacketAcquire (stage); + verts = QFV_PacketExtend (packet, vert_size); + uv = QFV_PacketExtend (packet, uv_size); + indices = QFV_PacketExtend (packet, ind_size); + + // populate the uvs, duplicating and shifting any that are on the seam + // and associated with back-facing triangles (marked by non-negative + // indexmap entry). + // the s coordinate is shifted right by half the skin width. + for (i = 0; i < hdr->mdl.numverts; i++) { + int vind = indexmap[i]; + uv[i].u = (float) stverts.a[i].s / hdr->mdl.skinwidth; + uv[i].v = (float) stverts.a[i].t / hdr->mdl.skinheight; + if (vind != -1) { + uv[vind] = uv[i]; + uv[vind].u += 0.5; + } + } + + // poputlate the vertex position and normal data, duplicating for + // back-facing on-seam verts (indicated by non-negative indexmap entry) + for (i = 0, pose = 0; i < hdr->numposes; i++, pose += numverts) { + for (j = 0; j < hdr->mdl.numverts; j++) { + pv = &poseverts.a[i][j]; + if (extra) { + VectorMultAdd (pv[hdr->mdl.numverts].v, 256, pv->v, pos); + } else { + VectorCopy (pv->v, pos); + } + VectorCompMultAdd (hdr->mdl.scale_origin, hdr->mdl.scale, + pos, verts[pose + j].vertex); + VectorCopy (vertex_normals[pv->lightnormalindex], + verts[pose + j].normal); + // duplicate on-seam vert associated with back-facing triangle + if (indexmap[j] != -1) { + verts[pose + indexmap[j]] = verts[pose + j]; + } + } + } + + // now build the indices for DrawElements + for (i = 0; i < numverts; i++) { + indexmap[i] = indexmap[i] != -1 ? indexmap[i] : i; + } + for (i = 0; i < numtris; i++) { + for (j = 0; j < 3; j++) { + indices[3 * i + j] = indexmap[triangles.a[i].vertindex[j]]; + } + } + // finished with indexmap + free (indexmap); + + hdr->poseverts = numverts; + + VkBufferMemoryBarrier wr_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + vbuff, 0, vert_size}, + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + uvbuff, 0, uv_size}, + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + ibuff, 0, ind_size}, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 3, wr_barriers, 0, 0); + VkBufferCopy copy_region[] = { + { packet->offset, 0, vert_size }, + { packet->offset + vert_size, 0, uv_size }, + { packet->offset + vert_size + uv_size, 0, ind_size }, + }; + dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer, + vbuff, 1, ©_region[0]); + dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer, + uvbuff, 1, ©_region[1]); + dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer, + ibuff, 1, ©_region[2]); + VkBufferMemoryBarrier rd_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + vbuff, 0, vert_size }, + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + uvbuff, 0, uv_size }, + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + ibuff, 0, ind_size }, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + 0, 0, 0, 1, rd_barriers, 0, 0); + QFV_PacketSubmit (packet); + QFV_DestroyStagingBuffer (stage); + + qfv_alias_mesh_t *mesh = Hunk_Alloc (sizeof (qfv_alias_mesh_t)); + mesh->vertex_buffer = vbuff; + mesh->uv_buffer = uvbuff; + mesh->index_buffer = ibuff; + mesh->memory = mem; + hdr->commands = (byte *) mesh - (byte *) hdr; +} diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 5a30c9f0c..e3b154541 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -269,6 +269,10 @@ quakebspv_src = libs/video/renderer/vulkan/quakebsp.vert quakebspv_c = libs/video/renderer/vulkan/quakebsp.vert.spvc quakebspf_src = libs/video/renderer/vulkan/quakebsp.frag quakebspf_c = libs/video/renderer/vulkan/quakebsp.frag.spvc +aliasv_src = libs/video/renderer/vulkan/alias.vert +aliasv_c = libs/video/renderer/vulkan/alias.vert.spvc +aliasf_src = libs/video/renderer/vulkan/alias.frag +aliasf_c = libs/video/renderer/vulkan/alias.frag.spvc passthrough_src = libs/video/renderer/vulkan/passthrough.vert passthrough_c = libs/video/renderer/vulkan/passthrough.vert.spvc pushcolor_src = libs/video/renderer/vulkan/pushcolor.frag @@ -282,6 +286,10 @@ $(quakebspv_c): $(quakebspv_src) $(quakebspf_c): $(quakebspf_src) +$(aliasv_c): $(aliasv_src) + +$(aliasf_c): $(aliasf_src) + $(passthrough_c): $(passthrough_src) $(pushcolor_c): $(pushcolor_src) @@ -291,6 +299,8 @@ vkshader_c = \ $(twodf_c) \ $(quakebspv_c) \ $(quakebspf_c) \ + $(aliasv_c) \ + $(aliasf_c) \ $(passthrough_c) \ $(pushcolor_c) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index a54962b52..2b001bcd3 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -39,6 +39,7 @@ #include "QF/plugin/general.h" #include "QF/plugin/vid_render.h" +#include "QF/Vulkan/qf_alias.h" #include "QF/Vulkan/qf_bsp.h" #include "QF/Vulkan/qf_draw.h" #include "QF/Vulkan/qf_lightmap.h" @@ -419,18 +420,21 @@ static void vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, int _s, int extra) { + Vulkan_Mod_MakeAliasModelDisplayLists (m, hdr, _m, _s, extra, vulkan_ctx); } static void * vulkan_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc) { - return skin + skinsize; + return Vulkan_Mod_LoadSkin (skin, skinsize, snum, gnum, group, skindesc, + vulkan_ctx); } static void vulkan_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr) { + Vulkan_Mod_FinalizeAliasModel (m, hdr, vulkan_ctx); } static void diff --git a/libs/video/renderer/vulkan/alias.frag b/libs/video/renderer/vulkan/alias.frag new file mode 100644 index 000000000..935fa06b4 --- /dev/null +++ b/libs/video/renderer/vulkan/alias.frag @@ -0,0 +1,55 @@ +#version 450 + +layout (set = 0, binding = 1) uniform sampler2D Texture; +layout (set = 0, binding = 2) uniform sampler2D GlowMap; +layout (set = 0, binding = 3) uniform sampler2D ColorA; +layout (set = 0, binding = 4) uniform sampler2D ColorB; + +struct LightData { + vec3 color; + float dist; + vec3 position; + int type; + vec3 direction; + float cone; +}; + +layout (constant_id = 0) const int MaxLights = 8; +layout (set = 1, binding = 0) uniform Lights { + int light_count; + LightData lights[MaxLights]; +}; + +layout (push_constant) uniform PushConstants { + layout (offset = 80) + vec4 fog; + vec4 color; +}; + +layout (location = 0) in vec2 st; +layout (location = 1) in vec3 position; +layout (location = 2) in vec3 normal; + +layout (location = 0) out vec4 frag_color; + +void +main (void) +{ + vec4 c; + int i; + vec3 light = vec3 (0); + + c = texture (Texture, st); + c += texture (ColorA, st); + c += texture (ColorB, st); + c += texture (GlowMap, st); + if (MaxLights > 0) { + for (i = 0; i < light_count; i++) { + vec3 dist = lights[i].position - position; + float dd = dot (dist, dist); + float mag = max (0.0, dot (dist, normal)); + light += lights[i].color * mag * lights[i].dist / dd; + } + } + frag_color = c * vec4(light, 1);//fogBlend (c); +} diff --git a/libs/video/renderer/vulkan/alias.vert b/libs/video/renderer/vulkan/alias.vert new file mode 100644 index 000000000..871c3a0c0 --- /dev/null +++ b/libs/video/renderer/vulkan/alias.vert @@ -0,0 +1,38 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + +layout (push_constant) uniform PushConstants { + mat4 Model; + float blend; +}; + +layout (location = 0) in vec4 vertexa; +layout (location = 1) in vec3 normala; +layout (location = 2) in vec4 vertexb; +layout (location = 3) in vec3 normalb; +layout (location = 4) in vec2 uv; + +layout (location = 0) out vec2 st; +layout (location = 1) out vec3 position; +layout (location = 2) out vec3 normal; + +void +main (void) +{ + vec4 vertex; + vec3 norm; + vec4 pos; + + vertex = mix (vertexa, vertexb, blend); + norm = mix (normala, normalb, blend); + pos = (Model * vertex); + gl_Position = Projection * (View * pos); + position = pos.xyz; + normal = mat3 (Model) * norm; + st = uv; +} diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index b5f5cd6cb..5fd0680af 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -11,6 +11,8 @@ twodf = $builtin/twod.frag; quakebspv = $builtin/quakebsp.vert; quakebspf = $builtin/quakebsp.frag; + aliasv = $builtin/alias.vert; + aliasf = $builtin/alias.frag; }; samplers = { quakepic = { @@ -30,7 +32,7 @@ borderColor = float_transparent_black; unnormalizedCoordinates = false; }; - quakebsp = { + quakebsp.sampler = { magFilter = linear; minFilter = linear; mipmapMode = linear; @@ -81,7 +83,7 @@ }, ); }; - quakebsp = { + quakebsp.textures = { flags = push_descriptor; bindings = ( { @@ -122,6 +124,51 @@ }, ); }; + alias.textures = { + flags = push_descriptor; + bindings = ( + { + binding = 0; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = vertex; + }, + { + binding = 1; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 2; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 3; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 4; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; + alias.lights = { + bindings = ( + { + binding = 0; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; something = { flags = 0; bindings = ( @@ -144,8 +191,8 @@ twod = { setLayouts = (twod); }; - quakebsp = { - setLayouts = (quakebsp); + quakebsp.layout = { + setLayouts = (quakebsp.textures); pushConstantRanges = ( { stageFlags = vertex; @@ -159,6 +206,21 @@ }, ); }; + alias.layout = { + setLayouts = (alias.textures, alias.lights); + pushConstantRanges = ( + { + stageFlags = vertex; + offset = 0; + size = "16 * 4 + 4"; + }, + { + stageFlags = fragment; + offset = 80; + size = "2 * 4 * 4"; + }, + ); + }; something = { setLayouts = (something); pushConstantRanges = ( @@ -171,6 +233,133 @@ }; }; pipelines = { + alias = { + stages = ( + { stage = vertex; name = main; module = aliasv; }, + { + stage = fragment; + name = main; + module = aliasf; + specializationInfo = { + mapEntries = ( + { size = 4; offset = 0; constantID = 0; }, + ); + data = <00000000>; + }; + }, + ); + vertexInput = { + bindings = ( + { + binding = 0; + stride = "2 * 4 * 4"; + inputRate = vertex; + }, + { + binding = 1; + stride = "2 * 4 * 4"; + inputRate = vertex; + }, + { + binding = 2; + stride = "2 * 4"; + inputRate = vertex; + }, + ); + attributes = ( + { + location = 0; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 0; + }, + { + location = 1; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 16; + }, + { + location = 2; + binding = 1; + format = r32g32b32a32_sfloat; + offset = 0; + }, + { + location = 3; + binding = 1; + format = r32g32b32a32_sfloat; + offset = 16; + }, + { + location = 4; + binding = 2; + format = r32g32_sfloat; + offset = 0; + }, + ); + }; + inputAssembly = { + topology = triangle; + primitiveRestartEnable = false; + }; + viewport = { + viewports = ( + { + x = 0; y = 0; + width = 640; height = 480; + minDepth = 0; maxDepth = 1; + } + ); + scissors = ( + { + offset = { x = 0; y = 0 }; + extent = { width = 640; height = 480; }; + }, + ); + }; + rasterization = { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = fill; + cullMode = back; + frontFace = clockwise; + depthBiasEnable = false; + lineWidth = 1; + }; + multisample = { + rasterizationSamples = $msaaSamples; + sampleShadingEnable = false; + minSampleShading = 0.5f; + alphaToCoverageEnable = false; + alphaToOneEnable = false; + }; + depthStencil = { + depthTestEnable = true; + depthWriteEnable = true; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + colorBlend = { + logicOpEnable = false; + attachments = ({ + blendEnable = true; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }); + }; + dynamic = { + dynamicState = ( viewport, scissor, blend_constants ); + }; + layout = alias; + //renderPass = renderpass; + }; quakebsp.main = { stages = ( { stage = vertex; name = main; module = quakebspv; }, @@ -257,7 +446,7 @@ dynamic = { dynamicState = ( viewport, scissor, blend_constants ); }; - layout = quakebsp; + layout = quakebsp.layout; //renderPass = renderpass; }; quakebsp.skysheet = { @@ -359,7 +548,7 @@ dynamic = { dynamicState = ( viewport, scissor, blend_constants ); }; - layout = quakebsp; + layout = quakebsp.layout; //renderPass = renderpass; }; twod = { diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index 4b0fed532..a3cc9e3f0 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -63,6 +63,10 @@ static static #include "libs/video/renderer/vulkan/quakebsp.frag.spvc" static +#include "libs/video/renderer/vulkan/alias.vert.spvc" +static +#include "libs/video/renderer/vulkan/alias.frag.spvc" +static #include "libs/video/renderer/vulkan/passthrough.vert.spvc" static #include "libs/video/renderer/vulkan/pushcolor.frag.spvc" @@ -78,6 +82,8 @@ static shaderdata_t builtin_shaders[] = { { "twod.frag", twod_frag, sizeof (twod_frag) }, { "quakebsp.vert", quakebsp_vert, sizeof (quakebsp_vert) }, { "quakebsp.frag", quakebsp_frag, sizeof (quakebsp_frag) }, + { "alias.vert", alias_vert, sizeof (alias_vert) }, + { "alias.frag", alias_frag, sizeof (alias_frag) }, { "passthrough.vert", passthrough_vert, sizeof (passthrough_vert) }, { "pushcolor.frag", pushcolor_frag, sizeof (pushcolor_frag) }, {} diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 6da253bea..c95a14c97 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -1420,13 +1420,8 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bctx->main = Vulkan_CreatePipeline (ctx, "quakebsp.main"); bctx->sky = Vulkan_CreatePipeline (ctx, "quakebsp.skysheet"); - bctx->layout = QFV_GetPipelineLayout (ctx, "quakebsp"); - bctx->sampler = QFV_GetSampler (ctx, "quakebsp"); - - __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (frames, alloca); - for (size_t i = 0; i < layouts->size; i++) { - layouts->a[i] = QFV_GetDescriptorSetLayout (ctx, "quakebsp"); - } + bctx->layout = QFV_GetPipelineLayout (ctx, "quakebsp.layout"); + bctx->sampler = QFV_GetSampler (ctx, "quakebsp.sampler"); __auto_type cmdBuffers = QFV_AllocCommandBufferSet (3 * frames, alloca); QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); From 56573d09e4795c3ec176d270fa3ee826cefb3500 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Jan 2021 10:22:06 +0900 Subject: [PATCH 295/435] [vulkan] Get Vulkan_LoadTex working Finally managed to actually use and thus sort out its issues. --- libs/video/renderer/vulkan/vulkan_texture.c | 34 +++++++++++++-------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index 07bcc7f0a..d5723ad3f 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -65,6 +65,7 @@ static int ilog2 (unsigned x) { + unsigned o = x; if (x > 0x7fffffff) { // avoid overflow return 31; @@ -82,7 +83,7 @@ ilog2 (unsigned x) y |= ((x & 0xf0f0f0f0) != 0) << 2; y |= ((x & 0xcccccccc) != 0) << 1; y |= ((x & 0xaaaaaaaa) != 0) << 0; - return y; + return y - ((o & (x - 1)) != 0); } void @@ -140,8 +141,8 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) if (!tex->palette) { return 0; } - format = VK_FORMAT_R8G8B8_UNORM; - bpp = 3; + format = VK_FORMAT_R8G8B8A8_UNORM; + bpp = 4; break; case tex_rgb: format = VK_FORMAT_R8G8B8_UNORM; @@ -174,6 +175,7 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) qtex->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, format, extent, mip, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); qtex->memory = QFV_AllocImageMemory (device, qtex->image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, @@ -190,7 +192,7 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) if (tex->format == tex_palette) { Vulkan_ExpandPalette (tex_data, tex->data, tex->palette, - 0, tex->width * tex->height); + 1, tex->width * tex->height); } else { memcpy (tex_data, tex->data, bytes); } @@ -201,6 +203,7 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; barrier.image = qtex->image; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, 1, &barrier); @@ -214,19 +217,29 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; stages.src = VK_PIPELINE_STAGE_TRANSFER_BIT; stages.dst = VK_PIPELINE_STAGE_TRANSFER_BIT; VkImageBlit blit = { {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {{0, 0, 0}, {tex->width, tex->height, 1}}, {VK_IMAGE_ASPECT_COLOR_BIT, 1, 0, 1}, - {{0, 0, 0}, {(tex->width + 1) >> 1, (tex->height + 1) >> 1, 1}}, + {{0, 0, 0}, {max (tex->width >> 1, 1), max (tex->height >> 1, 1), 1}}, }; + if (mip == 1) { + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = qtex->image; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + } while (--mip > 0) { barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + stages.dst = VK_PIPELINE_STAGE_TRANSFER_BIT; dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, @@ -242,6 +255,7 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + stages.dst = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, 1, &barrier); @@ -250,16 +264,10 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) blit.srcOffsets[1].x = blit.dstOffsets[1].x; blit.srcOffsets[1].y = blit.dstOffsets[1].y; blit.dstSubresource.mipLevel++; - blit.dstOffsets[1].x = (blit.dstOffsets[1].x + 1) >> 1; - blit.dstOffsets[1].y = (blit.dstOffsets[1].y + 1) >> 1; + blit.dstOffsets[1].x = max (blit.dstOffsets[1].x >> 1, 1); + blit.dstOffsets[1].y = max (blit.dstOffsets[1].y >> 1, 1); barrier.subresourceRange.baseMipLevel++; } - stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; - barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; - barrier.image = qtex->image; - dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, - 0, 0, 0, 0, 0, - 1, &barrier); QFV_PacketSubmit (packet); return qtex; } From 69a8b984a52a9ba9058438d45d1c660c5b5f68a1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Jan 2021 13:46:33 +0900 Subject: [PATCH 296/435] [vulkan] Sort out alias model load and unload --- libs/models/alias/vulkan_model_alias.c | 77 ++++++++++++++++++++------ 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index 97801febc..88e2ced29 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -62,6 +62,34 @@ static vec3_t vertex_normals[NUMVERTEXNORMALS] = { static void vulkan_alias_clear (model_t *m, void *data) { + vulkan_ctx_t *ctx = data; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliashdr_t *hdr; + qfv_alias_mesh_t *mesh; + + m->needload = true; //FIXME is this right? + if (!(hdr = m->aliashdr)) { + hdr = Cache_Get (&m->cache); + } + mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands); + dfunc->vkDestroyBuffer (device->dev, mesh->vertex_buffer, 0); + dfunc->vkDestroyBuffer (device->dev, mesh->uv_buffer, 0); + dfunc->vkDestroyBuffer (device->dev, mesh->index_buffer, 0); + dfunc->vkFreeMemory (device->dev, mesh->memory, 0); + + __auto_type skins = (maliasskindesc_t *) ((byte *) hdr + hdr->skindesc); + for (int i = 0; i < hdr->mdl.numskins; i++) { + if (skins[i].type == ALIAS_SKIN_GROUP) { + __auto_type group = (maliasskingroup_t *) + ((byte *) hdr + skins[i].skin); + for (int j = 0; j < group->numskins; j++) { + Vulkan_UnloadTex (ctx, group->skindescs[j].tex); + } + } else { + Vulkan_UnloadTex (ctx, skins[i].tex); + } + } } void * @@ -72,6 +100,8 @@ Vulkan_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, byte *tskin; int w, h; + //FIXME move all skins into arrays(?) + //FIXME fullbrights w = pheader->mdl.skinwidth; h = pheader->mdl.skinheight; tskin = malloc (skinsize); @@ -86,9 +116,8 @@ Vulkan_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, void Vulkan_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr, vulkan_ctx_t *ctx) { - if (hdr->mdl.ident == HEADER_MDL16) - VectorScale (hdr->mdl.scale, 1/256.0, hdr->mdl.scale); m->clear = vulkan_alias_clear; + m->data = ctx; } void @@ -96,6 +125,21 @@ Vulkan_Mod_LoadExternalSkins (model_t *mod, vulkan_ctx_t *ctx) { } +static size_t +get_buffer_size (qfv_device_t *device, VkBuffer buffer) +{ + qfv_devfuncs_t *dfunc = device->funcs; + size_t size; + size_t align; + + VkMemoryRequirements requirements; + dfunc->vkGetBufferMemoryRequirements (device->dev, buffer, &requirements); + size = requirements.size; + align = requirements.alignment - 1; + size = (size + align) & ~(align); + return size; +} + void Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, int _s, int extra, vulkan_ctx_t *ctx) @@ -113,6 +157,9 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, int pose; vec3_t pos; + if (hdr->mdl.ident == HEADER_MDL16) + VectorScale (hdr->mdl.scale, 1/256.0, hdr->mdl.scale); + numverts = hdr->mdl.numverts; numtris = hdr->mdl.numtris; @@ -148,33 +195,31 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // current and previous pose, uvbuff "statically" bound as uvs are not // animated by pose, and the same for ibuf: indices will never change for // the mesh - size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; - size_t atom_mask = atom - 1; size_t vert_count = numverts * hdr->numposes; size_t vert_size = vert_count * sizeof (aliasvrt_t); size_t uv_size = numverts * sizeof (aliasuv_t); - size_t ind_size = numverts * sizeof (uint32_t); - vert_size = (vert_size + atom_mask) & ~atom_mask; - uv_size = (uv_size + atom_mask) & ~atom_mask; - ind_size = (ind_size + atom_mask) & ~atom_mask; - size_t buff_size = vert_size + ind_size + uv_size; + size_t ind_size = 3 * numtris * sizeof (uint32_t); - VkBuffer vbuff = QFV_CreateBuffer (device, buff_size, + VkBuffer vbuff = QFV_CreateBuffer (device, vert_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - VkBuffer uvbuff = QFV_CreateBuffer (device, buff_size, + VkBuffer uvbuff = QFV_CreateBuffer (device, uv_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - VkBuffer ibuff = QFV_CreateBuffer (device, buff_size, + VkBuffer ibuff = QFV_CreateBuffer (device, ind_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + size_t voffs = 0; + size_t uvoffs = voffs + get_buffer_size (device, vbuff); + size_t ioffs = uvoffs + get_buffer_size (device, uvbuff); + size_t buff_size = ioffs + get_buffer_size (device, ibuff); VkDeviceMemory mem; mem = QFV_AllocBufferMemory (device, vbuff, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, buff_size, 0); - QFV_BindBufferMemory (device, vbuff, mem, 0); - QFV_BindBufferMemory (device, uvbuff, mem, vert_size); - QFV_BindBufferMemory (device, ibuff, mem, vert_size + uv_size); + QFV_BindBufferMemory (device, vbuff, mem, voffs); + QFV_BindBufferMemory (device, uvbuff, mem, uvoffs); + QFV_BindBufferMemory (device, ibuff, mem, ioffs); qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, buff_size, ctx->cmdpool); @@ -219,7 +264,7 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, } // now build the indices for DrawElements - for (i = 0; i < numverts; i++) { + for (i = 0; i < hdr->mdl.numverts; i++) { indexmap[i] = indexmap[i] != -1 ? indexmap[i] : i; } for (i = 0; i < numtris; i++) { From 826e650c273e466caf325a220dcdd664ce182e11 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Jan 2021 20:33:51 +0900 Subject: [PATCH 297/435] [models] Do full alias skin loading This includes base, glow and two color maps (pants and shorts). --- include/QF/Vulkan/qf_alias.h | 6 +++ include/QF/model.h | 16 +++---- include/mod_internal.h | 4 ++ libs/models/alias/vulkan_model_alias.c | 48 ++++++++++++++++++--- libs/models/fullbright.c | 17 ++++++-- libs/models/skin.c | 60 ++++++++++++++++++++++++++ 6 files changed, 131 insertions(+), 20 deletions(-) diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index efe3dd0dc..006bd8672 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -37,6 +37,12 @@ #include "QF/modelgen.h" #include "QF/Vulkan/qf_vid.h" +typedef struct aliasskin_s { + struct qfv_tex_s *tex; + struct qfv_tex_s *glow; + struct qfv_tex_s *colora; + struct qfv_tex_s *colorb; +} aliasskin_t; typedef struct aliasvrt_s { float vertex[4]; float normal[4]; diff --git a/include/QF/model.h b/include/QF/model.h index d1129bfce..5512506f3 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -278,14 +278,9 @@ typedef struct { typedef struct { aliasskintype_t type; - int skin; - union { - struct { - int texnum; - int fb_texnum; - }; - void *tex; - }; + int skin; + int texnum; + int fb_texnum; } maliasskindesc_t; typedef struct { @@ -447,7 +442,8 @@ void Mod_TouchModel (const char *name); mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model) __attribute__((pure)); byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model); model_t *Mod_FindName (const char *name); -int Mod_CalcFullbright (byte *in, byte *out, int pixels); +int Mod_CalcFullbright (const byte *in, byte *out, int pixels); +void Mod_ClearFullbright (const byte *in, byte *out, int pixels); int Mod_Fullbright (byte * skin, int width, int height, const char *name); void *Mod_LoadAliasFrame (void *pin, int *posenum, maliasframedesc_t *frame, @@ -457,7 +453,7 @@ void *Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame, void Mod_FindClipDepth (hull_t *hull); void Mod_LoadBrushModel (model_t *mod, void *buffer); -void Mod_FloodFillSkin (byte * skin, int skinwidth, int skinheight); +void Mod_FloodFillSkin (byte *skin, int skinwidth, int skinheight); void Mod_Print (void); diff --git a/include/mod_internal.h b/include/mod_internal.h index 632411785..382a8985f 100644 --- a/include/mod_internal.h +++ b/include/mod_internal.h @@ -62,6 +62,10 @@ void Skin_Init (void); skin_t *Skin_SetColormap (skin_t *skin, int cmap); skin_t *Skin_SetSkin (skin_t *skin, int cmap, const char *skinname); void Skin_SetTranslation (int cmap, int top, int bottom); +int Skin_CalcTopColors (const byte *in, byte *out, int pixels); +int Skin_CalcBottomColors (const byte *in, byte *out, int pixels); +void Skin_ClearTopColors (const byte *in, byte *out, int pixels); +void Skin_ClearBottomColors (const byte *in, byte *out, int pixels); void sw_Skin_SetupSkin (skin_t *skin, int cmap); void sw_Skin_ProcessTranslation (int cmap, const byte *translation); diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index 88e2ced29..3a7ad4705 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -59,6 +59,22 @@ static vec3_t vertex_normals[NUMVERTEXNORMALS] = { #include "anorms.h" }; +static void +skin_clear (int skin_offset, aliashdr_t *hdr, vulkan_ctx_t *ctx) +{ + aliasskin_t *skin = (aliasskin_t *) ((byte *) hdr + skin_offset); + Vulkan_UnloadTex (ctx, skin->tex); + if (skin->glow) { + Vulkan_UnloadTex (ctx, skin->glow); + } + if (skin->colora) { + Vulkan_UnloadTex (ctx, skin->colora); + } + if (skin->colorb) { + Vulkan_UnloadTex (ctx, skin->colorb); + } +} + static void vulkan_alias_clear (model_t *m, void *data) { @@ -84,32 +100,50 @@ vulkan_alias_clear (model_t *m, void *data) __auto_type group = (maliasskingroup_t *) ((byte *) hdr + skins[i].skin); for (int j = 0; j < group->numskins; j++) { - Vulkan_UnloadTex (ctx, group->skindescs[j].tex); + skin_clear (group->skindescs[j].skin, hdr, ctx); } } else { - Vulkan_UnloadTex (ctx, skins[i].tex); + skin_clear (skins[i].skin, hdr, ctx); } } } void * -Vulkan_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, +Vulkan_Mod_LoadSkin (byte *skinpix, int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc, vulkan_ctx_t *ctx) { + aliasskin_t *skin; byte *tskin; int w, h; + skin = Hunk_Alloc (sizeof (aliasskin_t)); + skindesc->skin = (byte *) skin - (byte *) pheader;//FIXME pheader global //FIXME move all skins into arrays(?) - //FIXME fullbrights w = pheader->mdl.skinwidth; h = pheader->mdl.skinheight; - tskin = malloc (skinsize); + tskin = malloc (2 * skinsize); memcpy (tskin, skin, skinsize); Mod_FloodFillSkin (tskin, w, h); - tex_t skin_tex = {w, h, tex_palette, 1, vid.palette, tskin}; - skindesc->tex = Vulkan_LoadTex (ctx, &skin_tex, 1); + + tex_t skin_tex = {w, h, tex_palette, 1, vid.palette, tskin + skinsize}; + if (Mod_CalcFullbright (tskin, tskin + skinsize, skinsize)) { + skin->glow = Vulkan_LoadTex (ctx, &skin_tex, 1); + Mod_ClearFullbright (tskin, tskin, skinsize); + } + if (Skin_CalcTopColors (tskin, tskin + skinsize, skinsize)) { + skin->colora = Vulkan_LoadTex (ctx, &skin_tex, 1); + Skin_ClearTopColors (tskin, tskin, skinsize); + } + if (Skin_CalcBottomColors (tskin, tskin + skinsize, skinsize)) { + skin->colorb = Vulkan_LoadTex (ctx, &skin_tex, 1); + Skin_ClearBottomColors (tskin, tskin, skinsize); + } + skin_tex.data = tskin; + skin->tex = Vulkan_LoadTex (ctx, &skin_tex, 1); + free (tskin); + return skin + skinsize; } diff --git a/libs/models/fullbright.c b/libs/models/fullbright.c index 79c32ede9..62f9ccee5 100644 --- a/libs/models/fullbright.c +++ b/libs/models/fullbright.c @@ -33,17 +33,28 @@ #include "r_local.h" - VISIBLE int -Mod_CalcFullbright (byte *in, byte *out, int pixels) +Mod_CalcFullbright (const byte *in, byte *out, int pixels) { byte fb = 0; - while (pixels--) { + while (pixels-- > 0) { byte pix = *in++; byte mask = (pix >= 256 - 32) - 1; fb |= mask + 1; + // mask is 0 for fullbright, otherwise 0xff *out++ = pix | mask; } return fb; } + +VISIBLE void +Mod_ClearFullbright (const byte *in, byte *out, int pixels) +{ + while (pixels-- > 0) { + byte pix = *in++; + byte mask = ~((pix >= 256 - 32) - 1); + // mask is 0xff for fullbright, otherwise 0 + *out++ = pix | mask; + } +} diff --git a/libs/models/skin.c b/libs/models/skin.c index 9897a4143..88d53cea6 100644 --- a/libs/models/skin.c +++ b/libs/models/skin.c @@ -246,3 +246,63 @@ Skin_Init (void) skin_cache = Hash_NewTable (127, skin_getkey, skin_free, 0, 0); m_funcs->Skin_InitTranslations (); } + +VISIBLE int +Skin_CalcTopColors (const byte *in, byte *out, int pixels) +{ + byte tc = 0; + + while (pixels-- > 0) { + byte pix = *in++; + byte a = (pix < TOP_RANGE) - 1; + byte b = (pix > TOP_RANGE + 15) - 1; + byte mask = ~(a & b); + tc |= mask; + // mask is 0 for top color otherwise 0xff + *out++ = (pix - TOP_RANGE) | mask; + } + return tc; +} + +VISIBLE int +Skin_CalcBottomColors (const byte *in, byte *out, int pixels) +{ + byte bc = 0; + + while (pixels-- > 0) { + byte pix = *in++; + byte a = (pix < BOTTOM_RANGE) - 1; + byte b = (pix > BOTTOM_RANGE + 15) - 1; + byte mask = ~(a & b); + bc |= mask; + // mask is 0 for bottom color otherwise 0xff + *out++ = (pix - BOTTOM_RANGE) | mask; + } + return bc; +} + +VISIBLE void +Skin_ClearTopColors (const byte *in, byte *out, int pixels) +{ + while (pixels-- > 0) { + byte pix = *in++; + byte a = (pix < TOP_RANGE) - 1; + byte b = (pix > TOP_RANGE + 15) - 1; + byte mask = (a & b); + // mask is 0xff for top color otherwise 0 + *out++ = (pix - TOP_RANGE) | mask; + } +} + +VISIBLE void +Skin_ClearBottomColors (const byte *in, byte *out, int pixels) +{ + while (pixels-- > 0) { + byte pix = *in++; + byte a = (pix < BOTTOM_RANGE) - 1; + byte b = (pix > BOTTOM_RANGE + 15) - 1; + byte mask = (a & b); + // mask is 0xff for bottom color otherwise 0 + *out++ = (pix - BOTTOM_RANGE) | mask; + } +} From 12ec6c5c296a416e7fbc2a07526fd917aee66cbc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Jan 2021 20:45:07 +0900 Subject: [PATCH 298/435] [util] Add eol to plist parse errors I suspect it got lost when I made the error message a string item. --- libs/util/qfplist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 3fa64b9d0..fe0fc3268 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -899,7 +899,7 @@ PL_GetPropertyList (const char *string) if (pl && pl->error) { const char *error = PL_String (pl->error); if (error[0]) { - Sys_Printf ("plist: %d,%d: %s", pl->line, pl->pos, error); + Sys_Printf ("plist: %d,%d: %s\n", pl->line, pl->pos, error); } PL_Free (pl->error); } From 748217b43833fcb0cc24f32d76115b1ead2312b4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Jan 2021 20:58:24 +0900 Subject: [PATCH 299/435] [vulkan] Start work on alias model rendering --- include/QF/Vulkan/qf_alias.h | 38 ++- include/vid_vulkan.h | 1 + libs/video/renderer/Makemodule.am | 1 + libs/video/renderer/vid_render_vulkan.c | 2 + libs/video/renderer/vulkan/alias.frag | 8 +- libs/video/renderer/vulkan/qfpipeline.plist | 65 +++-- libs/video/renderer/vulkan/vulkan_alias.c | 276 ++++++++++++++++++ libs/video/renderer/vulkan/vulkan_draw.c | 6 +- libs/video/renderer/vulkan/vulkan_main.c | 15 +- .../video/renderer/vulkan/vulkan_vid_common.c | 1 + 10 files changed, 378 insertions(+), 35 deletions(-) create mode 100644 libs/video/renderer/vulkan/vulkan_alias.c diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index 006bd8672..bcc5be337 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -43,6 +43,7 @@ typedef struct aliasskin_s { struct qfv_tex_s *colora; struct qfv_tex_s *colorb; } aliasskin_t; + typedef struct aliasvrt_s { float vertex[4]; float normal[4]; @@ -68,15 +69,39 @@ typedef struct qfv_light_s { float cone; } qfv_light_t; +#define ALIAS_LIGHTS 8 + typedef struct qfv_light_buffer_s { int light_count; - qfv_light_t lights[] __attribute__((aligned(16))); + qfv_light_t lights[ALIAS_LIGHTS] __attribute__((aligned(16))); } qfv_light_buffer_t; -typedef struct alias_ctx_s { -} alias_ctx_t; +#define ALIAS_BUFFER_INFOS 2 +#define ALIAS_IMAGE_INFOS 4 + +typedef struct aliasframe_s { + VkCommandBuffer cmd; + VkDescriptorBufferInfo bufferInfo[ALIAS_BUFFER_INFOS]; + VkDescriptorImageInfo imageInfo[ALIAS_IMAGE_INFOS]; + VkWriteDescriptorSet descriptors[ALIAS_BUFFER_INFOS + ALIAS_IMAGE_INFOS]; + qfv_light_buffer_t *lights; + VkBuffer light_buffer; +} aliasframe_t; + +typedef struct aliasframeset_s + DARRAY_TYPE (aliasframe_t) aliasframeset_t; + +typedef struct aliasctx_s { + aliasframeset_t frames; + VkPipeline pipeline; + VkPipelineLayout layout; + VkSampler sampler; + + VkDeviceMemory light_memory; +} aliasctx_t; struct vulkan_ctx_s; +struct entity_s; void *Vulkan_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc, struct vulkan_ctx_s *ctx); @@ -87,4 +112,11 @@ void Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, int _s, int extra, struct vulkan_ctx_s *ctx); +void Vulkan_AliasBegin (struct vulkan_ctx_s *ctx); +void Vulkan_DrawAlias (struct entity_s *ent, struct vulkan_ctx_s *ctx); +void Vulkan_AliasEnd (struct vulkan_ctx_s *ctx); + +void Vulkan_Alias_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Alias_Shutdown (struct vulkan_ctx_s *ctx); + #endif//__QF_Vulkan_qf_alias_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index f4642afb1..8a60707fe 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -63,6 +63,7 @@ typedef struct vulkan_ctx_s { struct hashtab_s *descriptorPools; struct hashtab_s *samplers; + struct aliasctx_s *alias_context; struct bspctx_s *bsp_context; struct drawctx_s *draw_context; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index e3b154541..b322a7ca4 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -236,6 +236,7 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/util.c \ libs/video/renderer/vulkan/util.h \ libs/video/renderer/vulkan/vkparse.c \ + libs/video/renderer/vulkan/vulkan_alias.c \ libs/video/renderer/vulkan/vulkan_bsp.c \ libs/video/renderer/vulkan/vulkan_draw.c \ libs/video/renderer/vulkan/vulkan_lightmap.c \ diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 2b001bcd3..fc8aebc11 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -98,6 +98,7 @@ vulkan_R_Init (void) // are being built vulkan_ctx->pipeline = Vulkan_CreatePipeline (vulkan_ctx, "pipeline"); Vulkan_Texture_Init (vulkan_ctx); + Vulkan_Alias_Init (vulkan_ctx); Vulkan_Bsp_Init (vulkan_ctx); Vulkan_Draw_Init (vulkan_ctx); Vulkan_Particles_Init (vulkan_ctx); @@ -611,6 +612,7 @@ vulkan_vid_render_shutdown (void) df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0); Vulkan_Draw_Shutdown (vulkan_ctx); Vulkan_Bsp_Shutdown (vulkan_ctx); + Vulkan_Alias_Shutdown (vulkan_ctx); Mod_ClearAll (); Vulkan_Texture_Shutdown (vulkan_ctx); Vulkan_Shutdown_Common (vulkan_ctx); diff --git a/libs/video/renderer/vulkan/alias.frag b/libs/video/renderer/vulkan/alias.frag index 935fa06b4..d1ad194bb 100644 --- a/libs/video/renderer/vulkan/alias.frag +++ b/libs/video/renderer/vulkan/alias.frag @@ -1,9 +1,9 @@ #version 450 -layout (set = 0, binding = 1) uniform sampler2D Texture; -layout (set = 0, binding = 2) uniform sampler2D GlowMap; -layout (set = 0, binding = 3) uniform sampler2D ColorA; -layout (set = 0, binding = 4) uniform sampler2D ColorB; +layout (set = 2, binding = 0) uniform sampler2D Texture; +layout (set = 2, binding = 1) uniform sampler2D GlowMap; +layout (set = 2, binding = 2) uniform sampler2D ColorA; +layout (set = 2, binding = 3) uniform sampler2D ColorB; struct LightData { vec3 color; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 5fd0680af..b6823707c 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -49,9 +49,26 @@ borderColor = float_transparent_black; unnormalizedCoordinates = false; }; + alias.sampler = { + magFilter = linear; + minFilter = linear; + mipmapMode = linear; + addressModeU = clamp_to_edge; + addressModeV = clamp_to_edge; + addressModeW = clamp_to_edge; + mipLodBias = 0; + anisotropyEnable = false; + maxAnisotropy = 0; + compareEnable = false; + compareOp = always; + minLod = 0; + maxLod = 1000; + borderColor = float_transparent_black; + unnormalizedCoordinates = false; + }; }; descriptorPools = { - twod = { + twod.pool = { flags = 0; maxSets = $framebuffers.size; bindings = ( @@ -65,9 +82,19 @@ }, ); }; + alias.pool = { + flags = 0; + maxSets = "2z * $framebuffers.size"; + bindings = ( + { + type = uniform_buffer; + descriptorCount = "2z * $framebuffers.size"; + }, + ); + }; }; setLayouts = { - twod = { + twod.set = { bindings = ( { binding = 0; @@ -124,8 +151,7 @@ }, ); }; - alias.textures = { - flags = push_descriptor; + alias.matrices = { bindings = ( { binding = 0; @@ -133,6 +159,17 @@ descriptorCount = 1; stageFlags = vertex; }, + ); + }; + alias.textures = { + flags = push_descriptor; + bindings = ( + { + binding = 0; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, { binding = 1; descriptorType = combined_image_sampler; @@ -151,12 +188,6 @@ descriptorCount = 1; stageFlags = fragment; }, - { - binding = 4; - descriptorType = combined_image_sampler; - descriptorCount = 1; - stageFlags = fragment; - }, ); }; alias.lights = { @@ -188,8 +219,8 @@ }; }; pipelineLayouts = { - twod = { - setLayouts = (twod); + twod.layout = { + setLayouts = (twod.set); }; quakebsp.layout = { setLayouts = (quakebsp.textures); @@ -207,7 +238,7 @@ ); }; alias.layout = { - setLayouts = (alias.textures, alias.lights); + setLayouts = (alias.matrices, alias.lights, alias.textures); pushConstantRanges = ( { stageFlags = vertex; @@ -244,7 +275,7 @@ mapEntries = ( { size = 4; offset = 0; constantID = 0; }, ); - data = <00000000>; + data = <00000008>; }; }, ); @@ -300,7 +331,7 @@ ); }; inputAssembly = { - topology = triangle; + topology = triangle_list; primitiveRestartEnable = false; }; viewport = { @@ -357,7 +388,7 @@ dynamic = { dynamicState = ( viewport, scissor, blend_constants ); }; - layout = alias; + layout = alias.layout; //renderPass = renderpass; }; quakebsp.main = { @@ -643,7 +674,7 @@ dynamic = { dynamicState = ( viewport, scissor ); }; - layout = twod; + layout = twod.layout; //renderPass = renderpass; }; }; diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c new file mode 100644 index 000000000..3fa9d7c52 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -0,0 +1,276 @@ +/* + vulkan_alias.c + + Vulkan alias model pipeline + + Copyright (C) 2012 Bill Currie + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2012/1/7 + Date: 2021/1/26 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "qfalloca.h" + +#include "QF/cvar.h" +#include "QF/darray.h" +#include "QF/dstring.h" +#include "QF/image.h" +#include "QF/render.h" +#include "QF/skin.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/vrect.h" + +#include "QF/Vulkan/qf_alias.h" +#include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/command.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" + +#include "r_internal.h" +#include "vid_vulkan.h" +#include "vkparse.h" + +static VkImageView +get_view (qfv_tex_t *tex, qfv_tex_t *default_tex) +{ + if (tex) { + return tex->view; + } + if (default_tex) { + return default_tex->view; + } + return 0; +} + +void +Vulkan_DrawAlias (struct entity_s *ent, struct vulkan_ctx_s *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliasctx_t *actx = ctx->alias_context; + aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + model_t *model = ent->model; + aliashdr_t *hdr; + qfv_alias_mesh_t *mesh; + float blend; + aliasskin_t *skin; + + if (!(hdr = model->aliashdr)) { + hdr = Cache_Get (&model->cache); + } + mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands); + + blend = R_AliasGetLerpedFrames (ent, hdr); + + if (0/*XXX ent->skin && ent->skin->tex*/) { + //skin = ent->skin->tex; + } else { + maliasskindesc_t *skindesc; + skindesc = R_AliasGetSkindesc (ent->skinnum, hdr); + skin = (aliasskin_t *) ((byte *) hdr + skindesc->skin); + } + + VkDeviceSize offsets[] = { + ent->pose1 * hdr->poseverts, + ent->pose2 * hdr->poseverts, + 0, + }; + VkBuffer buffers[] = { + mesh->vertex_buffer, + mesh->vertex_buffer, + mesh->uv_buffer, + }; + dfunc->vkCmdBindVertexBuffers (aframe->cmd, 0, 3, buffers, offsets); + dfunc->vkCmdBindIndexBuffer (aframe->cmd, mesh->index_buffer, 0, + VK_INDEX_TYPE_UINT32); + dfunc->vkCmdPushConstants (aframe->cmd, actx->layout, + VK_SHADER_STAGE_VERTEX_BIT, + 0, 16 * sizeof (float), ent->transform); + dfunc->vkCmdPushConstants (aframe->cmd, actx->layout, + VK_SHADER_STAGE_VERTEX_BIT, + 64, sizeof (float), &blend); + aframe->imageInfo[0].imageView = get_view (skin->tex, ctx->default_white); + aframe->imageInfo[1].imageView = get_view (skin->glow, ctx->default_black); + aframe->imageInfo[2].imageView = get_view (skin->colora, + ctx->default_black); + aframe->imageInfo[3].imageView = get_view (skin->colorb, + ctx->default_black); + dfunc->vkCmdPushDescriptorSetKHR (aframe->cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, + actx->layout, + 0, 2, aframe->descriptors + + ALIAS_BUFFER_INFOS); + dfunc->vkCmdDrawIndexed (aframe->cmd, 3 * hdr->mdl.numtris, 1, 0, 0, 0); +} + +void +Vulkan_AliasBegin (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliasctx_t *actx = ctx->alias_context; + //XXX quat_t fog; + + __auto_type cframe = &ctx->framebuffers.a[ctx->curFrame]; + aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + VkCommandBuffer cmd = aframe->cmd; + DARRAY_APPEND (cframe->subCommand, cmd); + + //FIXME need per frame matrices + aframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; + aframe->bufferInfo[1].buffer = aframe->light_buffer; + + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + ctx->renderpass.renderpass, 0, + cframe->framebuffer, + 0, 0, 0, + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + actx->pipeline); + VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; + VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; + dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); + + dfunc->vkUpdateDescriptorSets (device->dev, 2, aframe->descriptors, 0, 0); + + //XXX glsl_Fog_GetColor (fog); + //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; +} + +void +Vulkan_AliasEnd (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliasctx_t *actx = ctx->alias_context; + + aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + dfunc->vkEndCommandBuffer (aframe->cmd); +} + +static VkDescriptorBufferInfo base_buffer_info = { + 0, 0, VK_WHOLE_SIZE +}; +static VkDescriptorImageInfo base_image_info = { + 0, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL +}; +static VkWriteDescriptorSet base_buffer_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, 0, 0 +}; +static VkWriteDescriptorSet base_image_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 0, 0, 0 +}; + +void +Vulkan_Alias_Init (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + aliasctx_t *actx = calloc (1, sizeof (aliasctx_t)); + ctx->alias_context = actx; + + size_t frames = ctx->framebuffers.size; + DARRAY_INIT (&actx->frames, frames); + DARRAY_RESIZE (&actx->frames, frames); + actx->frames.grow = 0; + + actx->pipeline = Vulkan_CreatePipeline (ctx, "alias"); + actx->layout = QFV_GetPipelineLayout (ctx, "alias.layout"); + actx->sampler = QFV_GetSampler (ctx, "alias.sampler"); + + __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (2 * frames, alloca); + for (size_t i = 0; i < layouts->size / 2; i++) { + __auto_type mats = QFV_GetDescriptorSetLayout (ctx, "alias.matrices"); + __auto_type lights = QFV_GetDescriptorSetLayout (ctx, "alias.lights"); + layouts->a[2 * i + 0] = mats; + layouts->a[2 * i + 1] = lights; + } + __auto_type pool = QFV_GetDescriptorPool (ctx, "alias.pool"); + + __auto_type cmdBuffers = QFV_AllocCommandBufferSet (frames, alloca); + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); + + __auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); + for (size_t i = 0; i < frames; i++) { + __auto_type aframe = &actx->frames.a[i]; + aframe->cmd = cmdBuffers->a[i]; + + for (int j = 0; j < ALIAS_BUFFER_INFOS; j++) { + aframe->bufferInfo[j] = base_buffer_info; + aframe->descriptors[j] = base_buffer_write; + aframe->descriptors[j].dstSet = sets->a[2 * i + j]; + aframe->descriptors[j].dstBinding = 0; + aframe->descriptors[j].pBufferInfo = &aframe->bufferInfo[j]; + } + for (int j = 0; j < ALIAS_IMAGE_INFOS; j++) { + aframe->imageInfo[j] = base_image_info; + aframe->imageInfo[j].sampler = actx->sampler; + int k = j + ALIAS_BUFFER_INFOS; + aframe->descriptors[k] = base_image_write; + aframe->descriptors[k].dstBinding = j; + aframe->descriptors[k].pImageInfo = &aframe->imageInfo[j]; + } + } + free (sets); +} + +void +Vulkan_Alias_Shutdown (struct vulkan_ctx_s *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + aliasctx_t *actx = ctx->alias_context; + + dfunc->vkDestroyPipeline (device->dev, actx->pipeline, 0); + DARRAY_CLEAR (&actx->frames); + free (actx); +} diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index f4bf8c19e..3fc563cb2 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -383,13 +383,13 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) dctx->pipeline = Vulkan_CreatePipeline (ctx, "twod"); - dctx->layout = QFV_GetPipelineLayout (ctx, "twod"); + dctx->layout = QFV_GetPipelineLayout (ctx, "twod.layout"); __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (frames, alloca); for (size_t i = 0; i < layouts->size; i++) { - layouts->a[i] = QFV_GetDescriptorSetLayout (ctx, "twod"); + layouts->a[i] = QFV_GetDescriptorSetLayout (ctx, "twod.set"); } - __auto_type pool = QFV_GetDescriptorPool (ctx, "twod"); + __auto_type pool = QFV_GetDescriptorPool (ctx, "twod.pool"); VkDescriptorBufferInfo bufferInfo = { ctx->matrices.buffer_2d, 0, VK_WHOLE_SIZE diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index f31558e7b..95fcd02ab 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -49,7 +49,7 @@ #include "QF/sys.h" #include "QF/Vulkan/qf_vid.h" -//#include "QF/Vulkan/qf_alias.h" +#include "QF/Vulkan/qf_alias.h" #include "QF/Vulkan/qf_bsp.h" //#include "QF/Vulkan/qf_iqm.h" #include "QF/Vulkan/qf_lightmap.h" @@ -109,8 +109,8 @@ setup_view (vulkan_ctx_t *ctx) static void R_RenderEntities (vulkan_ctx_t *ctx) { - //entity_t *ent; - //int begun; + entity_t *ent; + int begun; if (!r_drawentities->int_val) return; @@ -121,17 +121,16 @@ R_RenderEntities (vulkan_ctx_t *ctx) if (ent->model->type != mod_##type_name) \ continue; \ if (!begun) { \ - glsl_R_##Type##Begin (); \ + Vulkan_##Type##Begin (ctx); \ begun = 1; \ } \ - currententity = ent; \ - glsl_R_Draw##Type (); \ + Vulkan_Draw##Type (ent, ctx); \ } \ if (begun) \ - glsl_R_##Type##End (); \ + Vulkan_##Type##End (ctx); \ } while (0) - //RE_LOOP (alias, Alias); + RE_LOOP (alias, Alias); //RE_LOOP (iqm, IQM); //RE_LOOP (sprite, Sprite); } diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 4e5f338cc..2ab5fc166 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -242,6 +242,7 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) plitem_t *item = ctx->pipelineDef; if (!item || !(item = PL_ObjectForKey (item, "renderpass"))) { Sys_Printf ("error loading renderpass\n"); + return; } else { Sys_Printf ("Found renderpass def\n"); } From a64f477796b1b6fcd023e94fe2397722613fc8b7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Jan 2021 12:15:45 +0900 Subject: [PATCH 300/435] [vulkan] Get alias texture loading working That was a mess, partly premature optimizations, and some silly mistakes. --- libs/models/alias/vulkan_model_alias.c | 2 +- libs/models/fullbright.c | 18 +-- libs/models/skin.c | 44 +++---- libs/video/renderer/vulkan/vulkan_texture.c | 125 +++++++++++++------- 4 files changed, 115 insertions(+), 74 deletions(-) diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index 3a7ad4705..e3e5f0701 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -123,7 +123,7 @@ Vulkan_Mod_LoadSkin (byte *skinpix, int skinsize, int snum, int gnum, w = pheader->mdl.skinwidth; h = pheader->mdl.skinheight; tskin = malloc (2 * skinsize); - memcpy (tskin, skin, skinsize); + memcpy (tskin, skinpix, skinsize); Mod_FloodFillSkin (tskin, w, h); tex_t skin_tex = {w, h, tex_palette, 1, vid.palette, tskin + skinsize}; diff --git a/libs/models/fullbright.c b/libs/models/fullbright.c index 62f9ccee5..22cef6a83 100644 --- a/libs/models/fullbright.c +++ b/libs/models/fullbright.c @@ -40,10 +40,12 @@ Mod_CalcFullbright (const byte *in, byte *out, int pixels) while (pixels-- > 0) { byte pix = *in++; - byte mask = (pix >= 256 - 32) - 1; - fb |= mask + 1; - // mask is 0 for fullbright, otherwise 0xff - *out++ = pix | mask; + if (pix >= 256 - 32) { + fb = 1; + *out++ = pix; + } else { + *out++ = 0; + } } return fb; } @@ -53,8 +55,10 @@ Mod_ClearFullbright (const byte *in, byte *out, int pixels) { while (pixels-- > 0) { byte pix = *in++; - byte mask = ~((pix >= 256 - 32) - 1); - // mask is 0xff for fullbright, otherwise 0 - *out++ = pix | mask; + if (pix >= 256 - 32) { + *out++ = 0; + } else { + *out++ = pix; + } } } diff --git a/libs/models/skin.c b/libs/models/skin.c index 88d53cea6..fd561143d 100644 --- a/libs/models/skin.c +++ b/libs/models/skin.c @@ -254,12 +254,12 @@ Skin_CalcTopColors (const byte *in, byte *out, int pixels) while (pixels-- > 0) { byte pix = *in++; - byte a = (pix < TOP_RANGE) - 1; - byte b = (pix > TOP_RANGE + 15) - 1; - byte mask = ~(a & b); - tc |= mask; - // mask is 0 for top color otherwise 0xff - *out++ = (pix - TOP_RANGE) | mask; + if (pix >= TOP_RANGE && pix < TOP_RANGE + 16) { + tc = 1; + *out++ = pix - TOP_RANGE; + } else { + *out++ = 0; + } } return tc; } @@ -271,12 +271,12 @@ Skin_CalcBottomColors (const byte *in, byte *out, int pixels) while (pixels-- > 0) { byte pix = *in++; - byte a = (pix < BOTTOM_RANGE) - 1; - byte b = (pix > BOTTOM_RANGE + 15) - 1; - byte mask = ~(a & b); - bc |= mask; - // mask is 0 for bottom color otherwise 0xff - *out++ = (pix - BOTTOM_RANGE) | mask; + if (pix >= BOTTOM_RANGE && pix < BOTTOM_RANGE + 16) { + bc = 1; + *out++ = pix - BOTTOM_RANGE; + } else { + *out++ = 0; + } } return bc; } @@ -286,11 +286,11 @@ Skin_ClearTopColors (const byte *in, byte *out, int pixels) { while (pixels-- > 0) { byte pix = *in++; - byte a = (pix < TOP_RANGE) - 1; - byte b = (pix > TOP_RANGE + 15) - 1; - byte mask = (a & b); - // mask is 0xff for top color otherwise 0 - *out++ = (pix - TOP_RANGE) | mask; + if (pix >= TOP_RANGE && pix < TOP_RANGE + 16) { + *out++ = 0; + } else { + *out++ = pix; + } } } @@ -299,10 +299,10 @@ Skin_ClearBottomColors (const byte *in, byte *out, int pixels) { while (pixels-- > 0) { byte pix = *in++; - byte a = (pix < BOTTOM_RANGE) - 1; - byte b = (pix > BOTTOM_RANGE + 15) - 1; - byte mask = (a & b); - // mask is 0xff for bottom color otherwise 0 - *out++ = (pix - BOTTOM_RANGE) | mask; + if (pix >= BOTTOM_RANGE && pix < BOTTOM_RANGE + 16) { + *out++ = 0; + } else { + *out++ = pix; + } } } diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index d5723ad3f..0129f886c 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -119,6 +119,85 @@ Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, } } +static void +blit_mips (int mips, VkImage image, tex_t *tex, + qfv_devfuncs_t *dfunc, VkCommandBuffer cmd) +{ + qfv_pipelinestagepair_t pre_stages = { + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + }; + qfv_pipelinestagepair_t post_stages = { + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + }; + qfv_pipelinestagepair_t final_stages = { + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + }; + VkImageMemoryBarrier pre_barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + image, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }; + VkImageMemoryBarrier post_barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + image, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }; + VkImageMemoryBarrier final_barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + image, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } + }; + + VkImageBlit blit = { + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, + {{0, 0, 0}, {tex->width, tex->height, 1}}, + {VK_IMAGE_ASPECT_COLOR_BIT, 1, 0, 1}, + {{0, 0, 0}, {max (tex->width >> 1, 1), max (tex->height >> 1, 1), 1}}, + }; + + while (--mips > 0) { + dfunc->vkCmdPipelineBarrier (cmd, pre_stages.src, pre_stages.dst, 0, + 0, 0, 0, 0, + 1, &pre_barrier); + dfunc->vkCmdBlitImage (cmd, + image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &blit, VK_FILTER_LINEAR); + + dfunc->vkCmdPipelineBarrier (cmd, post_stages.src, post_stages.dst, 0, + 0, 0, 0, 0, + 1, &post_barrier); + + blit.srcSubresource.mipLevel++; + blit.srcOffsets[1].x = blit.dstOffsets[1].x; + blit.srcOffsets[1].y = blit.dstOffsets[1].y; + blit.dstSubresource.mipLevel++; + blit.dstOffsets[1].x = max (blit.dstOffsets[1].x >> 1, 1); + blit.dstOffsets[1].y = max (blit.dstOffsets[1].y >> 1, 1); + pre_barrier.subresourceRange.baseMipLevel++; + post_barrier.subresourceRange.baseMipLevel++; + final_barrier.subresourceRange.baseMipLevel++; + } + dfunc->vkCmdPipelineBarrier (cmd, final_stages.src, final_stages.dst, 0, + 0, 0, 0, 0, + 1, &final_barrier); +} + qfv_tex_t * Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) { @@ -216,16 +295,6 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) qtex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - stages.src = VK_PIPELINE_STAGE_TRANSFER_BIT; - stages.dst = VK_PIPELINE_STAGE_TRANSFER_BIT; - VkImageBlit blit = { - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, - {{0, 0, 0}, {tex->width, tex->height, 1}}, - {VK_IMAGE_ASPECT_COLOR_BIT, 1, 0, 1}, - {{0, 0, 0}, {max (tex->width >> 1, 1), max (tex->height >> 1, 1), 1}}, - }; if (mip == 1) { stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; @@ -233,40 +302,8 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, 1, &barrier); - } - while (--mip > 0) { - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - stages.dst = VK_PIPELINE_STAGE_TRANSFER_BIT; - - dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, - 0, 0, 0, 0, - 1, &barrier); - - dfunc->vkCmdBlitImage (packet->cmd, - qtex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - qtex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &blit, VK_FILTER_LINEAR); - - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - stages.dst = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, - 0, 0, 0, 0, - 1, &barrier); - - blit.srcSubresource.mipLevel++; - blit.srcOffsets[1].x = blit.dstOffsets[1].x; - blit.srcOffsets[1].y = blit.dstOffsets[1].y; - blit.dstSubresource.mipLevel++; - blit.dstOffsets[1].x = max (blit.dstOffsets[1].x >> 1, 1); - blit.dstOffsets[1].y = max (blit.dstOffsets[1].y >> 1, 1); - barrier.subresourceRange.baseMipLevel++; + } else { + blit_mips (mip, qtex->image, tex, dfunc, packet->cmd); } QFV_PacketSubmit (packet); return qtex; From 97febc0888681dbae463c948841cdd8d665e7be9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Jan 2021 12:51:22 +0900 Subject: [PATCH 301/435] [tools/misc] Update mdl.py for python 3 --- tools/misc/mdl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/misc/mdl.py b/tools/misc/mdl.py index 00c788316..f9b6698c4 100644 --- a/tools/misc/mdl.py +++ b/tools/misc/mdl.py @@ -22,8 +22,8 @@ for i in range(m[6]): else: n = unpack ("i", model[:4])[0] model = model [4:] - print n - k = (n, unpack (`n`+"f", model[:n*4]), []) + print (n) + k = (n, unpack (("%df" % n), model[:n*4]), []) model = model [n*4:] for j in range (n): k[2].append (model[:s]) @@ -67,7 +67,7 @@ for i in range (m[11]): g = (t, unpack ("i 3B B 3B B", model[:12])) model = model[12:] n = g[1][0] - g = g + (unpack (`n`+"f", model[:n*4]), []) + g = g + (unpack (("%df" % n), model[:n*4]), []) model = model[n*4:] for k in range (g[1][0]): f = (unpack ("3B B 3B B 16s", model[:24]), []) From 4da8feca360d786e4c3adc1dda1cb4a28df53fce Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Jan 2021 16:13:37 +0900 Subject: [PATCH 302/435] [models] Fix some vulkan alias upload errors Fixes the bogus vertex/index data and does barriers for all three buffers. --- libs/models/alias/vulkan_model_alias.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index e3e5f0701..a5520217c 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -144,7 +144,7 @@ Vulkan_Mod_LoadSkin (byte *skinpix, int skinsize, int snum, int gnum, free (tskin); - return skin + skinsize; + return skinpix + skinsize; } void @@ -288,8 +288,10 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, } VectorCompMultAdd (hdr->mdl.scale_origin, hdr->mdl.scale, pos, verts[pose + j].vertex); + verts[pose + j].vertex[3] = 1; VectorCopy (vertex_normals[pv->lightnormalindex], verts[pose + j].normal); + verts[pose + j].normal[3] = 0; // duplicate on-seam vert associated with back-facing triangle if (indexmap[j] != -1) { verts[pose + indexmap[j]] = verts[pose + j]; @@ -357,7 +359,7 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, dfunc->vkCmdPipelineBarrier (packet->cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, - 0, 0, 0, 1, rd_barriers, 0, 0); + 0, 0, 0, 3, rd_barriers, 0, 0); QFV_PacketSubmit (packet); QFV_DestroyStagingBuffer (stage); From 9f6441684611a432521b770130173c929084a90a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Jan 2021 16:16:28 +0900 Subject: [PATCH 303/435] [vulkan] Create the lights buffer It's a tad bogus as it's the lights close to the camera, but it should at least be a good start once things are working. There's currently something very wrong with the state of things. --- include/QF/Vulkan/buffer.h | 5 +++ libs/video/renderer/vulkan/instance.c | 9 ++++- libs/video/renderer/vulkan/vulkan_alias.c | 46 ++++++++++++++++++++++- libs/video/renderer/vulkan/vulkan_main.c | 6 +-- 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/include/QF/Vulkan/buffer.h b/include/QF/Vulkan/buffer.h index 9346d0466..712b14a96 100644 --- a/include/QF/Vulkan/buffer.h +++ b/include/QF/Vulkan/buffer.h @@ -18,6 +18,11 @@ typedef struct qfv_buffertransitionset_s typedef struct qfv_bufferbarrierset_s DARRAY_TYPE (VkBufferMemoryBarrier) qfv_bufferbarrierset_t; +typedef struct qfv_bufferset_s + DARRAY_TYPE (VkBuffer) qfv_bufferset_t; +#define QFV_AllocBufferSet(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_bufferset_t, num, allocator) + struct qfv_device_s; VkBuffer QFV_CreateBuffer (struct qfv_device_s *device, VkDeviceSize size, diff --git a/libs/video/renderer/vulkan/instance.c b/libs/video/renderer/vulkan/instance.c index 617d792e8..d1c845c6b 100644 --- a/libs/video/renderer/vulkan/instance.c +++ b/libs/video/renderer/vulkan/instance.c @@ -125,6 +125,11 @@ static int message_types = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; +static void +debug_breakpoint (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity) +{ +} + static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, @@ -144,7 +149,9 @@ debug_callback (VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { msgSev = "error: "; } - fprintf (stderr, "validation layer: %s%s\n", msgSev, callbackData->pMessage); + fprintf (stderr, "validation layer: %s%s\n", msgSev, + callbackData->pMessage); + debug_breakpoint (messageSeverity); return VK_FALSE; } diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 3fa9d7c52..4ba872a1a 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -55,6 +55,7 @@ #include "QF/Vulkan/qf_alias.h" #include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/buffer.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" @@ -131,8 +132,9 @@ Vulkan_DrawAlias (struct entity_s *ent, struct vulkan_ctx_s *ctx) dfunc->vkCmdPushDescriptorSetKHR (aframe->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, actx->layout, - 0, 2, aframe->descriptors - + ALIAS_BUFFER_INFOS); + ALIAS_BUFFER_INFOS, ALIAS_IMAGE_INFOS, + aframe->descriptors + + ALIAS_BUFFER_INFOS); dfunc->vkCmdDrawIndexed (aframe->cmd, 3 * hdr->mdl.numtris, 1, 0, 0, 0); } @@ -142,6 +144,8 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; aliasctx_t *actx = ctx->alias_context; + + dlight_t *lights[ALIAS_LIGHTS]; //XXX quat_t fog; __auto_type cframe = &ctx->framebuffers.a[ctx->curFrame]; @@ -149,6 +153,18 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx) VkCommandBuffer cmd = aframe->cmd; DARRAY_APPEND (cframe->subCommand, cmd); + R_FindNearLights (r_origin, ALIAS_LIGHTS, lights); + aframe->lights->light_count = 0; + for (int i = 0; i < ALIAS_LIGHTS; i++) { + if (!lights[i]) { + break; + } + aframe->lights->light_count++; + VectorCopy (lights[i]->color, aframe->lights->lights[i].color); + VectorCopy (lights[i]->origin, aframe->lights->lights[i].position); + aframe->lights->lights[i].dist = lights[i]->radius; + } + //FIXME need per frame matrices aframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; aframe->bufferInfo[1].buffer = aframe->light_buffer; @@ -169,6 +185,12 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx) dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, actx->pipeline); + VkDescriptorSet sets[] = { + aframe->descriptors[0].dstSet, + aframe->descriptors[1].dstSet, + }; + dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + actx->layout, 0, 2, sets, 0, 0); VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); @@ -214,6 +236,7 @@ void Vulkan_Alias_Init (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; aliasctx_t *actx = calloc (1, sizeof (aliasctx_t)); ctx->alias_context = actx; @@ -239,10 +262,29 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) __auto_type cmdBuffers = QFV_AllocCommandBufferSet (frames, alloca); QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); + __auto_type lbuffers = QFV_AllocBufferSet (frames, alloca); + for (size_t i = 0; i < frames; i++) { + lbuffers->a[i] = QFV_CreateBuffer (device, sizeof (qfv_light_buffer_t), + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + } + VkMemoryRequirements requirements; + dfunc->vkGetBufferMemoryRequirements (device->dev, lbuffers->a[0], + &requirements); + actx->light_memory = QFV_AllocBufferMemory (device, lbuffers->a[0], + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + frames * requirements.size, 0); + byte *light_data; + dfunc->vkMapMemory (device->dev, actx->light_memory, 0, + frames * requirements.size, 0, (void **) &light_data); + __auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); for (size_t i = 0; i < frames; i++) { __auto_type aframe = &actx->frames.a[i]; aframe->cmd = cmdBuffers->a[i]; + aframe->light_buffer = lbuffers->a[i]; + aframe->lights = (qfv_light_buffer_t *) (light_data + i * requirements.size); + QFV_BindBufferMemory (device, lbuffers->a[i], actx->light_memory, + i * requirements.size); for (int j = 0; j < ALIAS_BUFFER_INFOS; j++) { aframe->bufferInfo[j] = base_buffer_info; diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index 95fcd02ab..8df89eaa1 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -109,14 +109,12 @@ setup_view (vulkan_ctx_t *ctx) static void R_RenderEntities (vulkan_ctx_t *ctx) { - entity_t *ent; - int begun; - if (!r_drawentities->int_val) return; #define RE_LOOP(type_name, Type) \ do { \ - begun = 0; \ + entity_t *ent; \ + int begun = 0; \ for (ent = r_ent_queue; ent; ent = ent->next) { \ if (ent->model->type != mod_##type_name) \ continue; \ From caa7623a353943070b2d871ca9f2fe5a9a8daa70 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Jan 2021 17:59:09 +0900 Subject: [PATCH 304/435] [vulkan] Clean up alias light buffer Still wedging, but it seems to be something to do with the matrix buffer. --- libs/video/renderer/vulkan/vulkan_alias.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 4ba872a1a..0a74c0582 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -105,8 +105,8 @@ Vulkan_DrawAlias (struct entity_s *ent, struct vulkan_ctx_s *ctx) } VkDeviceSize offsets[] = { - ent->pose1 * hdr->poseverts, - ent->pose2 * hdr->poseverts, + ent->pose1 * hdr->poseverts * sizeof (aliasvrt_t), + ent->pose2 * hdr->poseverts * sizeof (aliasvrt_t), 0, }; VkBuffer buffers[] = { @@ -289,7 +289,7 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) for (int j = 0; j < ALIAS_BUFFER_INFOS; j++) { aframe->bufferInfo[j] = base_buffer_info; aframe->descriptors[j] = base_buffer_write; - aframe->descriptors[j].dstSet = sets->a[2 * i + j]; + aframe->descriptors[j].dstSet = sets->a[ALIAS_BUFFER_INFOS*i + j]; aframe->descriptors[j].dstBinding = 0; aframe->descriptors[j].pBufferInfo = &aframe->bufferInfo[j]; } @@ -312,6 +312,12 @@ Vulkan_Alias_Shutdown (struct vulkan_ctx_s *ctx) qfv_devfuncs_t *dfunc = device->funcs; aliasctx_t *actx = ctx->alias_context; + for (size_t i = 0; i < actx->frames.size; i++) { + __auto_type aframe = &actx->frames.a[i]; + dfunc->vkDestroyBuffer (device->dev, aframe->light_buffer, 0); + } + dfunc->vkFreeMemory (device->dev, actx->light_memory, 0); + dfunc->vkDestroyPipeline (device->dev, actx->pipeline, 0); DARRAY_CLEAR (&actx->frames); free (actx); From 64904e2b2766e605e150facc50b50d0decb430be Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 28 Jan 2021 10:49:23 +0900 Subject: [PATCH 305/435] [vulkan] Switch over to pushed descriptors I don't really know why (I need to do some research), but this fixes the lockups when accessing the matrices UBO. It has made a mess of my carefully designed uniform binding layout, so I hope I can get bound descriptor sets working the way I want, but I really need to progress on the rest of the project. --- libs/video/renderer/vulkan/alias.frag | 8 ++-- libs/video/renderer/vulkan/qfpipeline.plist | 48 +++++++++++++++++++-- libs/video/renderer/vulkan/vulkan_alias.c | 27 +++++++----- 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/libs/video/renderer/vulkan/alias.frag b/libs/video/renderer/vulkan/alias.frag index d1ad194bb..8fb794f47 100644 --- a/libs/video/renderer/vulkan/alias.frag +++ b/libs/video/renderer/vulkan/alias.frag @@ -1,5 +1,5 @@ #version 450 - +/* layout (set = 2, binding = 0) uniform sampler2D Texture; layout (set = 2, binding = 1) uniform sampler2D GlowMap; layout (set = 2, binding = 2) uniform sampler2D ColorA; @@ -19,7 +19,7 @@ layout (set = 1, binding = 0) uniform Lights { int light_count; LightData lights[MaxLights]; }; - +*/ layout (push_constant) uniform PushConstants { layout (offset = 80) vec4 fog; @@ -38,7 +38,7 @@ main (void) vec4 c; int i; vec3 light = vec3 (0); - +/* c = texture (Texture, st); c += texture (ColorA, st); c += texture (ColorB, st); @@ -52,4 +52,6 @@ main (void) } } frag_color = c * vec4(light, 1);//fogBlend (c); +*/ + frag_color = vec4((normal + 1)/2, 1); } diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index b6823707c..3cbf8db5e 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -110,7 +110,7 @@ }, ); }; - quakebsp.textures = { + quakebsp.set = { flags = push_descriptor; bindings = ( { @@ -151,6 +151,47 @@ }, ); }; + alias.set = { + flags = push_descriptor; + bindings = ( + { + binding = 0; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = vertex; + }, + { + binding = 1; + descriptorType = uniform_buffer; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 2; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 3; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 4; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 5; + descriptorType = combined_image_sampler; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; alias.matrices = { bindings = ( { @@ -223,7 +264,7 @@ setLayouts = (twod.set); }; quakebsp.layout = { - setLayouts = (quakebsp.textures); + setLayouts = (quakebsp.set); pushConstantRanges = ( { stageFlags = vertex; @@ -238,7 +279,8 @@ ); }; alias.layout = { - setLayouts = (alias.matrices, alias.lights, alias.textures); + //setLayouts = (alias.matrices, alias.lights, alias.textures); + setLayouts = (alias.set); pushConstantRanges = ( { stageFlags = vertex; diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 0a74c0582..3fd17c0b1 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -123,6 +123,7 @@ Vulkan_DrawAlias (struct entity_s *ent, struct vulkan_ctx_s *ctx) dfunc->vkCmdPushConstants (aframe->cmd, actx->layout, VK_SHADER_STAGE_VERTEX_BIT, 64, sizeof (float), &blend); + if (0) { aframe->imageInfo[0].imageView = get_view (skin->tex, ctx->default_white); aframe->imageInfo[1].imageView = get_view (skin->glow, ctx->default_black); aframe->imageInfo[2].imageView = get_view (skin->colora, @@ -135,6 +136,7 @@ Vulkan_DrawAlias (struct entity_s *ent, struct vulkan_ctx_s *ctx) ALIAS_BUFFER_INFOS, ALIAS_IMAGE_INFOS, aframe->descriptors + ALIAS_BUFFER_INFOS); + } dfunc->vkCmdDrawIndexed (aframe->cmd, 3 * hdr->mdl.numtris, 1, 0, 0, 0); } @@ -185,18 +187,21 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx) dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, actx->pipeline); - VkDescriptorSet sets[] = { - aframe->descriptors[0].dstSet, - aframe->descriptors[1].dstSet, - }; - dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - actx->layout, 0, 2, sets, 0, 0); + //VkDescriptorSet sets[] = { + // aframe->descriptors[0].dstSet, + // aframe->descriptors[1].dstSet, + //}; + //dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + // actx->layout, 0, 2, sets, 0, 0); + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + actx->layout, + 0, 1, aframe->descriptors + 0); VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); - dfunc->vkUpdateDescriptorSets (device->dev, 2, aframe->descriptors, 0, 0); + //dfunc->vkUpdateDescriptorSets (device->dev, 2, aframe->descriptors, 0, 0); //XXX glsl_Fog_GetColor (fog); //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; @@ -257,7 +262,7 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) layouts->a[2 * i + 0] = mats; layouts->a[2 * i + 1] = lights; } - __auto_type pool = QFV_GetDescriptorPool (ctx, "alias.pool"); + //__auto_type pool = QFV_GetDescriptorPool (ctx, "alias.pool"); __auto_type cmdBuffers = QFV_AllocCommandBufferSet (frames, alloca); QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); @@ -277,7 +282,7 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) dfunc->vkMapMemory (device->dev, actx->light_memory, 0, frames * requirements.size, 0, (void **) &light_data); - __auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); + //__auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); for (size_t i = 0; i < frames; i++) { __auto_type aframe = &actx->frames.a[i]; aframe->cmd = cmdBuffers->a[i]; @@ -289,7 +294,7 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) for (int j = 0; j < ALIAS_BUFFER_INFOS; j++) { aframe->bufferInfo[j] = base_buffer_info; aframe->descriptors[j] = base_buffer_write; - aframe->descriptors[j].dstSet = sets->a[ALIAS_BUFFER_INFOS*i + j]; + //aframe->descriptors[j].dstSet = sets->a[ALIAS_BUFFER_INFOS*i + j]; aframe->descriptors[j].dstBinding = 0; aframe->descriptors[j].pBufferInfo = &aframe->bufferInfo[j]; } @@ -302,7 +307,7 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) aframe->descriptors[k].pImageInfo = &aframe->imageInfo[j]; } } - free (sets); + //free (sets); } void From 28652c4d59134443dc8a4910fdc90f5dec829ac2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 28 Jan 2021 14:14:21 +0900 Subject: [PATCH 306/435] [vulkan] Implement alias model texturing I had messed up my index array creation, but once that was fixed the textures worked well other than a lot of pixels are shades of grey due to being in the top or bottom color map range. --- libs/models/alias/vulkan_model_alias.c | 9 +++++---- libs/video/renderer/vulkan/alias.frag | 13 +++++++++---- libs/video/renderer/vulkan/vulkan_alias.c | 6 ++---- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index a5520217c..832541071 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -300,12 +300,13 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, } // now build the indices for DrawElements - for (i = 0; i < hdr->mdl.numverts; i++) { - indexmap[i] = indexmap[i] != -1 ? indexmap[i] : i; - } for (i = 0; i < numtris; i++) { for (j = 0; j < 3; j++) { - indices[3 * i + j] = indexmap[triangles.a[i].vertindex[j]]; + int vind = triangles.a[i].vertindex[j]; + if (stverts.a[vind].onseam && !triangles.a[i].facesfront) { + vind = indexmap[vind]; + } + indices[3 * i + j] = vind; } } // finished with indexmap diff --git a/libs/video/renderer/vulkan/alias.frag b/libs/video/renderer/vulkan/alias.frag index 8fb794f47..513b92d2a 100644 --- a/libs/video/renderer/vulkan/alias.frag +++ b/libs/video/renderer/vulkan/alias.frag @@ -1,4 +1,8 @@ #version 450 +layout (set = 0, binding = 2) uniform sampler2D Texture; +layout (set = 0, binding = 3) uniform sampler2D GlowMap; +layout (set = 0, binding = 4) uniform sampler2D ColorA; +layout (set = 0, binding = 5) uniform sampler2D ColorB; /* layout (set = 2, binding = 0) uniform sampler2D Texture; layout (set = 2, binding = 1) uniform sampler2D GlowMap; @@ -38,11 +42,10 @@ main (void) vec4 c; int i; vec3 light = vec3 (0); -/* c = texture (Texture, st); c += texture (ColorA, st); c += texture (ColorB, st); - c += texture (GlowMap, st); +/* if (MaxLights > 0) { for (i = 0; i < light_count; i++) { vec3 dist = lights[i].position - position; @@ -51,7 +54,9 @@ main (void) light += lights[i].color * mag * lights[i].dist / dd; } } - frag_color = c * vec4(light, 1);//fogBlend (c); + c *= vec4 (light, 1); */ - frag_color = vec4((normal + 1)/2, 1); + c += texture (GlowMap, st); + //frag_color = vec4((normal + 1)/2, 1); + frag_color = c;//fogBlend (c); } diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 3fd17c0b1..6d1628bc0 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -123,7 +123,6 @@ Vulkan_DrawAlias (struct entity_s *ent, struct vulkan_ctx_s *ctx) dfunc->vkCmdPushConstants (aframe->cmd, actx->layout, VK_SHADER_STAGE_VERTEX_BIT, 64, sizeof (float), &blend); - if (0) { aframe->imageInfo[0].imageView = get_view (skin->tex, ctx->default_white); aframe->imageInfo[1].imageView = get_view (skin->glow, ctx->default_black); aframe->imageInfo[2].imageView = get_view (skin->colora, @@ -133,10 +132,9 @@ Vulkan_DrawAlias (struct entity_s *ent, struct vulkan_ctx_s *ctx) dfunc->vkCmdPushDescriptorSetKHR (aframe->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, actx->layout, - ALIAS_BUFFER_INFOS, ALIAS_IMAGE_INFOS, + 0, ALIAS_IMAGE_INFOS, aframe->descriptors + ALIAS_BUFFER_INFOS); - } dfunc->vkCmdDrawIndexed (aframe->cmd, 3 * hdr->mdl.numtris, 1, 0, 0, 0); } @@ -303,7 +301,7 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) aframe->imageInfo[j].sampler = actx->sampler; int k = j + ALIAS_BUFFER_INFOS; aframe->descriptors[k] = base_image_write; - aframe->descriptors[k].dstBinding = j; + aframe->descriptors[k].dstBinding = k; aframe->descriptors[k].pImageInfo = &aframe->imageInfo[j]; } } From 206c63181141b37dec4cda716053928289dd15a8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 28 Jan 2021 15:20:24 +0900 Subject: [PATCH 307/435] [vulkan] Get alias lighting mostly working It's not so much that parts aren't working, but rather there's no base-level lighting so everything is black until a dlight is in the vicinity --- libs/video/renderer/vulkan/alias.frag | 11 ++++++----- libs/video/renderer/vulkan/vulkan_alias.c | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libs/video/renderer/vulkan/alias.frag b/libs/video/renderer/vulkan/alias.frag index 513b92d2a..aa0deafdb 100644 --- a/libs/video/renderer/vulkan/alias.frag +++ b/libs/video/renderer/vulkan/alias.frag @@ -8,7 +8,7 @@ layout (set = 2, binding = 0) uniform sampler2D Texture; layout (set = 2, binding = 1) uniform sampler2D GlowMap; layout (set = 2, binding = 2) uniform sampler2D ColorA; layout (set = 2, binding = 3) uniform sampler2D ColorB; - +*/ struct LightData { vec3 color; float dist; @@ -19,11 +19,12 @@ struct LightData { }; layout (constant_id = 0) const int MaxLights = 8; -layout (set = 1, binding = 0) uniform Lights { +//layout (set = 1, binding = 0) uniform Lights { +layout (set = 0, binding = 1) uniform Lights { int light_count; LightData lights[MaxLights]; }; -*/ + layout (push_constant) uniform PushConstants { layout (offset = 80) vec4 fog; @@ -45,7 +46,7 @@ main (void) c = texture (Texture, st); c += texture (ColorA, st); c += texture (ColorB, st); -/* + if (MaxLights > 0) { for (i = 0; i < light_count; i++) { vec3 dist = lights[i].position - position; @@ -55,7 +56,7 @@ main (void) } } c *= vec4 (light, 1); -*/ + c += texture (GlowMap, st); //frag_color = vec4((normal + 1)/2, 1); frag_color = c;//fogBlend (c); diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 6d1628bc0..a71e0629e 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -193,7 +193,7 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx) // actx->layout, 0, 2, sets, 0, 0); dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, actx->layout, - 0, 1, aframe->descriptors + 0); + 0, 2, aframe->descriptors + 0); VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); @@ -293,7 +293,7 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) aframe->bufferInfo[j] = base_buffer_info; aframe->descriptors[j] = base_buffer_write; //aframe->descriptors[j].dstSet = sets->a[ALIAS_BUFFER_INFOS*i + j]; - aframe->descriptors[j].dstBinding = 0; + aframe->descriptors[j].dstBinding = j; aframe->descriptors[j].pBufferInfo = &aframe->bufferInfo[j]; } for (int j = 0; j < ALIAS_IMAGE_INFOS; j++) { From 7ee02f39653e952101c73b8b67bc6dadf240e952 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 28 Jan 2021 19:17:40 +0900 Subject: [PATCH 308/435] [vulkan] Sort of implement ambient lighting It works, but as it uses the camera position rather than the lit entity's position, it is incorrect. I have some interim ideas to handle it, though. --- libs/video/renderer/vulkan/alias.frag | 21 ++++++++++++--- libs/video/renderer/vulkan/vulkan_alias.c | 33 ++++++++++++++++++----- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/libs/video/renderer/vulkan/alias.frag b/libs/video/renderer/vulkan/alias.frag index aa0deafdb..eff6ff10a 100644 --- a/libs/video/renderer/vulkan/alias.frag +++ b/libs/video/renderer/vulkan/alias.frag @@ -37,6 +37,22 @@ layout (location = 2) in vec3 normal; layout (location = 0) out vec4 frag_color; +vec3 +calc_light (LightData light) +{ + if (light.type == 0) { + vec3 dist = light.position - position; + float dd = dot (dist, dist); + float mag = max (0.0, dot (dist, normal)); + return light.color * mag * light.dist / dd; + } else if (light.type == 1) { + } else if (light.type == 2) { + float mag = max (0.0, -dot (light.direction, normal)); + // position is ambient light + return light.color * dot (light.direction, normal) + light.position; + } +} + void main (void) { @@ -49,10 +65,7 @@ main (void) if (MaxLights > 0) { for (i = 0; i < light_count; i++) { - vec3 dist = lights[i].position - position; - float dd = dot (dist, dist); - float mag = max (0.0, dot (dist, normal)); - light += lights[i].color * mag * lights[i].dist / dd; + light += calc_light (lights[i]); } } c *= vec4 (light, 1); diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index a71e0629e..a31267cfb 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -77,7 +77,7 @@ get_view (qfv_tex_t *tex, qfv_tex_t *default_tex) } void -Vulkan_DrawAlias (struct entity_s *ent, struct vulkan_ctx_s *ctx) +Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; @@ -138,6 +138,22 @@ Vulkan_DrawAlias (struct entity_s *ent, struct vulkan_ctx_s *ctx) dfunc->vkCmdDrawIndexed (aframe->cmd, 3 * hdr->mdl.numtris, 1, 0, 0, 0); } +static void +calc_lighting (qfv_light_t *light, entity_t *ent) +{ + vec3_t ambient_color; + //FIXME should be ent->position + float l = R_LightPoint (r_origin) / 128.0; + + //XXX l = max (light, max (ent->model->min_light, ent->min_light)); + light->type = 2; + VectorSet (1, 1, 1, ambient_color); //FIXME + // position doubles as ambient light + VectorScale (ambient_color, l, light->position); + VectorSet (-1, 0, 0, light->direction); //FIXME + VectorCopy (light->position, light->color); +} + void Vulkan_AliasBegin (vulkan_ctx_t *ctx) { @@ -153,16 +169,19 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx) VkCommandBuffer cmd = aframe->cmd; DARRAY_APPEND (cframe->subCommand, cmd); - R_FindNearLights (r_origin, ALIAS_LIGHTS, lights); - aframe->lights->light_count = 0; - for (int i = 0; i < ALIAS_LIGHTS; i++) { + //FIXME ambient needs to be per entity + aframe->lights->light_count = 1; + calc_lighting (&aframe->lights->lights[0], 0); + R_FindNearLights (r_origin, ALIAS_LIGHTS - 1, lights); + for (int i = 0; i < ALIAS_LIGHTS - 1; i++) { if (!lights[i]) { break; } aframe->lights->light_count++; - VectorCopy (lights[i]->color, aframe->lights->lights[i].color); - VectorCopy (lights[i]->origin, aframe->lights->lights[i].position); - aframe->lights->lights[i].dist = lights[i]->radius; + VectorCopy (lights[i]->color, aframe->lights->lights[i + 1].color); + VectorCopy (lights[i]->origin, aframe->lights->lights[i + 1].position); + aframe->lights->lights[i + 1].dist = lights[i]->radius; + aframe->lights->lights[i + 1].type = 0; } //FIXME need per frame matrices From cad1eb42fdc1f3e72feb0db3ce346fca41391b2f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 30 Jan 2021 14:45:47 +0900 Subject: [PATCH 309/435] [qwaq] Put my qdb script in a safe place The paths are generally wrong, and it's not overly complicated, but having a reference helps me remember how to use the thing. --- ruamoko/qwaq/qdb | 3 +++ 1 file changed, 3 insertions(+) create mode 100755 ruamoko/qwaq/qdb diff --git a/ruamoko/qwaq/qdb b/ruamoko/qwaq/qdb new file mode 100755 index 000000000..7f1ed27e2 --- /dev/null +++ b/ruamoko/qwaq/qdb @@ -0,0 +1,3 @@ +#! /bin/bash -x + +./qwaq-curses qwaq-app.dat $1 From f523f6ba80eeb7efdc0095c2c27a23e39439cc4d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 30 Jan 2021 14:49:42 +0900 Subject: [PATCH 310/435] [vid] Disable X11 repeat control For now, at least. It is a royal pain in the neck when doing a lot of development work and I'm not sure it's worthwhile on modern CPUs. --- libs/video/targets/in_x11.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/video/targets/in_x11.c b/libs/video/targets/in_x11.c index 8ef111ec2..2787771c6 100644 --- a/libs/video/targets/in_x11.c +++ b/libs/video/targets/in_x11.c @@ -599,11 +599,11 @@ XLateKey (XKeyEvent * ev, int *k, int *u) static void x11_keydest_callback (keydest_t key_dest) { - if (key_dest == key_game) { - XAutoRepeatOff (x_disp); - } else { - XAutoRepeatOn (x_disp); - } +// if (key_dest == key_game) { +// XAutoRepeatOff (x_disp); +// } else { +// XAutoRepeatOn (x_disp); +// } } static void @@ -792,7 +792,7 @@ IN_LL_Shutdown (void) Sys_MaskPrintf (SYS_VID, "IN_LL_Shutdown\n"); in_mouse_avail = 0; if (x_disp) { - XAutoRepeatOn (x_disp); +// XAutoRepeatOn (x_disp); dga_off (); } if (in_mouse_accel && !in_mouse_accel->int_val) From 7970525ef4fac3a3ea11e9ee85ff83d81dc853eb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 31 Jan 2021 16:01:20 +0900 Subject: [PATCH 311/435] [util] Make va thread-safe It now takes a context pointer (opaque data) that holds the buffers it uses for the temporary strings. If the context pointer is null, a static context is used (making those uses of va NOT thread-safe). Most calls to va use the static context, but all such calls have been formatted consistently so they are easy to find when it comes time to do a full audit. --- include/QF/va.h | 57 ++++++++++++++++++++-- include/vid_vulkan.h | 1 + libs/audio/cd_file.c | 4 +- libs/audio/renderer/snd_jack.c | 2 +- libs/audio/renderer/snd_sfx.c | 2 +- libs/console/client.c | 4 +- libs/console/complete.c | 2 +- libs/console/filelist.c | 2 +- libs/gib/exp.c | 16 +++--- libs/gib/gib_builtin.c | 2 +- libs/gib/gib_classes.c | 4 +- libs/gib/gib_object.c | 2 +- libs/gib/gib_parse.c | 6 ++- libs/gib/gib_vars.c | 2 +- libs/models/alias/gl_model_alias.c | 14 +++--- libs/models/alias/glsl_model_alias.c | 4 +- libs/models/alias/vulkan_model_alias.c | 17 +++++-- libs/models/brush/gl_model_brush.c | 20 ++++---- libs/models/brush/vulkan_model_brush.c | 2 +- libs/models/iqm/gl_model_iqm.c | 2 +- libs/models/iqm/glsl_model_iqm.c | 4 +- libs/models/iqm/sw_model_iqm.c | 2 +- libs/models/skin.c | 2 +- libs/models/sprite/gl_model_sprite.c | 2 +- libs/models/sprite/glsl_model_sprite.c | 2 +- libs/ruamoko/rua_cvar.c | 6 +-- libs/ruamoko/rua_qfs.c | 3 +- libs/util/cvar.c | 4 +- libs/util/qfplist.c | 32 +++++++----- libs/util/quakefs.c | 18 +++---- libs/util/va.c | 53 ++++++++++++++------ libs/video/renderer/gl/gl_dyn_part.c | 2 +- libs/video/renderer/gl/gl_screen.c | 2 +- libs/video/renderer/gl/gl_sky.c | 5 +- libs/video/renderer/glsl/glsl_bsp.c | 6 +-- libs/video/renderer/glsl/glsl_particles.c | 2 +- libs/video/renderer/glsl/glsl_screen.c | 4 +- libs/video/renderer/glsl/vid_common_glsl.c | 2 +- libs/video/renderer/sw/screen.c | 2 +- libs/video/renderer/sw/sw_rpart.c | 2 +- libs/video/renderer/sw32/screen.c | 4 +- libs/video/renderer/sw32/sw32_rpart.c | 2 +- libs/video/targets/context_sdl.c | 4 +- libs/video/targets/context_x11.c | 2 +- libs/video/targets/joy.c | 2 +- libs/video/targets/vid.c | 16 +++--- libs/video/targets/vid_x11.c | 4 +- libs/video/targets/vid_x11_vulkan.c | 2 + nq/source/cl_demo.c | 2 +- nq/source/cl_main.c | 10 ++-- nq/source/cl_parse.c | 2 +- nq/source/host.c | 6 +-- nq/source/host_cmd.c | 22 ++++----- nq/source/sbar.c | 28 +++++------ nq/source/sv_main.c | 2 +- nq/source/sv_pr_cmds.c | 2 +- qtv/source/client.c | 6 +-- qtv/source/qtv.c | 2 +- qtv/source/sbar.c | 4 +- qtv/source/server.c | 5 +- qtv/source/sv_parse.c | 12 ++--- qw/source/cl_chat.c | 2 +- qw/source/cl_cvar.c | 2 +- qw/source/cl_demo.c | 6 +-- qw/source/cl_main.c | 12 ++--- qw/source/cl_parse.c | 35 +++++++------ qw/source/cl_skin.c | 5 +- qw/source/cl_slist.c | 2 +- qw/source/crudefile.c | 2 +- qw/source/locs.c | 4 +- qw/source/sbar.c | 29 ++++++----- qw/source/sv_ccmds.c | 32 ++++++------ qw/source/sv_demo.c | 10 ++-- qw/source/sv_init.c | 4 +- qw/source/sv_main.c | 6 +-- qw/source/sv_pr_cmds.c | 10 ++-- qw/source/sv_pr_qwe.c | 2 +- qw/source/sv_qtv.c | 8 +-- qw/source/sv_sbar.c | 4 +- qw/source/sv_user.c | 16 +++--- qw/source/teamplay.c | 8 +-- ruamoko/qwaq/builtins/main.c | 2 +- ruamoko/qwaq/builtins/qwaq.c | 2 +- tools/qfbsp/source/brush.c | 2 +- tools/qfbsp/source/map.c | 2 +- tools/qfbsp/source/readbsp.c | 4 +- tools/qfbsp/source/writebsp.c | 2 +- tools/qfcc/source/class.c | 55 +++++++++++---------- tools/qfcc/source/def.c | 6 +-- tools/qfcc/source/dot_expr.c | 31 ++++++------ tools/qfcc/source/dot_flow.c | 2 +- tools/qfcc/source/dot_type.c | 2 +- tools/qfcc/source/dump_globals.c | 30 ++++++------ tools/qfcc/source/expr.c | 7 +-- tools/qfcc/source/flow.c | 2 +- tools/qfcc/source/function.c | 6 +-- tools/qfcc/source/linker.c | 2 +- tools/qfcc/source/method.c | 4 +- tools/qfcc/source/obj_file.c | 4 +- tools/qfcc/source/options.c | 2 +- tools/qfcc/source/qc-parse.y | 6 ++- tools/qfcc/source/qfcc.c | 4 +- tools/qfcc/source/qfprogs.c | 4 +- tools/qfcc/source/statements.c | 43 ++++++++-------- tools/qfcc/source/struct.c | 6 +-- tools/qflight/source/entities.c | 3 +- tools/qflight/source/qflight.c | 2 +- tools/wad/script.c | 2 +- 108 files changed, 505 insertions(+), 390 deletions(-) diff --git a/include/QF/va.h b/include/QF/va.h index 1bf0eadaf..74a28aba7 100644 --- a/include/QF/va.h +++ b/include/QF/va.h @@ -34,9 +34,60 @@ */ ///@{ -// does a varargs printf into a temp buffer -char *va(const char *format, ...) __attribute__((format(printf,1,2))); -// does a varargs printf into a malloced buffer +/** Opaque context for va so it can have per-thread data. + */ +typedef struct va_ctx_s va_ctx_t; + +/** Create a va context with the specified number of buffers. + * + * Having multiple buffers allows va to be used in short chains. + * + * \param buffers The number of buffers to create in the context. va() will + * cycle through the buffers for each call. + * \return Pointer to the context. Pass to va() for thread-safe usage. + */ +va_ctx_t *va_create_context (int buffers); + +/** Destroy a va context. + * + * \param ctx The context to be destroyed. Must have been created by + * va_create_context(). + * \note Any pointers to strings returned by va() using the context + * referenced by \a ctx will become invalid as the backing + * memory for the strings will have been freed. + */ +void va_destroy_context (va_ctx_t *ctx); + +/** Does a varargs printf into a private buffer. + * + * \param ctx Context used for storing the private buffer such that va + * can be used in a multi-threaded environment. If null then + * a static context is used, in which case va is NOT + * thread-safe. + * \param format Standard printf() format string. + * \return Pointer to the beginning of the output string. The memory + * for the returned string is owned by the context pointed to + * by \a ctx. + * \note The static context is created with 4 buffers, so va (0,...) + * can be used to produce mildly complex output (eg, 3 calls + * to va sent to a 4th) with a reduced risk of strings being + * trampled. + */ +char *va(va_ctx_t *ctx, const char *format, ...) __attribute__((format(printf,2,3))); + +/** Does a varargs printf into a malloced buffer. + * + * Combines the effect of strdup and sprintf, but in a safe manner. Essentially + * the equivalent of strdup (va (ctx, format, ...)); + * + * \param format Standard printf() format string. + * \return Pointer to the beginning of the output string. The caller + * is responsible for freeing the memory holding the string. + * \note As nva() creates a new buffer every time it is called, it + * is thread-safe and there is no risk of the string being + * trampled. In addition, it does not use va(), so combining + * nva() with va() is safe. + */ char *nva(const char *format, ...) __attribute__((format(printf,1,2))); ///@} diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 8a60707fe..a213c7ac5 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -50,6 +50,7 @@ typedef struct vulkan_ctx_s { void (*create_window) (struct vulkan_ctx_s *ctx); VkSurfaceKHR (*create_surface) (struct vulkan_ctx_s *ctx); + struct va_ctx_s *va_ctx; struct qfv_instance_s *instance; struct qfv_device_s *device; struct qfv_swapchain_s *swapchain; diff --git a/libs/audio/cd_file.c b/libs/audio/cd_file.c index 94d394154..ef9979bd9 100644 --- a/libs/audio/cd_file.c +++ b/libs/audio/cd_file.c @@ -189,7 +189,7 @@ Load_Tracklist (void) static void I_OGGMus_SetPlayList (int track) { - const char *trackstring = va ("%i", track); + const char *trackstring = va (0, "%i", track); int i; play_list = PL_ObjectForKey (tracklist, trackstring); @@ -327,7 +327,7 @@ I_OGGMus_Info (void) /* loop, and count up the Highest key number. */ for (iter = 1, count = 0; count < keycount && iter <= 99 ; iter++) { - trackstring = va ("%i", iter); + trackstring = va (0, "%i", iter); if (!(currenttrack = PL_ObjectForKey (tracklist, trackstring))) { continue; } diff --git a/libs/audio/renderer/snd_jack.c b/libs/audio/renderer/snd_jack.c index f37ef3dc8..e35d61e50 100644 --- a/libs/audio/renderer/snd_jack.c +++ b/libs/audio/renderer/snd_jack.c @@ -329,7 +329,7 @@ s_jack_connect (void) jack_set_process_callback (jack_handle, snd_jack_process, 0); jack_on_shutdown (jack_handle, snd_jack_shutdown, 0); for (i = 0; i < 2; i++) - jack_out[i] = jack_port_register (jack_handle, va ("out_%d", i + 1), + jack_out[i] = jack_port_register (jack_handle, va (0, "out_%d", i + 1), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); snd_shm->speed = jack_get_sample_rate (jack_handle); diff --git a/libs/audio/renderer/snd_sfx.c b/libs/audio/renderer/snd_sfx.c index 4dc57ee90..8152213a6 100644 --- a/libs/audio/renderer/snd_sfx.c +++ b/libs/audio/renderer/snd_sfx.c @@ -199,7 +199,7 @@ SND_PrecacheSound (const char *name) if (!name) Sys_Error ("SND_PrecacheSound: NULL"); - sfx = SND_LoadSound (va ("sound/%s", name)); + sfx = SND_LoadSound (va (0, "sound/%s", name)); if (sfx && precache->int_val) { if (sfx->retain (sfx)) sfx->release (sfx); diff --git a/libs/console/client.c b/libs/console/client.c index 582113703..3370a7614 100644 --- a/libs/console/client.c +++ b/libs/console/client.c @@ -251,7 +251,7 @@ Condump_f (void) Sys_Printf ("invalid character in filename\n"); return; } - name = va ("%s/%s.txt", qfs_gamedir->dir.def, Cmd_Argv (1)); + name = va (0, "%s/%s.txt", qfs_gamedir->dir.def, Cmd_Argv (1));//FIXME if (!(file = QFS_WOpen (name, 0))) { Sys_Printf ("could not open %s for writing: %s\n", name, @@ -375,7 +375,7 @@ C_Print (const char *fmt, va_list args) // log all messages to file if (con_debuglog) - Sys_DebugLog (va ("%s/%s/qconsole.log", qfs_userpath, + Sys_DebugLog (va (0, "%s/%s/qconsole.log", qfs_userpath,//FIXME qfs_gamedir->dir.def), "%s", buffer->str); if (!con_initialized) diff --git a/libs/console/complete.c b/libs/console/complete.c index 83dedc7a1..220906473 100644 --- a/libs/console/complete.c +++ b/libs/console/complete.c @@ -157,7 +157,7 @@ Con_BasicCompleteCommandLine (inputline_t *il) && strncmp (s + bound, cmd, strlen (s + bound))) bound++; - overwrite = va("%.*s%.*s", bound, s, cmd_len, cmd); + overwrite = va (0, "%.*s%.*s", bound, s, cmd_len, cmd); il->lines[il->edit_line][1] = '/'; strncpy (il->lines[il->edit_line] + 2, overwrite, il->line_size - 3); diff --git a/libs/console/filelist.c b/libs/console/filelist.c index dd979743a..b2942c593 100644 --- a/libs/console/filelist.c +++ b/libs/console/filelist.c @@ -167,7 +167,7 @@ Con_Skyboxlist_f (void) for (j = 1; sb_endings[j]; j++) { b = 0; for (k = 0; k < skyboxlist->count; k++) { - if (strcmp(va("%s%s", basename->str, sb_endings[j]), + if (strcmp(va (0, "%s%s", basename->str, sb_endings[j]), skyboxlist->list[k]) == 0) { b = 1; *skyboxlist->list[k] = 0; diff --git a/libs/gib/exp.c b/libs/gib/exp.c index f56159e71..3ca5b19b8 100644 --- a/libs/gib/exp.c +++ b/libs/gib/exp.c @@ -311,7 +311,7 @@ EXP_ParseString (char *str) } else { EXP_DestroyTokens (chain); EXP_Error (EXP_E_INVOP, - va ("Unknown operator or function '%s'.", buf)); + va (0, "Unknown operator or function '%s'.", buf)); return 0; } } @@ -347,8 +347,7 @@ EXP_SimplifyTokens (token * chain) cur = cur->generic.prev; if (EXP_DoFunction (cur)) return EXP_Error (EXP_E_SYNTAX, - va - ("Invalid number of arguments to function '%s'.", + va (0, "Invalid number of arguments to function '%s'.", cur->func.func->str)); } else { if (EXP_ContainsCommas (cur)) @@ -374,8 +373,7 @@ EXP_SimplifyTokens (token * chain) if (cur->generic.next->generic.type == TOKEN_OP) if (EXP_DoUnary (cur->generic.next)) return EXP_Error (EXP_E_SYNTAX, - va - ("Unary operator '%s' not followed by a unary operator or numerical value.", + va (0, "Unary operator '%s' not followed by a unary operator or numerical value.", cur->generic.next->op.op->str)); if (optable[i].operands == 1 && cur->generic.next->generic.type == TOKEN_NUM) { @@ -482,14 +480,12 @@ EXP_Validate (token * chain) cur->generic.next->op.op = EXP_FindOpByStr ("neg"); else if (cur->generic.next->op.op->operands == 2) return EXP_Error (EXP_E_SYNTAX, - va - ("Operator '%s' does not follow a number or numerical value.", + va (0, "Operator '%s' does not follow a number or numerical value.", cur->generic.next->op.op->str)); } else if (cur->generic.type == TOKEN_FUNC && cur->generic.next->generic.type != TOKEN_OPAREN) return EXP_Error (EXP_E_SYNTAX, - va - ("Function '%s' called without an argument list.", + va (0, "Function '%s' called without an argument list.", cur->func.func->str)); else if (cur->generic.type == TOKEN_COMMA && @@ -501,7 +497,7 @@ EXP_Validate (token * chain) else if (cur->generic.type == TOKEN_OP && cur->generic.next->generic.type == TOKEN_CPAREN) return EXP_Error (EXP_E_SYNTAX, - va ("Operator '%s' is missing an operand.", + va (0, "Operator '%s' is missing an operand.", cur->op.op->str)); else if (cur->generic.type == TOKEN_NUM && cur->generic.next->generic.type == TOKEN_NUM) diff --git a/libs/gib/gib_builtin.c b/libs/gib/gib_builtin.c index b7f571458..190ec8373 100644 --- a/libs/gib/gib_builtin.c +++ b/libs/gib/gib_builtin.c @@ -823,7 +823,7 @@ GIB_File_Write_f (void) } path = GIB_Argv (1); - QFS_WriteFile (va ("%s/%s", qfs_gamedir->dir.def, path), + QFS_WriteFile (va (0, "%s/%s", qfs_gamedir->dir.def, path), GIB_Argv(2), GIB_Argd(2)->size-1); } diff --git a/libs/gib/gib_classes.c b/libs/gib/gib_classes.c index 88922af50..55087dcdf 100644 --- a/libs/gib/gib_classes.c +++ b/libs/gib/gib_classes.c @@ -612,9 +612,9 @@ static const char *g_gcbs_name; static const char *gcbs_fname (const char *str) { if (g_gcbs_mode == INSTANCE) - return va ("__%s_%s__", g_gcbs_name, str); + return va (0, "__%s_%s__", g_gcbs_name, str); else - return va ("%s::%s", g_gcbs_name, str); + return va (0, "%s::%s", g_gcbs_name, str); } void diff --git a/libs/gib/gib_object.c b/libs/gib/gib_object.c index 3d69b887e..b9fbf66a9 100644 --- a/libs/gib/gib_object.c +++ b/libs/gib/gib_object.c @@ -205,7 +205,7 @@ GIB_Object_Create (const char *classname, qboolean classobj) obj->data = malloc (sizeof (void *) * (class->depth+1)); obj->methods = classobj ? class->class_methods : class->methods; obj->handle = classobj ? 0 : GIB_Handle_New (obj); - obj->handstr = strdup (va ("%lu", obj->handle)); + obj->handstr = strdup (va (0, "%lu", obj->handle)); obj->refs = 1; obj->signals = Hash_NewTable (128, GIB_Signal_Get_Key, GIB_Signal_Free, NULL, 0); diff --git a/libs/gib/gib_parse.c b/libs/gib/gib_parse.c index 0ace51571..c0afaa8d5 100644 --- a/libs/gib/gib_parse.c +++ b/libs/gib/gib_parse.c @@ -333,7 +333,8 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs) return nodes; ERROR: if (c) - GIB_Parse_Error (va ("Could not find match for '%c'.", c), *i + pofs); + GIB_Parse_Error (va (0, "Could not find match for '%c'.", c), + *i + pofs); if (nodes) GIB_Tree_Unref (&nodes); return 0; @@ -496,7 +497,8 @@ GIB_Parse_Embedded (gib_tree_t *token) return lines; ERROR: if (c) - GIB_Parse_Error (va ("Could not find match for '%c'.", c), i + token->start); + GIB_Parse_Error (va (0, "Could not find match for '%c'.", c), + i + token->start); if (lines) GIB_Tree_Unref (&lines); return 0; diff --git a/libs/gib/gib_vars.c b/libs/gib/gib_vars.c index 31d7b3c6a..2d40141e1 100644 --- a/libs/gib/gib_vars.c +++ b/libs/gib/gib_vars.c @@ -210,7 +210,7 @@ GIB_Var_Get_Very_Complex (hashtab_t ** first, hashtab_t ** second, dstring_t *ke key->str[i] = 0; if ((var = GIB_Var_Get_Very_Complex (&one, &two, key, n+1+varstartskip, &index2, create))) { if (key->str[n] == '#') - str = va("%u", var->size); + str = va (0, "%u", var->size); else str = var->array[index2].value->str; key->str[i] = c; diff --git a/libs/models/alias/gl_model_alias.c b/libs/models/alias/gl_model_alias.c index 82919aad4..ff5d62347 100644 --- a/libs/models/alias/gl_model_alias.c +++ b/libs/models/alias/gl_model_alias.c @@ -122,7 +122,7 @@ Mod_LoadExternalSkin (maliasskindesc_t *pskindesc, char *filename) tex = LoadImage (filename, 1); if (!tex) - tex = LoadImage (va ("textures/%s", ptr + 1), 1); + tex = LoadImage (va (0, "textures/%s", ptr + 1), 1); if (tex) { pskindesc->texnum = GL_LoadTexture (filename, tex->width, tex->height, tex->data, true, false, @@ -130,22 +130,22 @@ Mod_LoadExternalSkin (maliasskindesc_t *pskindesc, char *filename) pskindesc->fb_texnum = 0; - glow = LoadImage (va ("%s_luma", filename), 1); + glow = LoadImage (va (0, "%s_luma", filename), 1); if (!glow) - glow = LoadImage (va ("%s_glow", filename), 1); + glow = LoadImage (va (0, "%s_glow", filename), 1); if (!glow) - glow = LoadImage (va ("textures/%s_luma", ptr + 1), 1); + glow = LoadImage (va (0, "textures/%s_luma", ptr + 1), 1); if (!glow) - glow = LoadImage (va ("textures/%s_glow", ptr + 1), 1); + glow = LoadImage (va (0, "textures/%s_glow", ptr + 1), 1); if (glow) pskindesc->fb_texnum = - GL_LoadTexture (va ("fb_%s", filename), glow->width, + GL_LoadTexture (va (0, "fb_%s", filename), glow->width, glow->height, glow->data, true, true, glow->format > 2 ? glow->format : 1); else if (tex->format < 3) pskindesc->fb_texnum = Mod_Fullbright (tex->data, tex->width, tex->height, - va ("fb_%s", filename)); + va (0, "fb_%s", filename)); } } diff --git a/libs/models/alias/glsl_model_alias.c b/libs/models/alias/glsl_model_alias.c index cb612e962..796b3f346 100644 --- a/libs/models/alias/glsl_model_alias.c +++ b/libs/models/alias/glsl_model_alias.c @@ -104,9 +104,9 @@ glsl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, memcpy (tskin, skin, skinsize); Mod_FloodFillSkin (tskin, w, h); if (group) - name = va ("%s_%i_%i", loadmodel->name, snum, gnum); + name = va (0, "%s_%i_%i", loadmodel->name, snum, gnum); else - name = va ("%s_%i", loadmodel->name, snum); + name = va (0, "%s_%i", loadmodel->name, snum); skindesc->texnum = GLSL_LoadQuakeTexture (name, w, h, tskin); free (tskin); return skin + skinsize; diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index 832541071..91ae665d0 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -128,19 +128,28 @@ Vulkan_Mod_LoadSkin (byte *skinpix, int skinsize, int snum, int gnum, tex_t skin_tex = {w, h, tex_palette, 1, vid.palette, tskin + skinsize}; if (Mod_CalcFullbright (tskin, tskin + skinsize, skinsize)) { - skin->glow = Vulkan_LoadTex (ctx, &skin_tex, 1); + skin->glow = Vulkan_LoadTex (ctx, &skin_tex, 1, + va (ctx->va_ctx, "%s:%d:%d:glow", + loadmodel->name, snum, gnum)); Mod_ClearFullbright (tskin, tskin, skinsize); } if (Skin_CalcTopColors (tskin, tskin + skinsize, skinsize)) { - skin->colora = Vulkan_LoadTex (ctx, &skin_tex, 1); + skin->colora = Vulkan_LoadTex (ctx, &skin_tex, 1, + va (ctx->va_ctx, "%s:%d:%d:colora", + loadmodel->name, snum, gnum)); Skin_ClearTopColors (tskin, tskin, skinsize); } if (Skin_CalcBottomColors (tskin, tskin + skinsize, skinsize)) { - skin->colorb = Vulkan_LoadTex (ctx, &skin_tex, 1); + skin->colorb = Vulkan_LoadTex (ctx, &skin_tex, 1, + va (ctx->va_ctx, "%s:%d:%d:colorb", + loadmodel->name, snum, gnum)); Skin_ClearBottomColors (tskin, tskin, skinsize); } skin_tex.data = tskin; - skin->tex = Vulkan_LoadTex (ctx, &skin_tex, 1); + skin->tex = Vulkan_LoadTex (ctx, &skin_tex, 1, + va (ctx->va_ctx, "%s:%d:%d:tex", + loadmodel->name, + snum, gnum)); free (tskin); diff --git a/libs/models/brush/gl_model_brush.c b/libs/models/brush/gl_model_brush.c index 1d7d04634..878d2c344 100644 --- a/libs/models/brush/gl_model_brush.c +++ b/libs/models/brush/gl_model_brush.c @@ -63,17 +63,17 @@ Mod_LoadAnExternalTexture (char *tname, char *mname) if (rname[0] == '*') rname[0] = '#'; - image = LoadImage (va ("textures/%.*s/%s", (int) strlen (mname + 5) - 4, + image = LoadImage (va (0, "textures/%.*s/%s", (int) strlen (mname + 5) - 4, mname + 5, rname), 1); if (!image) - image = LoadImage (va ("maps/%.*s/%s", (int) strlen (mname + 5) - 4, + image = LoadImage (va (0, "maps/%.*s/%s", (int) strlen (mname + 5) - 4, mname + 5, rname), 1); // if (!image) -// image = LoadImage (va ("textures/bmodels/%s", rname)); +// image = LoadImage (va (0, "textures/bmodels/%s", rname)); if (!image) - image = LoadImage (va ("textures/%s", rname), 1); + image = LoadImage (va (0, "textures/%s", rname), 1); if (!image) - image = LoadImage (va ("maps/%s", rname), 1); + image = LoadImage (va (0, "maps/%s", rname), 1); return image; } @@ -93,23 +93,23 @@ Mod_LoadExternalTextures (model_t *mod, texture_t *tx) base->data, true, false, base->format > 2 ? base->format : 1); - luma = Mod_LoadAnExternalTexture (va ("%s_luma", tx->name), + luma = Mod_LoadAnExternalTexture (va (0, "%s_luma", tx->name), mod->name); if (!luma) - luma = Mod_LoadAnExternalTexture (va ("%s_glow", tx->name), + luma = Mod_LoadAnExternalTexture (va (0, "%s_glow", tx->name), mod->name); gltx->gl_fb_texturenum = 0; if (luma) { gltx->gl_fb_texturenum = - GL_LoadTexture (va ("fb_%s", tx->name), luma->width, + GL_LoadTexture (va (0, "fb_%s", tx->name), luma->width, luma->height, luma->data, true, true, luma->format > 2 ? luma->format : 1); } else if (base->format < 3) { gltx->gl_fb_texturenum = Mod_Fullbright (base->data, base->width, base->height, - va ("fb_%s", tx->name)); + va (0, "fb_%s", tx->name)); } } return external; @@ -133,7 +133,7 @@ gl_Mod_ProcessTexture (texture_t *tx) return; } gltex_t *gltex = tx->render; - name = va ("fb_%s", tx->name); + name = va (0, "fb_%s", tx->name); gltex->gl_fb_texturenum = Mod_Fullbright ((byte *) (tx + 1), tx->width, tx->height, name); gltex->gl_texturenum = diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index c9b336f0f..3d45dd63c 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -356,7 +356,7 @@ Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx) return; } - const char *name = va ("fb_%s", tx->name); + const char *name = va (ctx->va_ctx, "fb_%s", tx->name); int size = (tx->width * tx->height * 85) / 64; int fullbright_mark = Hunk_LowMark (); byte *pixels = Hunk_AllocName (size, name); diff --git a/libs/models/iqm/gl_model_iqm.c b/libs/models/iqm/gl_model_iqm.c index 93a1e9992..fc9c50f1a 100644 --- a/libs/models/iqm/gl_model_iqm.c +++ b/libs/models/iqm/gl_model_iqm.c @@ -80,7 +80,7 @@ gl_iqm_load_textures (iqm_t *iqm) for (i = 0; i < iqm->num_meshes; i++) { dstring_copystr (str, iqm->text + iqm->meshes[i].material); QFS_StripExtension (str->str, str->str); - if ((tex = LoadImage (va ("textures/%s", str->str), 1))) + if ((tex = LoadImage (va (0, "textures/%s", str->str), 1))) gl->textures[i] = GL_LoadTexture (str->str, tex->width, tex->height, tex->data, true, false, diff --git a/libs/models/iqm/glsl_model_iqm.c b/libs/models/iqm/glsl_model_iqm.c index 5b37e0fd2..c8a82a112 100644 --- a/libs/models/iqm/glsl_model_iqm.c +++ b/libs/models/iqm/glsl_model_iqm.c @@ -102,12 +102,12 @@ glsl_iqm_load_textures (iqm_t *iqm) for (i = 0; i < iqm->num_meshes; i++) { dstring_copystr (str, iqm->text + iqm->meshes[i].material); QFS_StripExtension (str->str, str->str); - if ((tex = LoadImage (va ("textures/%s", str->str), 1))) + if ((tex = LoadImage (va (0, "textures/%s", str->str), 1))) glsl->textures[i] = GLSL_LoadRGBATexture (str->str, tex->width, tex->height, tex->data); else glsl->textures[i] = GLSL_LoadRGBATexture ("", 2, 2, null_texture); - if ((tex = LoadImage (va ("textures/%s_norm", str->str), 1))) + if ((tex = LoadImage (va (0, "textures/%s_norm", str->str), 1))) glsl->normmaps[i] = GLSL_LoadRGBATexture (str->str, tex->width, tex->height, tex->data); else diff --git a/libs/models/iqm/sw_model_iqm.c b/libs/models/iqm/sw_model_iqm.c index 274a6f0a9..f48867ae1 100644 --- a/libs/models/iqm/sw_model_iqm.c +++ b/libs/models/iqm/sw_model_iqm.c @@ -174,7 +174,7 @@ sw_iqm_load_textures (iqm_t *iqm) continue; dstring_copystr (str, iqm->text + iqm->meshes[i].material); QFS_StripExtension (str->str, str->str); - if ((tex = LoadImage (va ("textures/%s", str->str), 1))) + if ((tex = LoadImage (va (0, "textures/%s", str->str), 1))) tex = sw->skins[i] = convert_tex (tex); else tex = sw->skins[i] = &null_texture; diff --git a/libs/models/skin.c b/libs/models/skin.c index fd561143d..e5a0353f5 100644 --- a/libs/models/skin.c +++ b/libs/models/skin.c @@ -177,7 +177,7 @@ Skin_SetSkin (skin_t *skin, int cmap, const char *skinname) break; } - file = QFS_FOpenFile (va ("skins/%s.pcx", name)); + file = QFS_FOpenFile (va (0, "skins/%s.pcx", name)); if (!file) { Sys_Printf ("Couldn't load skin %s\n", name); free (name); diff --git a/libs/models/sprite/gl_model_sprite.c b/libs/models/sprite/gl_model_sprite.c index f050e9bdb..1d5d1597c 100644 --- a/libs/models/sprite/gl_model_sprite.c +++ b/libs/models/sprite/gl_model_sprite.c @@ -49,7 +49,7 @@ gl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum) tex_t *targa; const char *name; - targa = LoadImage (name = va ("%s_%i", loadmodel->name, framenum), 1); + targa = LoadImage (name = va (0, "%s_%i", loadmodel->name, framenum), 1); if (targa) { if (targa->format < 4) pspriteframe->gl_texturenum = GL_LoadTexture (name, diff --git a/libs/models/sprite/glsl_model_sprite.c b/libs/models/sprite/glsl_model_sprite.c index bbef94e02..138b3d0d0 100644 --- a/libs/models/sprite/glsl_model_sprite.c +++ b/libs/models/sprite/glsl_model_sprite.c @@ -76,7 +76,7 @@ glsl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum) const char *name; loadmodel->clear = glsl_sprite_clear; - name = va ("%s_%i", loadmodel->name, framenum); + name = va (0, "%s_%i", loadmodel->name, framenum); pspriteframe->gl_texturenum = GLSL_LoadQuakeTexture (name, pspriteframe->width, pspriteframe->height, pspriteframe->pixels); diff --git a/libs/ruamoko/rua_cvar.c b/libs/ruamoko/rua_cvar.c index 18275988e..dbb652817 100644 --- a/libs/ruamoko/rua_cvar.c +++ b/libs/ruamoko/rua_cvar.c @@ -140,7 +140,7 @@ bi_Cvar_SetInteger (progs_t *pr) if (!var) var = Cvar_FindAlias (varname); if (var) - Cvar_Set (var, va ("%d", val)); + Cvar_Set (var, va (0, "%d", val)); } static void @@ -153,7 +153,7 @@ bi_Cvar_SetFloat (progs_t *pr) if (!var) var = Cvar_FindAlias (varname); if (var) - Cvar_Set (var, va ("%g", val)); + Cvar_Set (var, va (0, "%g", val)); } static void @@ -166,7 +166,7 @@ bi_Cvar_SetVector (progs_t *pr) if (!var) var = Cvar_FindAlias (varname); if (var) - Cvar_Set (var, va ("%g %g %g", val[0], val[1], val[2])); + Cvar_Set (var, va (0, "%g %g %g", val[0], val[1], val[2])); } static void diff --git a/libs/ruamoko/rua_qfs.c b/libs/ruamoko/rua_qfs.c index 87b2c5add..4a3eebb59 100644 --- a/libs/ruamoko/rua_qfs.c +++ b/libs/ruamoko/rua_qfs.c @@ -146,7 +146,8 @@ bi_QFS_WriteFile (progs_t *pr) int count = P_INT (pr, 2); check_buffer (pr, buf, count, "QFS_WriteFile"); - QFS_WriteFile (va ("%s/%s", qfs_gamedir->dir.def, filename), buf, count); + QFS_WriteFile (va (0, "%s/%s", qfs_gamedir->dir.def, filename), buf, + count); } static void diff --git a/libs/util/cvar.c b/libs/util/cvar.c index dc4485828..afcfeef33 100644 --- a/libs/util/cvar.c +++ b/libs/util/cvar.c @@ -284,7 +284,7 @@ Cvar_Set (cvar_t *var, const char *value) VISIBLE void Cvar_SetValue (cvar_t *var, float value) { - Cvar_Set (var, va ("%g", value)); + Cvar_Set (var, va (0, "%g", value)); } /* @@ -608,7 +608,7 @@ Cvar_CvarList_f (void) showhelp++; } for (var = cvar_vars, i = 0; var; var = var->next, i++) { - flags = va ("%c%c%c%c", + flags = va (0, "%c%c%c%c", var->flags & CVAR_ROM ? 'r' : ' ', var->flags & CVAR_ARCHIVE ? '*' : ' ', var->flags & CVAR_USERINFO ? 'u' : ' ', diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index fe0fc3268..f36b6552e 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -90,6 +90,7 @@ typedef struct pldata_s { // Unparsed property list string unsigned pos; unsigned line; plitem_t *error; + va_ctx_t *va_ctx; } pldata_t; // Ugly defines for fast checking and conversion from char to number @@ -533,7 +534,8 @@ PL_ParseData (pldata_t *pl, int *len) pl->ptr[start + i * 2 + 1]); return str; } - pl->error = PL_NewString (va ("invalid character in data: %02x", c)); + pl->error = PL_NewString (va (pl->va_ctx, + "invalid character in data: %02x", c)); return NULL; } pl->error = PL_NewString ("Reached end of string while parsing data"); @@ -748,7 +750,7 @@ PL_ParsePropertyListItem (pldata_t *pl) } if (pl->ptr[pl->pos] != '=') { - pl->error = PL_NewString (va ("Unexpected character %c (expected '=')", pl->ptr[pl->pos])); + pl->error = PL_NewString (va (pl->va_ctx, "Unexpected character %c (expected '=')", pl->ptr[pl->pos])); PL_Free (key); PL_Free (item); return NULL; @@ -772,7 +774,7 @@ PL_ParsePropertyListItem (pldata_t *pl) if (pl->ptr[pl->pos] == ';') { pl->pos++; } else if (pl->ptr[pl->pos] != '}') { - pl->error = PL_NewString (va ("Unexpected character %c (wanted ';' or '}')", pl->ptr[pl->pos])); + pl->error = PL_NewString (va (pl->va_ctx, "Unexpected character %c (wanted ';' or '}')", pl->ptr[pl->pos])); PL_Free (key); PL_Free (value); PL_Free (item); @@ -822,7 +824,7 @@ PL_ParsePropertyListItem (pldata_t *pl) if (pl->ptr[pl->pos] == ',') { pl->pos++; } else if (pl->ptr[pl->pos] != ')') { - pl->error = PL_NewString (va ("Unexpected character %c (wanted ',' or ')')", pl->ptr[pl->pos])); + pl->error = PL_NewString (va (pl->va_ctx, "Unexpected character %c (wanted ',' or ')')", pl->ptr[pl->pos])); PL_Free (value); PL_Free (item); return NULL; @@ -891,8 +893,10 @@ PL_GetPropertyList (const char *string) pl->end = strlen (string); pl->error = NULL; pl->line = 1; + pl->va_ctx = va_create_context (4); if ((newpl = PL_ParsePropertyListItem (pl))) { + va_destroy_context (pl->va_ctx); free (pl); return newpl; } else { @@ -903,6 +907,7 @@ PL_GetPropertyList (const char *string) } PL_Free (pl->error); } + va_destroy_context (pl->va_ctx); free (pl); return NULL; } @@ -1093,22 +1098,25 @@ VISIBLE void PL_Message (plitem_t *messages, const plitem_t *item, const char *fmt, ...) { va_list args; - dstring_t *string; + dstring_t *va_str; + dstring_t *msg_str; + char *msg; - string = dstring_new (); + va_str = dstring_new (); + msg_str = dstring_new (); va_start (args, fmt); - dvsprintf (string, fmt, args); + dvsprintf (va_str, fmt, args); va_end (args); if (item) { - PL_A_AddObject (messages, - PL_NewString (va ("%d: %s", item->line, string->str))); + msg = dsprintf (msg_str, "%d: %s", item->line, va_str->str); } else { - PL_A_AddObject (messages, - PL_NewString (va ("internal: %s", string->str))); + msg = dsprintf (msg_str, "internal: %s", va_str->str); } - dstring_delete (string); + PL_A_AddObject (messages, PL_NewString (msg)); + dstring_delete (va_str); + dstring_delete (msg_str); } static int diff --git a/libs/util/quakefs.c b/libs/util/quakefs.c index 039548130..683378904 100644 --- a/libs/util/quakefs.c +++ b/libs/util/quakefs.c @@ -359,7 +359,7 @@ qfs_var_subst (const char *string, hashtab_t *vars) dstring_appendsubstr (new, s, (e - s)); break; } - var = va ("%.*s", (int) (e - s) - 1, s + 1); + var = va (0, "%.*s", (int) (e - s) - 1, s + 1); sub = Hash_Find (vars, var); if (sub) dstring_appendstr (new, sub->val); @@ -370,7 +370,7 @@ qfs_var_subst (const char *string, hashtab_t *vars) s = e; while (qfs_isident (*e)) e++; - var = va ("%.*s", (int) (e - s), s); + var = va (0, "%.*s", (int) (e - s), s); sub = Hash_Find (vars, var); if (sub) dstring_appendstr (new, sub->val); @@ -588,7 +588,7 @@ qfs_build_gamedir (const char **list) gamedir = calloc (1, sizeof (gamedir_t)); path = dstring_newstr (); while (j--) { - const char *name = va ("%s:%s", qfs_game, dir = list[j]); + const char *name = va (0, "%s:%s", qfs_game, dir = list[j]); if (Hash_Find (dirs, name)) continue; gdpl = qfs_find_gamedir (name, dirs); @@ -1661,7 +1661,7 @@ QFS_FilelistAdd (filelist_t *filelist, const char *fname, const char *ext) } str = strdup (fname); - if (ext && (s = strstr(str, va(".%s", ext)))) + if (ext && (s = strstr(str, va (0, ".%s", ext)))) *s = 0; filelist->list[filelist->count++] = str; } @@ -1680,9 +1680,9 @@ qfs_filelistfill_do (filelist_t *list, const searchpath_t *search, const char *c for (i = 0; i < pak->numfiles; i++) { char *name = pak->files[i].name; - if (!fnmatch (va("%s%s*.%s", cp, separator, ext), name, + if (!fnmatch (va (0, "%s%s*.%s", cp, separator, ext), name, FNM_PATHNAME) - || !fnmatch (va("%s%s*.%s.gz", cp, separator, ext), name, + || !fnmatch (va (0, "%s%s*.%s.gz", cp, separator, ext), name, FNM_PATHNAME)) QFS_FilelistAdd (list, name, strip ? ext : 0); } @@ -1690,12 +1690,12 @@ qfs_filelistfill_do (filelist_t *list, const searchpath_t *search, const char *c DIR *dir_ptr; struct dirent *dirent; - dir_ptr = opendir (va ("%s/%s", search->filename, cp)); + dir_ptr = opendir (va (0, "%s/%s", search->filename, cp)); if (!dir_ptr) return; while ((dirent = readdir (dir_ptr))) - if (!fnmatch (va("*.%s", ext), dirent->d_name, 0) - || !fnmatch (va("*.%s.gz", ext), dirent->d_name, 0)) + if (!fnmatch (va (0, "*.%s", ext), dirent->d_name, 0) + || !fnmatch (va (0, "*.%s.gz", ext), dirent->d_name, 0)) QFS_FilelistAdd (list, dirent->d_name, strip ? ext : 0); closedir (dir_ptr); } diff --git a/libs/util/va.c b/libs/util/va.c index dd24c05d1..c4b83aebb 100644 --- a/libs/util/va.c +++ b/libs/util/va.c @@ -40,28 +40,51 @@ #include "QF/dstring.h" #include "QF/va.h" +struct va_ctx_s { + dstring_t **strings; + int num_strings; + int str_index; +}; -/* - va - - does a varargs printf into a temp buffer, so I don't need to have - varargs versions of all text functions. -*/ -VISIBLE char * -va (const char *fmt, ...) +VISIBLE va_ctx_t * +va_create_context (int buffers) { + va_ctx_t *ctx; + + ctx = malloc (sizeof (va_ctx_t) + buffers * sizeof (dstring_t *)); + ctx->strings = (dstring_t **) (ctx + 1); + ctx->num_strings = buffers; + ctx->str_index = 0; + + for (int i = 0; i < buffers; i++) { + ctx->strings[i] = dstring_new (); + } + return ctx; +} + +VISIBLE void +va_destroy_context (va_ctx_t *ctx) +{ + for (int i = 0; i < ctx->num_strings; i++) { + dstring_delete (ctx->strings[i]); + } + free (ctx); +} + +VISIBLE char * +va (va_ctx_t *ctx, const char *fmt, ...) +{ + static va_ctx_t *_ctx; va_list args; - static dstring_t *string[4]; -#define NUM_STRINGS (sizeof (string) / sizeof (string[0])) - static int str_index; dstring_t *dstr; - if (!string[0]) { - for (size_t i = 0; i < NUM_STRINGS; i++) { - string[i] = dstring_new (); + if (!ctx) { + if (!_ctx) { + _ctx = va_create_context (4); } + ctx = _ctx; } - dstr = string[str_index++ % NUM_STRINGS]; + dstr = ctx->strings[ctx->str_index++ % ctx->num_strings]; va_start (args, fmt); dvsprintf (dstr, fmt, args); diff --git a/libs/video/renderer/gl/gl_dyn_part.c b/libs/video/renderer/gl/gl_dyn_part.c index 0572efec0..c3b0ddf68 100644 --- a/libs/video/renderer/gl/gl_dyn_part.c +++ b/libs/video/renderer/gl/gl_dyn_part.c @@ -210,7 +210,7 @@ gl_R_ReadPointFile_f (void) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); - name = va ("%s.pts", mapname); + name = va (0, "%s.pts", mapname); free (mapname); f = QFS_FOpenFile (name); diff --git a/libs/video/renderer/gl/gl_screen.c b/libs/video/renderer/gl/gl_screen.c index f8b0e6546..96738d58e 100644 --- a/libs/video/renderer/gl/gl_screen.c +++ b/libs/video/renderer/gl/gl_screen.c @@ -152,7 +152,7 @@ gl_SCR_ScreenShot_f (void) // find a file name to save it to if (!QFS_NextFilename (pcxname, - va ("%s/qf", qfs_gamedir->dir.shots), ".tga")) { + va (0, "%s/qf", qfs_gamedir->dir.shots), ".tga")) { Sys_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n"); } else { tex_t *tex; diff --git a/libs/video/renderer/gl/gl_sky.c b/libs/video/renderer/gl/gl_sky.c index 4f69ef8b7..cb3258246 100644 --- a/libs/video/renderer/gl/gl_sky.c +++ b/libs/video/renderer/gl/gl_sky.c @@ -131,11 +131,12 @@ gl_R_LoadSkys (const char *skyname) qfglBindTexture (GL_TEXTURE_2D, SKY_TEX + i); - targa = LoadImage (name = va ("env/%s%s", skyname, suf[i]), 1); + targa = LoadImage (name = va (0, "env/%s%s", skyname, suf[i]), 1); if (!targa || targa->format < 3) { // FIXME Can't do PCX right now Sys_MaskPrintf (SYS_DEV, "Couldn't load %s\n", name); // also look in gfx/env, where Darkplaces looks for skies - targa = LoadImage (name = va ("gfx/env/%s%s", skyname, suf[i]), 1); + targa = LoadImage (name = va (0, "gfx/env/%s%s", skyname, + suf[i]), 1); if (!targa) { Sys_MaskPrintf (SYS_DEV, "Couldn't load %s\n", name); gl_skyloaded = false; diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index 144f8094c..480c647a9 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -1402,7 +1402,7 @@ glsl_R_LoadSkys (const char *sky) //blender envmap // bk rt ft // dn up lt - tex = LoadImage (name = va ("env/%s_map", sky), 1); + tex = LoadImage (name = va (0, "env/%s_map", sky), 1); if (tex && tex->format >= 3 && tex->height * 3 == tex->width * 2 && is_pow2 (tex->height)) { tex_t *sub; @@ -1430,11 +1430,11 @@ glsl_R_LoadSkys (const char *sky) } else { skybox_loaded = true; for (i = 0; i < 6; i++) { - tex = LoadImage (name = va ("env/%s%s", sky, sky_suffix[i]), 1); + tex = LoadImage (name = va (0, "env/%s%s", sky, sky_suffix[i]), 1); if (!tex || tex->format < 3) { // FIXME pcx support Sys_MaskPrintf (SYS_GLSL, "Couldn't load %s\n", name); // also look in gfx/env, where Darkplaces looks for skies - tex = LoadImage (name = va ("gfx/env/%s%s", sky, + tex = LoadImage (name = va (0, "gfx/env/%s%s", sky, sky_suffix[i]), 1); if (!tex || tex->format < 3) { // FIXME pcx support Sys_MaskPrintf (SYS_GLSL, "Couldn't load %s\n", name); diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index cb956188c..5a0dcd43a 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -318,7 +318,7 @@ glsl_R_ReadPointFile_f (void) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); - name = va ("%s.pts", mapname); + name = va (0, "%s.pts", mapname); free (mapname); f = QFS_FOpenFile (name); diff --git a/libs/video/renderer/glsl/glsl_screen.c b/libs/video/renderer/glsl/glsl_screen.c index a19d3205a..16063c7c5 100644 --- a/libs/video/renderer/glsl/glsl_screen.c +++ b/libs/video/renderer/glsl/glsl_screen.c @@ -231,8 +231,8 @@ glsl_SCR_ScreenShot_f (void) dstring_t *name = dstring_new (); // find a file name to save it to - if (!QFS_NextFilename (name, - va ("%s/qf", qfs_gamedir->dir.shots), ".png")) { + if (!QFS_NextFilename (name, va (0, "%s/qf", + qfs_gamedir->dir.shots), ".png")) { Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PNG file\n"); } else { tex_t *tex; diff --git a/libs/video/renderer/glsl/vid_common_glsl.c b/libs/video/renderer/glsl/vid_common_glsl.c index a437fd96e..7fabdd6d2 100644 --- a/libs/video/renderer/glsl/vid_common_glsl.c +++ b/libs/video/renderer/glsl/vid_common_glsl.c @@ -268,7 +268,7 @@ type_name (GLenum type) case GL_FIXED: return "fixed"; } - return va("%x", type); + return va (0, "%x", type); } static void diff --git a/libs/video/renderer/sw/screen.c b/libs/video/renderer/sw/screen.c index 125d8648f..12b7116de 100644 --- a/libs/video/renderer/sw/screen.c +++ b/libs/video/renderer/sw/screen.c @@ -159,7 +159,7 @@ SCR_ScreenShot_f (void) // find a file name to save it to if (!QFS_NextFilename (pcxname, - va ("%s/qf", qfs_gamedir->dir.shots), ".pcx")) { + va (0, "%s/qf", qfs_gamedir->dir.shots), ".pcx")) { Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PCX"); } else { // enable direct drawing of console to back buffer diff --git a/libs/video/renderer/sw/sw_rpart.c b/libs/video/renderer/sw/sw_rpart.c index d7039504f..c05281863 100644 --- a/libs/video/renderer/sw/sw_rpart.c +++ b/libs/video/renderer/sw/sw_rpart.c @@ -88,7 +88,7 @@ R_ReadPointFile_f (void) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); - name = va ("maps/%s.pts", mapname); + name = va (0, "maps/%s.pts", mapname); free (mapname); f = QFS_FOpenFile (name); diff --git a/libs/video/renderer/sw32/screen.c b/libs/video/renderer/sw32/screen.c index ce84cb08c..f1e9e1380 100644 --- a/libs/video/renderer/sw32/screen.c +++ b/libs/video/renderer/sw32/screen.c @@ -103,8 +103,8 @@ sw32_SCR_ScreenShot_f (void) int pcx_len; // find a file name to save it to - if (!QFS_NextFilename (pcxname, - va ("%s/qf", qfs_gamedir->dir.shots), ".pcx")) { + if (!QFS_NextFilename (pcxname, va (0, "%s/qf", + qfs_gamedir->dir.shots), ".pcx")) { Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PCX"); } else { // enable direct drawing of console to back buffer diff --git a/libs/video/renderer/sw32/sw32_rpart.c b/libs/video/renderer/sw32/sw32_rpart.c index fe2e39601..655467525 100644 --- a/libs/video/renderer/sw32/sw32_rpart.c +++ b/libs/video/renderer/sw32/sw32_rpart.c @@ -93,7 +93,7 @@ sw32_R_ReadPointFile_f (void) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); - name = va ("maps/%s.pts", mapname); + name = va (0, "maps/%s.pts", mapname); free (mapname); f = QFS_FOpenFile (name); diff --git a/libs/video/targets/context_sdl.c b/libs/video/targets/context_sdl.c index 7a764553a..21fde4b06 100644 --- a/libs/video/targets/context_sdl.c +++ b/libs/video/targets/context_sdl.c @@ -40,10 +40,10 @@ VID_SetCaption (const char *text) if (text && *text) { char *temp = strdup (text); - SDL_WM_SetCaption (va ("%s: %s", PACKAGE_STRING, temp), NULL); + SDL_WM_SetCaption (va (0, "%s: %s", PACKAGE_STRING, temp), NULL); free (temp); } else { - SDL_WM_SetCaption (va ("%s", PACKAGE_STRING), NULL); + SDL_WM_SetCaption (va (0, "%s", PACKAGE_STRING), NULL); } } diff --git a/libs/video/targets/context_x11.c b/libs/video/targets/context_x11.c index 7f952aa99..c118feab2 100644 --- a/libs/video/targets/context_x11.c +++ b/libs/video/targets/context_x11.c @@ -566,7 +566,7 @@ X11_CreateWindow (int width, int height) XFree (SizeHints); } // Set window title - X11_SetCaption (va ("%s", PACKAGE_STRING)); + X11_SetCaption (va (0, "%s", PACKAGE_STRING)); // Set icon name XSetIconName (x_disp, x_win, PACKAGE_NAME); diff --git a/libs/video/targets/joy.c b/libs/video/targets/joy.c index 0a209cdfe..da25db1f4 100644 --- a/libs/video/targets/joy.c +++ b/libs/video/targets/joy.c @@ -183,7 +183,7 @@ JOY_Init (void) static void joyamp_f (cvar_t *var) { - Cvar_Set (var, va ("%g", max (0.0001, var->value))); + Cvar_Set (var, va (0, "%g", max (0.0001, var->value))); } typedef struct { diff --git a/libs/video/targets/vid.c b/libs/video/targets/vid.c index b656b5a22..49f33c004 100644 --- a/libs/video/targets/vid.c +++ b/libs/video/targets/vid.c @@ -90,9 +90,9 @@ VID_GetWindowSize (int def_w, int def_h) { int pnum, conheight; - vid_width = Cvar_Get ("vid_width", va ("%d", def_w), CVAR_NONE, NULL, + vid_width = Cvar_Get ("vid_width", va (0, "%d", def_w), CVAR_NONE, NULL, "screen width"); - vid_height = Cvar_Get ("vid_height", va ("%d", def_h), CVAR_NONE, NULL, + vid_height = Cvar_Get ("vid_height", va (0, "%d", def_h), CVAR_NONE, NULL, "screen height"); vid_aspect = Cvar_Get ("vid_aspect", "4:3", CVAR_ROM, vid_aspect_f, "Physical screen aspect ratio in \"width:height\" format. " @@ -140,7 +140,7 @@ VID_GetWindowSize (int def_w, int def_h) viddef.aspect = ((vid_aspect->vec[0] * viddef.height) / (vid_aspect->vec[1] * viddef.width)); - con_width = Cvar_Get ("con_width", va ("%d", viddef.width), CVAR_NONE, + con_width = Cvar_Get ("con_width", va (0, "%d", viddef.width), CVAR_NONE, NULL, "console effective width (GL only)"); if ((pnum = COM_CheckParm ("-conwidth"))) { if (pnum >= com_argc - 1) @@ -148,20 +148,20 @@ VID_GetWindowSize (int def_w, int def_h) Cvar_Set (con_width, com_argv[pnum + 1]); } // make con_width a multiple of 8 and >= 320 - Cvar_Set (con_width, va ("%d", max (con_width->int_val & ~7, 320))); + Cvar_Set (con_width, va (0, "%d", max (con_width->int_val & ~7, 320))); Cvar_SetFlags (con_width, con_width->flags | CVAR_ROM); viddef.conwidth = con_width->int_val; conheight = (viddef.conwidth * vid_aspect->vec[1]) / vid_aspect->vec[0]; - con_height = Cvar_Get ("con_height", va ("%d", conheight), CVAR_NONE, NULL, - "console effective height (GL only)"); + con_height = Cvar_Get ("con_height", va (0, "%d", conheight), CVAR_NONE, + NULL, "console effective height (GL only)"); if ((pnum = COM_CheckParm ("-conheight"))) { if (pnum >= com_argc - 1) Sys_Error ("VID: -conheight "); Cvar_Set (con_height, com_argv[pnum + 1]); } // make con_height >= 200 - Cvar_Set (con_height, va ("%d", max (con_height->int_val, 200))); + Cvar_Set (con_height, va (0, "%d", max (con_height->int_val, 200))); Cvar_SetFlags (con_height, con_height->flags | CVAR_ROM); viddef.conheight = con_height->int_val; @@ -258,7 +258,7 @@ VID_InitGamma (unsigned char *pal) } gamma = bound (0.1, gamma, 9.9); - vid_gamma = Cvar_Get ("vid_gamma", va ("%f", gamma), CVAR_ARCHIVE, + vid_gamma = Cvar_Get ("vid_gamma", va (0, "%f", gamma), CVAR_ARCHIVE, VID_UpdateGamma, "Gamma correction"); VID_BuildGammaTable (vid_gamma->value); diff --git a/libs/video/targets/vid_x11.c b/libs/video/targets/vid_x11.c index 58183ba8f..b29b64b1f 100644 --- a/libs/video/targets/vid_x11.c +++ b/libs/video/targets/vid_x11.c @@ -182,10 +182,10 @@ VID_SetCaption (const char *text) if (text && *text) { char *temp = strdup (text); - X11_SetCaption (va ("%s: %s", PACKAGE_STRING, temp)); + X11_SetCaption (va (0, "%s: %s", PACKAGE_STRING, temp)); free (temp); } else { - X11_SetCaption (va ("%s", PACKAGE_STRING)); + X11_SetCaption (va (0, "%s", PACKAGE_STRING)); } } diff --git a/libs/video/targets/vid_x11_vulkan.c b/libs/video/targets/vid_x11_vulkan.c index cd228b051..d64bed09f 100644 --- a/libs/video/targets/vid_x11_vulkan.c +++ b/libs/video/targets/vid_x11_vulkan.c @@ -53,6 +53,7 @@ #include "QF/cvar.h" #include "QF/set.h" #include "QF/sys.h" +#include "QF/va.h" #include "QF/Vulkan/instance.h" @@ -211,6 +212,7 @@ X11_Vulkan_Context (void) ctx->create_window = x11_vulkan_create_window; ctx->create_surface = x11_vulkan_create_surface; ctx->required_extensions = required_extensions; + ctx->va_ctx = va_create_context (4); return ctx; } diff --git a/nq/source/cl_demo.c b/nq/source/cl_demo.c index 55a10af26..2b264d850 100644 --- a/nq/source/cl_demo.c +++ b/nq/source/cl_demo.c @@ -312,7 +312,7 @@ CL_Record_f (void) // start up the map if (c > 2) - Cmd_ExecuteString (va ("map %s", Cmd_Argv (2)), src_command); + Cmd_ExecuteString (va (0, "map %s", Cmd_Argv (2)), src_command); CL_Record (Cmd_Argv (1), track); } diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index f93b924d6..9424a670e 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -106,7 +106,7 @@ CL_WriteConfiguration (void) // dedicated servers initialize the host but don't parse and set the // config.cfg cvars if (host_initialized && !isDedicated && cl_writecfg->int_val) { - char *path = va ("%s/config.cfg", qfs_gamedir->dir.def); + char *path = va (0, "%s/config.cfg", qfs_gamedir->dir.def); f = QFS_WOpen (path, 0); if (!f) { Sys_Printf ("Couldn't write config.cfg.\n"); @@ -344,10 +344,11 @@ CL_SignonReply (void) case so_spawn: MSG_WriteByte (&cls.message, clc_stringcmd); - MSG_WriteString (&cls.message, va ("name \"%s\"\n", cl_name->string)); + MSG_WriteString (&cls.message, va (0, "name \"%s\"\n", + cl_name->string)); MSG_WriteByte (&cls.message, clc_stringcmd); MSG_WriteString (&cls.message, - va ("color %i %i\n", (cl_color->int_val) >> 4, + va (0, "color %i %i\n", (cl_color->int_val) >> 4, (cl_color->int_val) & 15)); MSG_WriteByte (&cls.message, clc_stringcmd); MSG_WriteString (&cls.message, "spawn"); @@ -389,7 +390,8 @@ CL_NextDemo (void) } } - Cbuf_InsertText (host_cbuf, va ("playdemo %s\n", cls.demos[cls.demonum])); + Cbuf_InsertText (host_cbuf, va (0, "playdemo %s\n", + cls.demos[cls.demonum])); cls.demonum++; } diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index bf9ce6418..981f72714 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -866,7 +866,7 @@ CL_ParseServerMessage (void) continue; } - SHOWNET (va ("%s(%d)", svc_strings[cmd], cmd)); + SHOWNET (va (0, "%s(%d)", svc_strings[cmd], cmd)); // other commands switch (cmd) { diff --git a/nq/source/host.c b/nq/source/host.c index c852311be..861e9d06b 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -529,7 +529,7 @@ Host_FilterTime (float time) //FIXME not having the framerate cap is nice, but it breaks net play timedifference = (timescale / 72.0) - (realtime - oldrealtime); - if (!cls.timedemo && (timedifference > 0)) + if (0 && !cls.timedemo && (timedifference > 0)) return timedifference; // framerate is too high host_frametime = realtime - oldrealtime; @@ -541,7 +541,7 @@ Host_FilterTime (float time) if (host_framerate->value > 0) host_frametime = host_framerate->value; else // don't allow really long or short frames - host_frametime = bound (0.001, host_frametime, 0.1); + host_frametime = bound (0.000, host_frametime, 0.1); return 0; } @@ -696,7 +696,7 @@ _Host_Frame (float time) if (cls.demo_capture) { tex_t *tex = r_funcs->SCR_CaptureBGR (); - WritePNGqfs (va ("%s/qfmv%06d.png", qfs_gamedir->dir.shots, + WritePNGqfs (va (0, "%s/qfmv%06d.png", qfs_gamedir->dir.shots, cls.demo_capture++), tex->data, tex->width, tex->height); free (tex); diff --git a/nq/source/host_cmd.c b/nq/source/host_cmd.c index ce79f1212..76529838e 100644 --- a/nq/source/host_cmd.c +++ b/nq/source/host_cmd.c @@ -239,13 +239,13 @@ nice_time (float time) int t = time + 0.5; if (t < 60) { - return va ("%ds", t); + return va (0, "%ds", t); } else if (t < 3600) { - return va ("%dm%02ds", t / 60, t % 60); + return va (0, "%dm%02ds", t / 60, t % 60); } else if (t < 86400) { - return va ("%dh%02dm%02ds", t / 3600, (t / 60) % 60, t % 60); + return va (0, "%dh%02dm%02ds", t / 3600, (t / 60) % 60, t % 60); } else { - return va ("%dd%02dh%02dm%02ds", + return va (0, "%dd%02dh%02dm%02ds", t / 86400, (t / 3600) % 24, (t / 60) % 60, t % 60); } } @@ -279,7 +279,7 @@ Host_Map_f (void) } // check to make sure the level exists - expanded = va ("maps/%s.bsp", Cmd_Argv (1)); + expanded = va (0, "maps/%s.bsp", Cmd_Argv (1)); f = QFS_FOpenFile (expanded); if (!f) { Sys_Printf ("Can't find %s\n", expanded); @@ -395,7 +395,7 @@ spawn_parms_array (void) const char *parm; for (i = 0; i < NUM_SPAWN_PARMS; i++) { - parm = va ("%.9g", svs.clients->spawn_parms[i]); + parm = va (0, "%.9g", svs.clients->spawn_parms[i]); PL_A_AddObject (parms, PL_NewString (parm)); } return parms; @@ -437,15 +437,15 @@ game_dict (void) plitem_t *game = PL_NewDictionary (); PL_D_AddObject (game, "comment", - PL_NewString (va ("%-21s kills:%3i/%3i", cl.levelname, + PL_NewString (va (0, "%-21s kills:%3i/%3i", cl.levelname, cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]))); PL_D_AddObject (game, "spawn_parms", spawn_parms_array ()); PL_D_AddObject (game, "current_skill", - PL_NewString (va ("%d", current_skill))); + PL_NewString (va (0, "%d", current_skill))); PL_D_AddObject (game, "name", PL_NewString (sv.name)); // sv.time is a double, so it gets 17 digits - PL_D_AddObject (game, "time", PL_NewString (va ("%.17g", sv.time))); + PL_D_AddObject (game, "time", PL_NewString (va (0, "%.17g", sv.time))); PL_D_AddObject (game, "lightstyles", lightstyles_array ()); PL_D_AddObject (game, "globals", ED_GlobalsDict (&sv_pr_state)); PL_D_AddObject (game, "entities", entities_array ()); @@ -478,7 +478,7 @@ convert_to_game_dict (script_t *script) // values Script_GetToken (script, 1); skill = (int) (atof (script->token->str) + 0.1); - PL_D_AddObject (game, "current_skill", PL_NewString (va ("%d", skill))); + PL_D_AddObject (game, "current_skill", PL_NewString (va (0, "%d", skill))); Script_GetToken (script, 1); PL_D_AddObject (game, "name", PL_NewString (script->token->str)); @@ -752,7 +752,7 @@ Host_Name_f (void) if (cmd_source == src_command) { if (strcmp (cl_name->string, newName) == 0) return; - Cvar_Set (cl_name, va ("%.15s", newName)); + Cvar_Set (cl_name, va (0, "%.15s", newName)); if (cls.state >= ca_connected) CL_Cmd_ForwardToServer (); return; diff --git a/nq/source/sbar.c b/nq/source/sbar.c index dd8c9adef..fe7e3264a 100644 --- a/nq/source/sbar.c +++ b/nq/source/sbar.c @@ -1648,8 +1648,8 @@ Sbar_Init (void) Key_KeydestCallback (sbar_keydest_callback); for (i = 0; i < 10; i++) { - sb_nums[0][i] = r_funcs->Draw_PicFromWad (va ("num_%i", i)); - sb_nums[1][i] = r_funcs->Draw_PicFromWad (va ("anum_%i", i)); + sb_nums[0][i] = r_funcs->Draw_PicFromWad (va (0, "num_%i", i)); + sb_nums[1][i] = r_funcs->Draw_PicFromWad (va (0, "anum_%i", i)); } sb_nums[0][10] = r_funcs->Draw_PicFromWad ("num_minus"); @@ -1676,19 +1676,19 @@ Sbar_Init (void) for (i = 0; i < 5; i++) { sb_weapons[2 + i][0] = - r_funcs->Draw_PicFromWad (va ("inva%i_shotgun", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_shotgun", i + 1)); sb_weapons[2 + i][1] = - r_funcs->Draw_PicFromWad (va ("inva%i_sshotgun", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_sshotgun", i + 1)); sb_weapons[2 + i][2] = - r_funcs->Draw_PicFromWad (va ("inva%i_nailgun", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_nailgun", i + 1)); sb_weapons[2 + i][3] = - r_funcs->Draw_PicFromWad (va ("inva%i_snailgun", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_snailgun", i + 1)); sb_weapons[2 + i][4] = - r_funcs->Draw_PicFromWad (va ("inva%i_rlaunch", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_rlaunch", i + 1)); sb_weapons[2 + i][5] = - r_funcs->Draw_PicFromWad (va ("inva%i_srlaunch", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_srlaunch", i + 1)); sb_weapons[2 + i][6] = - r_funcs->Draw_PicFromWad (va ("inva%i_lightng", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_lightng", i + 1)); } sb_ammo[0] = r_funcs->Draw_PicFromWad ("sb_shells"); @@ -1753,15 +1753,15 @@ Sbar_Init (void) for (i = 0; i < 5; i++) { hsb_weapons[2 + i][0] = - r_funcs->Draw_PicFromWad (va ("inva%i_laser", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_laser", i + 1)); hsb_weapons[2 + i][1] = - r_funcs->Draw_PicFromWad (va ("inva%i_mjolnir", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_mjolnir", i + 1)); hsb_weapons[2 + i][2] = - r_funcs->Draw_PicFromWad (va ("inva%i_gren_prox", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_gren_prox", i + 1)); hsb_weapons[2 + i][3] = - r_funcs->Draw_PicFromWad (va ("inva%i_prox_gren", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_prox_gren", i + 1)); hsb_weapons[2 + i][4] = - r_funcs->Draw_PicFromWad (va ("inva%i_prox", i + 1)); + r_funcs->Draw_PicFromWad (va (0, "inva%i_prox", i + 1)); } hsb_items[0] = r_funcs->Draw_PicFromWad ("sb_wsuit"); diff --git a/nq/source/sv_main.c b/nq/source/sv_main.c index 70b3d91f4..60ede5d87 100644 --- a/nq/source/sv_main.c +++ b/nq/source/sv_main.c @@ -1214,7 +1214,7 @@ SV_SpawnServer (const char *server) *sv_globals.serverflags = svs.serverflags; *sv_globals.time = sv.time; - ent_file = QFS_VOpenFile (va ("maps/%s.ent", server), 0, + ent_file = QFS_VOpenFile (va (0, "maps/%s.ent", server), 0, sv.worldmodel->vpath); if ((buf = QFS_LoadFile (ent_file, 0))) { ED_LoadFromFile (&sv_pr_state, (char *) buf); diff --git a/nq/source/sv_pr_cmds.c b/nq/source/sv_pr_cmds.c index d5dcc4bb4..0084b3b99 100644 --- a/nq/source/sv_pr_cmds.c +++ b/nq/source/sv_pr_cmds.c @@ -1280,7 +1280,7 @@ PF_changelevel (progs_t *pr) svs.changelevel_issued = true; s = P_GSTRING (pr, 0); - Cbuf_AddText (host_cbuf, va ("changelevel %s\n", s)); + Cbuf_AddText (host_cbuf, va (0, "changelevel %s\n", s)); } // entity (entity ent) testentitypos diff --git a/qtv/source/client.c b/qtv/source/client.c index 06955b12f..c55e57bd2 100644 --- a/qtv/source/client.c +++ b/qtv/source/client.c @@ -177,9 +177,9 @@ cl_prespawn_f (client_t *cl, void *unused) if (buf >= sv->num_signon_buffers) buf = 0; if (buf == sv->num_signon_buffers - 1) - cmd = va ("cmd spawn %i 0\n", cl->server->spawncount); + cmd = va (0, "cmd spawn %i 0\n", cl->server->spawncount); else - cmd = va ("cmd prespawn %i %i\n", cl->server->spawncount, buf + 1); + cmd = va (0, "cmd prespawn %i %i\n", cl->server->spawncount, buf + 1); size = sv->signon_buffer_size[buf] + 1 + strlen (cmd) + 1; msg = MSG_ReliableCheckBlock (&cl->backbuf, size); SZ_Write (msg, sv->signon_buffers[buf], sv->signon_buffer_size[buf]); @@ -1234,7 +1234,7 @@ Client_New (client_t *cl) MSG_WriteByte (&cl->netchan.message, sv->cdtrack); MSG_WriteByte (&cl->netchan.message, svc_stufftext); MSG_WriteString (&cl->netchan.message, - va ("fullserverinfo \"%s\"\n", + va (0, "fullserverinfo \"%s\"\n", Info_MakeString (sv->info, 0))); } diff --git a/qtv/source/qtv.c b/qtv/source/qtv.c index a227bfc31..513bb069e 100644 --- a/qtv/source/qtv.c +++ b/qtv/source/qtv.c @@ -237,7 +237,7 @@ qtv_quit_f (void) static void qtv_net_init (void) { - qtv_port = Cvar_Get ("qtv_port", va ("%d", PORT_QTV), 0, 0, + qtv_port = Cvar_Get ("qtv_port", va (0, "%d", PORT_QTV), 0, 0, "udp port to use"); sv_timeout = Cvar_Get ("sv_timeout", "60", 0, 0, "server timeout"); NET_Init (qtv_port->int_val); diff --git a/qtv/source/sbar.c b/qtv/source/sbar.c index 092c85ea1..c6e9ead8a 100644 --- a/qtv/source/sbar.c +++ b/qtv/source/sbar.c @@ -52,7 +52,7 @@ draw_clients (view_t *view) const char *s; char *d; - str = va ("[CL: %3d]", client_count); + str = va (0, "[CL: %3d]", client_count); for (s = str, d = sb->text + view->xrel; *s; s++) *d++ = *s; } @@ -66,7 +66,7 @@ draw_servers (view_t *view) const char *s; char *d; - str = va ("[SV: %2d]", server_count); + str = va (0, "[SV: %2d]", server_count); for (s = str, d = sb->text + view->xrel; *s; s++) *d++ = *s; } diff --git a/qtv/source/server.c b/qtv/source/server.c index c376905d2..00778acea 100644 --- a/qtv/source/server.c +++ b/qtv/source/server.c @@ -452,7 +452,8 @@ sv_new_f (void) sv->qport = qport->int_val; sv->info = Info_ParseString ("", MAX_INFO_STRING, 0); Info_SetValueForStarKey (sv->info, "*ver", - va ("%s QTV %s", QW_VERSION, PACKAGE_VERSION), 0); + va (0, "%s QTV %s", QW_VERSION, PACKAGE_VERSION), + 0); Info_SetValueForStarKey (sv->info, "*qsg_version", QW_QSG_VERSION, 0); Info_SetValueForKey (sv->info, "name", "QTV Proxy", 0); Hash_Add (server_hash, sv); @@ -628,7 +629,7 @@ Server_Broadcast (server_t *sv, int reliable, int all, const byte *msg, void Server_BroadcastCommand (server_t *sv, const char *cmd) { - const char *msg = va ("%c%s", svc_stufftext, cmd); + const char *msg = va (0, "%c%s", svc_stufftext, cmd); int len = strlen (msg) + 1; Server_Broadcast (sv, 1, 1, (const byte *) msg, len); } diff --git a/qtv/source/sv_parse.c b/qtv/source/sv_parse.c index 1b6ca5841..493aa613a 100644 --- a/qtv/source/sv_parse.c +++ b/qtv/source/sv_parse.c @@ -118,7 +118,7 @@ sv_serverdata (server_t *sv, qmsg_t *msg) MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); MSG_WriteString (&sv->netchan.message, - va ("soundlist %i %i", sv->spawncount, 0)); + va (0, "soundlist %i %i", sv->spawncount, 0)); sv->next_run = realtime; } @@ -147,11 +147,11 @@ sv_soundlist (server_t *sv, qmsg_t *msg) if (n) { MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); MSG_WriteString (&sv->netchan.message, - va ("soundlist %d %d", sv->spawncount, n)); + va (0, "soundlist %d %d", sv->spawncount, n)); } else { MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); MSG_WriteString (&sv->netchan.message, - va ("modellist %d %d", sv->spawncount, 0)); + va (0, "modellist %d %d", sv->spawncount, 0)); } sv->next_run = realtime; } @@ -183,11 +183,11 @@ sv_modellist (server_t *sv, qmsg_t *msg) if (n) { MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); MSG_WriteString (&sv->netchan.message, - va ("modellist %d %d", sv->spawncount, n)); + va (0, "modellist %d %d", sv->spawncount, n)); } else { MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); MSG_WriteString (&sv->netchan.message, - va ("prespawn %d 0 0", sv->spawncount)); + va (0, "prespawn %d 0 0", sv->spawncount)); sv->signon = 1; } sv->next_run = realtime; @@ -213,7 +213,7 @@ sv_skins_f (server_t *sv) // to get everything ready at the last miniute before we start getting // actual in-game update messages MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); - MSG_WriteString (&sv->netchan.message, va ("begin %d", sv->spawncount)); + MSG_WriteString (&sv->netchan.message, va (0, "begin %d", sv->spawncount)); sv->next_run = realtime; sv->connected = 2; sv->delta = -1; diff --git a/qw/source/cl_chat.c b/qw/source/cl_chat.c index 7a3dcb186..b2099d22d 100644 --- a/qw/source/cl_chat.c +++ b/qw/source/cl_chat.c @@ -233,7 +233,7 @@ CL_ChatInfo (int val) val = 0; if (cls.chat != val) { cls.chat = val; - Cbuf_AddText(cl_cbuf, va ("setinfo chat \"%d\"\n", val)); + Cbuf_AddText(cl_cbuf, va (0, "setinfo chat \"%d\"\n", val)); } } diff --git a/qw/source/cl_cvar.c b/qw/source/cl_cvar.c index ebd569ba8..f9e116ae9 100644 --- a/qw/source/cl_cvar.c +++ b/qw/source/cl_cvar.c @@ -53,7 +53,7 @@ Cvar_Info (cvar_t *var) if (cls.state >= ca_connected && !cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va ("setinfo \"%s\" \"%s\"\n", var->name, + va (0, "setinfo \"%s\" \"%s\"\n", var->name, var->string)); } } diff --git a/qw/source/cl_demo.c b/qw/source/cl_demo.c index 51c709adc..b6e0049e7 100644 --- a/qw/source/cl_demo.c +++ b/qw/source/cl_demo.c @@ -697,7 +697,7 @@ demo_start_recording (int track) // send server info string MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("fullserverinfo \"%s\"\n", + MSG_WriteString (&buf, va (0, "fullserverinfo \"%s\"\n", Info_MakeString (cl.serverinfo, 0))); // flush packet @@ -803,7 +803,7 @@ demo_start_recording (int track) } MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("cmd spawn %i 0\n", cl.servercount)); + MSG_WriteString (&buf, va (0, "cmd spawn %i 0\n", cl.servercount)); if (buf.cursize) { CL_WriteRecordDemoMessage (&buf, seq++); @@ -863,7 +863,7 @@ demo_start_recording (int track) // get the client to check and download skins // when that is completed, a begin command will be issued MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("skins\n")); + MSG_WriteString (&buf, va (0, "skins\n")); CL_WriteRecordDemoMessage (&buf, seq++); diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index e1c305c2b..d9ee07b56 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -321,7 +321,7 @@ CL_CheckForResend (void) connect_time = realtime + t2 - t1; // for retransmit requests - VID_SetCaption (va ("Connecting to %s", cls.servername->str)); + VID_SetCaption (va (0, "Connecting to %s", cls.servername->str)); Sys_Printf ("Connecting to %s...\n", cls.servername->str); Netchan_SendPacket (strlen (getchallenge), (void *) getchallenge, cls.server_addr); @@ -785,7 +785,7 @@ CL_NextDemo (void) } } - Cbuf_InsertText (cl_cbuf, va ("playdemo %s\n", cls.demos[cls.demonum])); + Cbuf_InsertText (cl_cbuf, va (0, "playdemo %s\n", cls.demos[cls.demonum])); cls.demonum++; } @@ -1089,7 +1089,7 @@ CL_Download_f (void) cls.downloadtype = dl_single; MSG_WriteByte (&cls.netchan.message, clc_stringcmd); - SZ_Print (&cls.netchan.message, va ("download %s\n", Cmd_Argv (1))); + SZ_Print (&cls.netchan.message, va (0, "download %s\n", Cmd_Argv (1))); } else { Sys_Printf ("error downloading %s: %s\n", Cmd_Argv (1), strerror (errno)); @@ -1515,7 +1515,7 @@ Host_WriteConfiguration (void) QFile *f; if (host_initialized && cl_writecfg->int_val) { - char *path = va ("%s/config.cfg", qfs_gamedir->dir.def); + char *path = va (0, "%s/config.cfg", qfs_gamedir->dir.def); f = QFS_WOpen (path, 0); if (!f) { @@ -1700,7 +1700,7 @@ Host_Frame (float time) if (cls.demo_capture) { tex_t *tex = r_funcs->SCR_CaptureBGR (); - WritePNGqfs (va ("%s/qfmv%06d.png", qfs_gamedir->dir.shots, + WritePNGqfs (va (0, "%s/qfmv%06d.png", qfs_gamedir->dir.shots, cls.demo_capture++), tex->data, tex->width, tex->height); free (tex); @@ -1782,7 +1782,7 @@ CL_Autoexec (int phase) Cbuf_AddText (cl_cbuf, "exec autoexec.cfg\n"); } - Cbuf_AddText (cl_cbuf, va ("cmd_warncmd %d\n", cmd_warncmd_val)); + Cbuf_AddText (cl_cbuf, va (0, "cmd_warncmd %d\n", cmd_warncmd_val)); } void diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 2446413d6..21c7dabd2 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -265,7 +265,7 @@ CL_CheckOrDownloadFile (const char *filename) MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va ("download \"%s\"", cls.downloadname->str)); + va (0, "download \"%s\"", cls.downloadname->str)); cls.downloadnumber++; @@ -373,12 +373,13 @@ Model_NextDownload (void) aliashdr_t *ahdr = cl.model_precache[i]->aliashdr; if (!ahdr) ahdr = Cache_Get (&cl.model_precache[i]->cache); - Info_SetValueForKey (cls.userinfo, info_key, va ("%d", ahdr->crc), + Info_SetValueForKey (cls.userinfo, info_key, va (0, "%d", + ahdr->crc), 0); if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); - SZ_Print (&cls.netchan.message, va ("setinfo %s %d", info_key, - ahdr->crc)); + SZ_Print (&cls.netchan.message, va (0, "setinfo %s %d", + info_key, ahdr->crc)); } if (!cl.model_precache[i]->aliashdr) Cache_Release (&cl.model_precache[i]->cache); @@ -402,7 +403,7 @@ Model_NextDownload (void) if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (prespawn_name, cl.servercount, + va (0, prespawn_name, cl.servercount, cl.worldmodel->checksum2)); } } @@ -423,7 +424,7 @@ Sound_NextDownload (void) for (; cl.sound_name[cls.downloadnumber][0]; cls.downloadnumber++) { s = cl.sound_name[cls.downloadnumber]; - if (!CL_CheckOrDownloadFile (va ("sound/%s", s))) + if (!CL_CheckOrDownloadFile (va (0, "sound/%s", s))) return; // started a download } @@ -443,7 +444,7 @@ Sound_NextDownload (void) if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (modellist_name, cl.servercount, 0)); + va (0, modellist_name, cl.servercount, 0)); } } @@ -472,7 +473,7 @@ void CL_FinishDownload (void) { Qclose (cls.download); - VID_SetCaption (va ("Connecting to %s", cls.servername->str)); + VID_SetCaption (va (0, "Connecting to %s", cls.servername->str)); // rename the temp file to it's final name if (strcmp (cls.downloadtempname->str, cls.downloadname->str)) { @@ -662,8 +663,8 @@ CL_ParseDownload (void) if (percent != 100) { // request next block if (percent != cls.downloadpercent) - VID_SetCaption (va ("Downloading %s %d%%", cls.downloadname->str, - percent)); + VID_SetCaption (va (0, "Downloading %s %d%%", + cls.downloadname->str, percent)); cls.downloadpercent = percent; MSG_WriteByte (&cls.netchan.message, clc_stringcmd); @@ -842,7 +843,7 @@ CL_ParseServerData (void) if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (soundlist_name, cl.servercount, 0)); + va (0, soundlist_name, cl.servercount, 0)); } // now waiting for downloads, etc @@ -878,7 +879,7 @@ CL_ParseSoundlist (void) if (n && !cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (soundlist_name, cl.servercount, n)); + va (0, soundlist_name, cl.servercount, n)); return; } @@ -929,7 +930,7 @@ CL_ParseModellist (void) if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va (modellist_name, cl.servercount, n)); + va (0, modellist_name, cl.servercount, n)); } return; } @@ -1095,7 +1096,8 @@ CL_ProcessUserInfo (int slot, player_info_t *player) while (!(player->name = Info_Key (player->userinfo, "name"))) { if (player->userid) Info_SetValueForKey (player->userinfo, "name", - va ("user-%i [exploit]", player->userid), 1); + va (0, "user-%i [exploit]", + player->userid), 1); else Info_SetValueForKey (player->userinfo, "name", "", 1); } @@ -1248,7 +1250,8 @@ CL_SetStat (int stat, int value) break; case STAT_HEALTH: if (cl_player_health_e->func) - GIB_Event_Callback (cl_player_health_e, 1, va ("%i", value)); + GIB_Event_Callback (cl_player_health_e, 1, + va (0, "%i", value)); if (value <= 0) Team_Dead (); break; @@ -1331,7 +1334,7 @@ CL_ParseServerMessage (void) break; // end of message } - SHOWNET (va ("%s(%d)", svc_strings[cmd], cmd)); + SHOWNET (va (0, "%s(%d)", svc_strings[cmd], cmd)); // other commands switch (cmd) { diff --git a/qw/source/cl_skin.c b/qw/source/cl_skin.c index 21a9afea7..491d12652 100644 --- a/qw/source/cl_skin.c +++ b/qw/source/cl_skin.c @@ -78,7 +78,8 @@ Skin_NextDownload (void) //XXX Skin_Find (sc); if (noskins->int_val) //XXX FIXME continue; - //XXX if (!CL_CheckOrDownloadFile (va ("skins/%s.pcx", sc->skin->name))) + //XXX if (!CL_CheckOrDownloadFile (va (0, "skins/%s.pcx", + // sc->skin->name))) //XXX return; // started a download } @@ -99,7 +100,7 @@ Skin_NextDownload (void) // get next signon phase MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, - va ("begin %i", cl.servercount)); + va (0, "begin %i", cl.servercount)); Cache_Report (); // print remaining memory } CL_SetState (ca_active); diff --git a/qw/source/cl_slist.c b/qw/source/cl_slist.c index 4b5ea16b8..ded6445c8 100644 --- a/qw/source/cl_slist.c +++ b/qw/source/cl_slist.c @@ -575,7 +575,7 @@ MSL_ParseServerList (const char *msl_data) unsigned int msl_ptr; for (msl_ptr = 0; msl_ptr < strlen (msl_data); msl_ptr = msl_ptr + 6) { - slist = SL_Add (slist, va ("%i.%i.%i.%i:%i", + slist = SL_Add (slist, va (0, "%i.%i.%i.%i:%i", (byte) msl_data[msl_ptr], (byte) msl_data[msl_ptr+1], (byte) msl_data[msl_ptr+2], diff --git a/qw/source/crudefile.c b/qw/source/crudefile.c index 3050a6efc..a02bc81bc 100644 --- a/qw/source/crudefile.c +++ b/qw/source/crudefile.c @@ -150,7 +150,7 @@ CF_BuildQuota (void) cf_cursize = 0; while ((i = readdir (dir))) { - cf_cursize += CF_GetFileSize (va ("%s/%s", path->str, i->d_name)); + cf_cursize += CF_GetFileSize (va (0, "%s/%s", path->str, i->d_name)); } closedir (dir); } diff --git a/qw/source/locs.c b/qw/source/locs.c index c30080dd7..ab92ec4c2 100644 --- a/qw/source/locs.c +++ b/qw/source/locs.c @@ -136,7 +136,7 @@ locs_load (const char *filename) vec3_t loc; QFile *file; - tmp = va ("maps/%s", filename); + tmp = va (0, "maps/%s", filename); file = QFS_FOpenFile (tmp); if (!file) { Sys_Printf ("Couldn't load %s\n", tmp); @@ -196,7 +196,7 @@ locs_save (const char *filename, qboolean gz) if (gz) { if (strcmp (QFS_FileExtension (filename), ".gz") != 0) - filename = va ("%s.gz", filename); + filename = va (0, "%s.gz", filename); locfd = QFS_Open (filename, "z9w+"); } else locfd = QFS_Open (filename, "w+"); diff --git a/qw/source/sbar.c b/qw/source/sbar.c index 3a6e97778..a7b3ab415 100644 --- a/qw/source/sbar.c +++ b/qw/source/sbar.c @@ -1605,7 +1605,7 @@ draw_net (view_t *view) int ping = cl.players[cl.playernum].ping; ping = bound (0, ping, 999); - draw_string (view, 0, 0, va ("%3d ms ", ping)); + draw_string (view, 0, 0, va (0, "%3d ms ", ping)); } if (hud_ping->int_val && hud_pl->int_val) @@ -1615,7 +1615,7 @@ draw_net (view_t *view) int lost = CL_CalcNet (); lost = bound (0, lost, 999); - draw_string (view, 56, 0, va ("%3d pl", lost)); + draw_string (view, 56, 0, va (0, "%3d pl", lost)); } } @@ -1950,8 +1950,8 @@ Sbar_Init (void) Key_KeydestCallback (sbar_keydest_callback); for (i = 0; i < 10; i++) { - sb_nums[0][i] = r_funcs->Draw_PicFromWad (va ("num_%i", i)); - sb_nums[1][i] = r_funcs->Draw_PicFromWad (va ("anum_%i", i)); + sb_nums[0][i] = r_funcs->Draw_PicFromWad (va (0, "num_%i", i)); + sb_nums[1][i] = r_funcs->Draw_PicFromWad (va (0, "anum_%i", i)); } sb_nums[0][10] = r_funcs->Draw_PicFromWad ("num_minus"); @@ -1977,19 +1977,26 @@ Sbar_Init (void) sb_weapons[1][6] = r_funcs->Draw_PicFromWad ("inv2_lightng"); for (i = 0; i < 5; i++) { - sb_weapons[2 + i][0] = r_funcs->Draw_PicFromWad (va ("inva%i_shotgun", + sb_weapons[2 + i][0] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_shotgun", i + 1)); - sb_weapons[2 + i][1] = r_funcs->Draw_PicFromWad (va ("inva%i_sshotgun", + sb_weapons[2 + i][1] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_sshotgun", i + 1)); - sb_weapons[2 + i][2] = r_funcs->Draw_PicFromWad (va ("inva%i_nailgun", + sb_weapons[2 + i][2] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_nailgun", i + 1)); - sb_weapons[2 + i][3] = r_funcs->Draw_PicFromWad (va ("inva%i_snailgun", + sb_weapons[2 + i][3] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_snailgun", i + 1)); - sb_weapons[2 + i][4] = r_funcs->Draw_PicFromWad (va ("inva%i_rlaunch", + sb_weapons[2 + i][4] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_rlaunch", i + 1)); - sb_weapons[2 + i][5] = r_funcs->Draw_PicFromWad (va ("inva%i_srlaunch", + sb_weapons[2 + i][5] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_srlaunch", i + 1)); - sb_weapons[2 + i][6] = r_funcs->Draw_PicFromWad (va ("inva%i_lightng", + sb_weapons[2 + i][6] = r_funcs->Draw_PicFromWad (va (0, + "inva%i_lightng", i + 1)); } diff --git a/qw/source/sv_ccmds.c b/qw/source/sv_ccmds.c index aef14bea6..22604df69 100644 --- a/qw/source/sv_ccmds.c +++ b/qw/source/sv_ccmds.c @@ -250,7 +250,7 @@ SV_Fraglogfile_f (void) } name = dstring_new (); if (!QFS_NextFilename (name, - va ("%s/frag_", qfs_gamedir->dir.def), ".log")) { + va (0, "%s/frag_", qfs_gamedir->dir.def), ".log")) { SV_Printf ("Can't open any logfiles.\n"); sv_fraglogfile = NULL; } else { @@ -396,29 +396,29 @@ nice_time (float time) #if 0 //FIXME ditch or cvar? if (t < 60) { - return va ("%ds", t); + return va (0, "%ds", t); } else if (t < 600) { - return va ("%dm%02ds", t / 60, t % 60); + return va (0, "%dm%02ds", t / 60, t % 60); } else if (t < 3600) { - return va ("%dm", t / 60); + return va (0, "%dm", t / 60); } else if (t < 36000) { t /= 60; - return va ("%dh%02dm", t / 60, t % 60); + return va (0, "%dh%02dm", t / 60, t % 60); } else if (t < 86400) { - return va ("%dh", t / 3600); + return va (0, "%dh", t / 3600); } else { t /= 3600; - return va ("%dd%02dh", t / 24, t % 24); + return va (0, "%dd%02dh", t / 24, t % 24); } #endif if (t < 60) { - return va ("%ds", t); + return va (0, "%ds", t); } else if (t < 3600) { - return va ("%dm%02ds", t / 60, t % 60); + return va (0, "%dm%02ds", t / 60, t % 60); } else if (t < 86400) { - return va ("%dh%02dm%02ds", t / 3600, (t / 60) % 60, t % 60); + return va (0, "%dh%02dm%02ds", t / 3600, (t / 60) % 60, t % 60); } else { - return va ("%dd%02dh%02dm%02ds", + return va (0, "%dd%02dh%02dm%02ds", t / 86400, (t / 3600) % 24, (t / 60) % 60, t % 60); } } @@ -742,15 +742,15 @@ SV_Ban_f (void) if (argc > argr) { reason = Cmd_Args (argr); SV_BroadcastPrintf (PRINT_HIGH, "Admin Banned user %s %s: %s\n", - cl->name, mins ? va ("for %.1f minutes", mins) + cl->name, mins ? va (0, "for %.1f minutes", mins) : "permanently", reason); } else { SV_BroadcastPrintf (PRINT_HIGH, "Admin Banned user %s %s\n", - cl->name, mins ? va ("for %.1f minutes", mins) + cl->name, mins ? va (0, "for %.1f minutes", mins) : "permanently"); } SV_DropClient (cl); - Cmd_ExecuteString (va ("addip %s %f", + Cmd_ExecuteString (va (0, "addip %s %f", NET_BaseAdrToString (cl->netchan.remote_address), mins), src_command); } @@ -812,7 +812,7 @@ SV_ConSay (const char *prefix, client_t *client) dbuf = SVR_WriteBegin (dem_all, 0, strlen (text->str) + 7); MSG_WriteByte (dbuf, svc_print); MSG_WriteByte (dbuf, PRINT_HIGH); - MSG_WriteString (dbuf, va ("%s\n", text->str)); + MSG_WriteString (dbuf, va (0, "%s\n", text->str)); MSG_WriteByte (dbuf, svc_print); MSG_WriteByte (dbuf, PRINT_CHAT); MSG_WriteString (dbuf, ""); @@ -1136,7 +1136,7 @@ SV_Snap (int uid) cl->uploadfn = dstring_new (); if (!QFS_NextFilename (cl->uploadfn, - va ("%s/snap/%d-", qfs_gamedir->dir.def, uid), + va (0, "%s/snap/%d-", qfs_gamedir->dir.def, uid), ".pcx")) { SV_Printf ("Snap: Couldn't create a file, clean some out.\n"); dstring_delete (cl->uploadfn); diff --git a/qw/source/sv_demo.c b/qw/source/sv_demo.c index cc53372a8..b13135c93 100644 --- a/qw/source/sv_demo.c +++ b/qw/source/sv_demo.c @@ -191,7 +191,7 @@ SV_Stop (int reason) sv_redirected = RD_NONE; // onrecord script is called always // from the console - Cmd_TokenizeString (va ("script %s \"%s\" \"%s\" \"%s\" %s", + Cmd_TokenizeString (va (0, "script %s \"%s\" \"%s\" \"%s\" %s", sv_onrecordfinish->string, demo.path->str, serverdemo->string, path, p != NULL ? p + 1 : "")); @@ -454,7 +454,7 @@ SV_Record (char *name) // send server info string MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("fullserverinfo \"%s\"\n", + MSG_WriteString (&buf, va (0, "fullserverinfo \"%s\"\n", Info_MakeString (svs.info, 0))); // flush packet @@ -524,7 +524,7 @@ SV_Record (char *name) } MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("cmd spawn %i 0\n", svs.spawncount)); + MSG_WriteString (&buf, va (0, "cmd spawn %i 0\n", svs.spawncount)); if (buf.cursize) { SV_WriteRecordDemoMessage (&buf); @@ -576,7 +576,7 @@ SV_Record (char *name) // get the client to check and download skins // when that is completed, a begin command will be issued MSG_WriteByte (&buf, svc_stufftext); - MSG_WriteString (&buf, va ("skins\n")); + MSG_WriteString (&buf, va (0, "skins\n")); SV_WriteRecordDemoMessage (&buf); @@ -797,7 +797,7 @@ Demo_Init (void) sv_demoPings = Cvar_Get ("sv_demoPings", "3", CVAR_NONE, 0, "FIXME"); sv_demoNoVis = Cvar_Get ("sv_demoNoVis", "1", CVAR_NONE, 0, "FIXME"); sv_demoUseCache = Cvar_Get ("sv_demoUseCache", "0", CVAR_NONE, 0, "FIXME"); - sv_demoCacheSize = Cvar_Get ("sv_demoCacheSize", va ("%d", size / 1024), + sv_demoCacheSize = Cvar_Get ("sv_demoCacheSize", va (0, "%d", size / 1024), CVAR_ROM, 0, "FIXME"); sv_demoMaxSize = Cvar_Get ("sv_demoMaxSize", "20480", CVAR_NONE, 0, "FIXME"); diff --git a/qw/source/sv_init.c b/qw/source/sv_init.c index d5b6d0d2c..6e8b7bae5 100644 --- a/qw/source/sv_init.c +++ b/qw/source/sv_init.c @@ -374,7 +374,7 @@ SV_SpawnServer (const char *server) SV_LoadProgs (); SV_FreeAllEdictLeafs (); SV_SetupUserCommands (); - Info_SetValueForStarKey (svs.info, "*progs", va ("%i", sv_pr_state.crc), + Info_SetValueForStarKey (svs.info, "*progs", va (0, "%i", sv_pr_state.crc), !sv_highchars->int_val); // leave slots at start for only clients @@ -437,7 +437,7 @@ SV_SpawnServer (const char *server) // load and spawn all other entities *sv_globals.time = sv.time; - ent_file = QFS_VOpenFile (va ("maps/%s.ent", server), 0, + ent_file = QFS_VOpenFile (va (0, "maps/%s.ent", server), 0, sv.worldmodel->vpath); if ((buf = QFS_LoadFile (ent_file, 0))) { ED_LoadFromFile (&sv_pr_state, (char *) buf); diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index ffc1a5db4..0156d689a 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -368,7 +368,7 @@ SV_DropClient (client_t *drop) // Trigger GIB event if (sv_client_disconnect_e->func) GIB_Event_Callback (sv_client_disconnect_e, 1, - va ("%u", drop->userid)); + va (0, "%u", drop->userid)); } int @@ -1459,7 +1459,7 @@ SV_AddIP_f (void) bantime / 60); else strncpy (timestr, "permanently", sizeof (timestr)); - text = va ("You are %s %s\n%s", + text = va (0, "You are %s %s\n%s", typestr, timestr, type == ft_ban ? "" : "\nReconnecting won't help..."); MSG_ReliableWrite_Begin (&cl->backbuf, svc_centerprint, @@ -1884,7 +1884,7 @@ SV_CheckVars (void) Info_SetValueForKey (svs.info, "needpass", "", !sv_highchars->int_val); else - Info_SetValueForKey (svs.info, "needpass", va ("%i", v), + Info_SetValueForKey (svs.info, "needpass", va (0, "%i", v), !sv_highchars->int_val); } diff --git a/qw/source/sv_pr_cmds.c b/qw/source/sv_pr_cmds.c index 49f0cc332..7298dc74a 100644 --- a/qw/source/sv_pr_cmds.c +++ b/qw/source/sv_pr_cmds.c @@ -1411,7 +1411,7 @@ PF_changelevel (progs_t *pr) last_spawncount = svs.spawncount; s = P_GSTRING (pr, 0); - Cbuf_AddText (sv_cbuf, va ("map %s\n", s)); + Cbuf_AddText (sv_cbuf, va (0, "map %s\n", s)); } /* @@ -1460,13 +1460,13 @@ PF_logfrag (progs_t *pr) snprintf(buf, sizeof(buf), "%d", u2); - GIB_Event_Callback (sv_frag_e, 4, type1, va ("%d", u1), type2, buf); + GIB_Event_Callback (sv_frag_e, 4, type1, va (0, "%d", u1), type2, buf); } if (e1 < 1 || e1 > MAX_CLIENTS || e2 < 1 || e2 > MAX_CLIENTS) return; - s = va ("\\%s\\%s\\\n", svs.clients[e1 - 1].name, + s = va (0, "\\%s\\%s\\\n", svs.clients[e1 - 1].name, svs.clients[e2 - 1].name); SZ_Print (&svs.log[svs.logsequence & 1], s); @@ -1511,7 +1511,7 @@ PF_infokey (progs_t *pr) else if (!strcmp (key, "ping")) { int ping = SV_CalcPing (&svs.clients[e1 - 1]); - value = va ("%d", ping); + value = va (0, "%d", ping); } else value = Info_ValueForKey (svs.clients[e1 - 1].userinfo, key); } else @@ -1862,7 +1862,7 @@ PF_SV_FreeClient (progs_t *pr) cl->state = cs_free; //if (sv_client_disconnect_e->func) - // GIB_Event_Callback (sv_client_disconnect_e, 2, va ("%u", cl->userid), + // GIB_Event_Callback (sv_client_disconnect_e, 2, va (0, "%u", cl->userid), // "server"); } diff --git a/qw/source/sv_pr_qwe.c b/qw/source/sv_pr_qwe.c index 010c8a5a6..ea4d533f4 100644 --- a/qw/source/sv_pr_qwe.c +++ b/qw/source/sv_pr_qwe.c @@ -451,7 +451,7 @@ PF_log (progs_t *pr) char *text; QFile *file; - name = va ("%s/%s.log", qfs_gamedir->dir.def, P_GSTRING (pr, 0)); + name = va (0, "%s/%s.log", qfs_gamedir->dir.def, P_GSTRING (pr, 0)); file = QFS_Open (name, "a"); text = PF_VarString (pr, 2); diff --git a/qw/source/sv_qtv.c b/qw/source/sv_qtv.c index 6804a51e3..366c2d687 100644 --- a/qw/source/sv_qtv.c +++ b/qw/source/sv_qtv.c @@ -194,9 +194,9 @@ qtv_prespawn_f (sv_qtv_t *proxy) buf = 0; if (buf == sv.num_signon_buffers - 1) - command = va ("cmd spawn %i 0\n", svs.spawncount); + command = va (0, "cmd spawn %i 0\n", svs.spawncount); else - command = va ("cmd prespawn %i %i\n", svs.spawncount, buf + 1); + command = va (0, "cmd prespawn %i %i\n", svs.spawncount, buf + 1); size = (3 + sv.signon_buffer_size[buf]) + (1 + strlen (command) + 1); msg = MSG_ReliableCheckBlock (&proxy->backbuf, size); @@ -534,7 +534,7 @@ SV_qtvChanging (void) int i, len; const char *msg; - msg = va ("%cchanging", qtv_stringcmd); + msg = va (0, "%cchanging", qtv_stringcmd); len = strlen (msg) + 1; for (i = 0; i < MAX_PROXIES; i++) { proxy = proxies + i; @@ -555,7 +555,7 @@ SV_qtvReconnect (void) int i, len; const char *msg; - msg = va ("%creconnect", qtv_stringcmd); + msg = va (0, "%creconnect", qtv_stringcmd); len = strlen (msg) + 1; for (i = 0; i < MAX_PROXIES; i++) { proxy = proxies + i; diff --git a/qw/source/sv_sbar.c b/qw/source/sv_sbar.c index 012a38835..12aa9115a 100644 --- a/qw/source/sv_sbar.c +++ b/qw/source/sv_sbar.c @@ -55,7 +55,7 @@ draw_cpu (view_t *view) cpu = (svs.stats.latched_active + svs.stats.latched_idle); cpu = 100 * svs.stats.latched_active / cpu; - cpu_str = va ("[CPU: %3d%%]", (int) cpu); + cpu_str = va (0, "[CPU: %3d%%]", (int) cpu); for (s = cpu_str, d = sb->text + view->xrel; *s; s++) *d++ = *s; if (cpu > 70.0) { @@ -74,7 +74,7 @@ draw_rec (view_t *view) const char *s; char *d; - str = va ("[REC: %d]", SVR_NumRecorders ()); + str = va (0, "[REC: %d]", SVR_NumRecorders ()); for (s = str, d = sb->text + view->xrel; *s; s++) *d++ = *s; } diff --git a/qw/source/sv_user.c b/qw/source/sv_user.c index f9c44f48f..3fba2c17f 100644 --- a/qw/source/sv_user.c +++ b/qw/source/sv_user.c @@ -141,7 +141,7 @@ SV_WriteWorldVars (netchan_t *netchan) // send server info string MSG_WriteByte (&netchan->message, svc_stufftext); MSG_WriteString (&netchan->message, - va ("fullserverinfo \"%s\"\n", + va (0, "fullserverinfo \"%s\"\n", Info_MakeString (svs.info, 0))); } @@ -194,7 +194,7 @@ SV_New_f (void *unused) // Trigger GIB connection event if (sv_client_connect_e->func) GIB_Event_Callback (sv_client_connect_e, 1, - va ("%u", host_client->userid)); + va (0, "%u", host_client->userid)); } void @@ -351,9 +351,9 @@ SV_PreSpawn_f (void *unused) host_client->prespawned = true; if (buf == sv.num_signon_buffers - 1) - command = va ("cmd spawn %i 0\n", svs.spawncount); + command = va (0, "cmd spawn %i 0\n", svs.spawncount); else - command = va ("cmd prespawn %i %i\n", svs.spawncount, buf + 1); + command = va (0, "cmd prespawn %i %i\n", svs.spawncount, buf + 1); size = sv.signon_buffer_size[buf] + 1 + strlen (command) + 1; @@ -605,7 +605,7 @@ SV_Begin_f (void *unused) // Trigger GIB events if (sv_client_spawn_e->func) - GIB_Event_Callback (sv_client_spawn_e, 1, va ("%u", + GIB_Event_Callback (sv_client_spawn_e, 1, va (0, "%u", host_client->userid)); } @@ -787,7 +787,7 @@ SV_BeginDownload_f (void *unused) MSG_ReliableWrite_Short (&host_client->backbuf, DL_HTTP); MSG_ReliableWrite_Byte (&host_client->backbuf, 0); MSG_ReliableWrite_String (&host_client->backbuf, - va ("%s/%s", sv_http_url_base->string, + va (0, "%s/%s", sv_http_url_base->string, ren ? qfs_foundfile.realname : name)); MSG_ReliableWrite_String (&host_client->backbuf, ren ? qfs_foundfile.realname : ""); @@ -914,7 +914,7 @@ SV_Say (qboolean team) dsprintf (text, fmt, host_client->name); if (sv_chat_e->func) - GIB_Event_Callback (sv_chat_e, 2, va ("%i", host_client->userid), p, + GIB_Event_Callback (sv_chat_e, 2, va (0, "%i", host_client->userid), p, type); dstring_appendstr (text, p); @@ -1201,7 +1201,7 @@ SV_SetUserinfo (client_t *client, const char *key, const char *value) // trigger a GIB event if (sv_setinfo_e->func) - GIB_Event_Callback (sv_setinfo_e, 4, va("%d", client->userid), + GIB_Event_Callback (sv_setinfo_e, 4, va (0, "%d", client->userid), key, oldvalue, value); if (sv_funcs.UserInfoChanged) { diff --git a/qw/source/teamplay.c b/qw/source/teamplay.c index c5df33cd3..b8158cbdb 100644 --- a/qw/source/teamplay.c +++ b/qw/source/teamplay.c @@ -424,7 +424,7 @@ Locs_Init (void) static const char * Team_F_Version (char *args) { - return va ("say %s", PACKAGE_STRING); + return va (0, "say %s", PACKAGE_STRING); } static const char * @@ -446,7 +446,7 @@ Team_F_Skins (char *args) if (l == 0) { //XXXtotalfb = Skin_FbPercent (0); totalfb = 0; - return va ("say Player models have %f%% brightness\n" + return va (0, "say Player models have %f%% brightness\n" "say Average percent fullbright for all loaded skins is " "%d.%d%%", allfb * 100, totalfb / 10, totalfb % 10); } @@ -455,8 +455,8 @@ Team_F_Skins (char *args) totalfb = 0; if (totalfb >= 0) - return va ("say \"Skin %s is %d.%d%% fullbright\"", args, totalfb / 10, - totalfb % 10); + return va (0, "say \"Skin %s is %d.%d%% fullbright\"", + args, totalfb / 10, totalfb % 10); else return ("say \"Skin not currently loaded.\""); } diff --git a/ruamoko/qwaq/builtins/main.c b/ruamoko/qwaq/builtins/main.c index f493e8528..dbafed33f 100644 --- a/ruamoko/qwaq/builtins/main.c +++ b/ruamoko/qwaq/builtins/main.c @@ -102,7 +102,7 @@ load_file (progs_t *pr, const char *name, off_t *_size) file = open_file (name, &size); if (!file) { - file = open_file (va ("%s.gz", name), &size); + file = open_file (va (0, "%s.gz", name), &size); if (!file) { return 0; } diff --git a/ruamoko/qwaq/builtins/qwaq.c b/ruamoko/qwaq/builtins/qwaq.c index 0a8070825..f74b429cf 100644 --- a/ruamoko/qwaq/builtins/qwaq.c +++ b/ruamoko/qwaq/builtins/qwaq.c @@ -79,7 +79,7 @@ load_file (progs_t *pr, const char *name, off_t *_size) file = open_file (name, &size); if (!file) { - file = open_file (va ("%s.gz", name), &size); + file = open_file (va (0, "%s.gz", name), &size); if (!file) { return 0; } diff --git a/tools/qfbsp/source/brush.c b/tools/qfbsp/source/brush.c index 97ddbfd4d..e0b05f2d9 100644 --- a/tools/qfbsp/source/brush.c +++ b/tools/qfbsp/source/brush.c @@ -347,7 +347,7 @@ CreateBrushFaces (void) GetVectorForKey (FoundEntity, "origin", offset); SetKeyValue (CurrentEntity, "origin", - va ("%g %g %g", VectorExpand (offset))); + va (0, "%g %g %g", VectorExpand (offset))); } for (i = 0; i < numbrushfaces; i++) { diff --git a/tools/qfbsp/source/map.c b/tools/qfbsp/source/map.c index d8bb6c893..870fb7c07 100644 --- a/tools/qfbsp/source/map.c +++ b/tools/qfbsp/source/map.c @@ -620,7 +620,7 @@ WriteEntitiesToString (void) dstring_appendstr (buf, "{\n"); for (ep = entities[i].epairs; ep; ep = ep->next) { - dstring_appendstr (buf, va ("\"%s\" \"%s\"\n", + dstring_appendstr (buf, va (0, "\"%s\" \"%s\"\n", ep->key, ep->value)); } dstring_appendstr (buf, "}\n"); diff --git a/tools/qfbsp/source/readbsp.c b/tools/qfbsp/source/readbsp.c index caf69255b..c554755c5 100644 --- a/tools/qfbsp/source/readbsp.c +++ b/tools/qfbsp/source/readbsp.c @@ -359,13 +359,13 @@ unique_name (wad_t *wad, const char *name) do { strncpy (uname, name, MIPTEXNAME); uname[(MIPTEXNAME - 1)] = 0; - tag = va ("~%x", i++); + tag = va (0, "~%x", i++); if (strlen (uname) + strlen (tag) <= (MIPTEXNAME - 1)) strcat (uname, tag); else strcpy (uname + (MIPTEXNAME - 1) - strlen (tag), tag); } while (wad_find_lump (wad, uname)); - return va ("%s", uname); // just to make a safe returnable that doesn't + return va (0, "%s", uname); // just to make a safe returnable that doesn't // need to be freed } diff --git a/tools/qfbsp/source/writebsp.c b/tools/qfbsp/source/writebsp.c index 94f679313..dd7d0fa99 100644 --- a/tools/qfbsp/source/writebsp.c +++ b/tools/qfbsp/source/writebsp.c @@ -301,7 +301,7 @@ TEX_InitFromWad (const char *path) wad = wad_open (path); #ifdef HAVE_ZLIB if (!wad) - wad = wad_open (path = va ("%s.gz", path)); + wad = wad_open (path = va (0, "%s.gz", path)); #endif if (!wad) return -1; diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 9203e9fbf..ddef199fa 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -258,7 +258,8 @@ emit_static_instances (const char *classname) } instances_struct[1].type = array_type (&type_pointer, data.num_instances + 1); - instances_def = emit_structure (va ("_OBJ_STATIC_INSTANCES_%s", classname), + instances_def = emit_structure (va (0, "_OBJ_STATIC_INSTANCES_%s", + classname), 's', instances_struct, 0, &data, 0, sc_static); free (data.instances); @@ -538,16 +539,16 @@ get_class_name (class_type_t *class_type, int pretty) if (pretty) return class_type->c.class->name; else - return va ("%s_", class_type->c.class->name); + return va (0, "%s_", class_type->c.class->name); case ct_category: if (pretty) - return va ("%s (%s)", class_type->c.category->class->name, + return va (0, "%s (%s)", class_type->c.category->class->name, class_type->c.category->name); else - return va ("%s_%s", class_type->c.category->class->name, + return va (0, "%s_%s", class_type->c.category->class->name, class_type->c.category->name); case ct_protocol: - return va ("<%s>", class_type->c.protocol->name); + return va (0, "<%s>", class_type->c.protocol->name); } return "???"; } @@ -561,13 +562,13 @@ class_symbol (class_type_t *class_type, int external) switch (class_type->type) { case ct_category: - name = va ("_OBJ_CATEGORY_%s_%s", + name = va (0, "_OBJ_CATEGORY_%s_%s", class_type->c.category->class->name, class_type->c.category->name); type = &type_category; break; case ct_class: - name = va ("_OBJ_CLASS_%s", class_type->c.class->name); + name = va (0, "_OBJ_CLASS_%s", class_type->c.class->name); type = &type_class; break; case ct_protocol: @@ -710,7 +711,8 @@ begin_category (category_t *category) EMIT_STRING (space, pr_category->class_name, class->name); EMIT_DEF (space, pr_category->protocols, emit_protocol_list (category->protocols, - va ("%s_%s", class->name, category->name))); + va (0, "%s_%s", class->name, + category->name))); } typedef struct { @@ -786,7 +788,7 @@ emit_ivars (symtab_t *ivars, const char *name) } ivar_list_struct[1].type = array_type (&type_ivar, ivar_data.count); - def = emit_structure (va ("_OBJ_INSTANCE_VARIABLES_%s", name), 's', + def = emit_structure (va (0, "_OBJ_INSTANCE_VARIABLES_%s", name), 's', ivar_list_struct, 0, &ivar_data, 0, sc_static); dstring_delete (ivar_data.encoding); @@ -803,7 +805,7 @@ begin_class (class_t *class) def_t *def; defspace_t *space; - sym = make_symbol (va ("_OBJ_METACLASS_%s", class->name), + sym = make_symbol (va (0, "_OBJ_METACLASS_%s", class->name), &type_class, pr.far_data, sc_static); meta_def = sym->s.def; meta_def->initialized = meta_def->constant = meta_def->nosave = 1; @@ -872,15 +874,15 @@ emit_class_ref (const char *class_name) def_t *ref_def; def_t *name_def; - ref_sym = make_symbol (va (".obj_class_ref_%s", class_name), &type_pointer, - pr.far_data, sc_static); + ref_sym = make_symbol (va (0, ".obj_class_ref_%s", class_name), + &type_pointer, pr.far_data, sc_static); if (!ref_sym->table) symtab_addsymbol (pr.symtab, ref_sym); ref_def = ref_sym->s.def; if (ref_def->initialized) return; ref_def->initialized = ref_def->constant = ref_def->nosave = 1; - name_sym = make_symbol (va (".obj_class_name_%s", class_name), + name_sym = make_symbol (va (0, ".obj_class_name_%s", class_name), &type_pointer, pr.far_data, sc_extern); if (!name_sym->table) symtab_addsymbol (pr.symtab, name_sym); @@ -896,7 +898,7 @@ emit_class_name (const char *class_name) symbol_t *name_sym; def_t *name_def; - name_sym = make_symbol (va (".obj_class_name_%s", class_name), + name_sym = make_symbol (va (0, ".obj_class_name_%s", class_name), &type_pointer, pr.far_data, sc_global); if (!name_sym->table) symtab_addsymbol (pr.symtab, name_sym); @@ -916,9 +918,9 @@ emit_category_ref (const char *class_name, const char *category_name) def_t *ref_def; def_t *name_def; - ref_sym = make_symbol (va (".obj_category_ref_%s_%s", - class_name, category_name), - &type_pointer, pr.far_data, sc_static); + ref_sym = make_symbol (va (0, ".obj_category_ref_%s_%s", + class_name, category_name), + &type_pointer, pr.far_data, sc_static); if (!ref_sym->table) symtab_addsymbol (pr.symtab, ref_sym); ref_def = ref_sym->s.def; @@ -926,9 +928,9 @@ emit_category_ref (const char *class_name, const char *category_name) return; ref_def->initialized = ref_def->constant = 1; ref_def->nosave = 1; - name_sym = make_symbol (va (".obj_category_name_%s_%s", - class_name, category_name), - &type_pointer, pr.far_data, sc_extern); + name_sym = make_symbol (va (0, ".obj_category_name_%s_%s", + class_name, category_name), + &type_pointer, pr.far_data, sc_extern); if (!name_sym->table) symtab_addsymbol (pr.symtab, name_sym); name_def = name_sym->s.def; @@ -943,7 +945,7 @@ emit_category_name (const char *class_name, const char *category_name) symbol_t *name_sym; def_t *name_def; - name_sym = make_symbol (va (".obj_category_name_%s_%s", + name_sym = make_symbol (va (0, ".obj_category_name_%s_%s", class_name, category_name), &type_pointer, pr.far_data, sc_global); if (!name_sym->table) @@ -1374,9 +1376,8 @@ class_pointer_symbol (class_t *class) class_type.c.class = class; - sym = make_symbol (va ("_OBJ_CLASS_POINTER_%s", class->name), - &type_Class, - pr.near_data, sc_static); + sym = make_symbol (va (0, "_OBJ_CLASS_POINTER_%s", class->name), + &type_Class, pr.near_data, sc_static); if (!sym->table) symtab_addsymbol (pr.symtab, sym); def = sym->s.def; @@ -1716,7 +1717,7 @@ emit_protocol (protocol_t *protocol) pr_protocol_t *proto; defspace_t *space; - proto_def = make_symbol (va ("_OBJ_PROTOCOL_%s", protocol->name), + proto_def = make_symbol (va (0, "_OBJ_PROTOCOL_%s", protocol->name), &type_protocol, pr.far_data, sc_static)->s.def; if (proto_def->initialized) return proto_def; @@ -1728,7 +1729,7 @@ emit_protocol (protocol_t *protocol) EMIT_STRING (space, proto->protocol_name, protocol->name); EMIT_DEF (space, proto->protocol_list, emit_protocol_list (protocol->protocols, - va ("PROTOCOL_%s", protocol->name))); + va (0, "PROTOCOL_%s", protocol->name))); EMIT_DEF (space, proto->instance_methods, emit_method_descriptions (protocol->methods, protocol->name, 1)); EMIT_DEF (space, proto->class_methods, @@ -1786,7 +1787,7 @@ emit_protocol_list (protocollist_t *protocols, const char *name) if (!protocols) return 0; proto_list_struct[2].type = array_type (&type_pointer, protocols->count); - return emit_structure (va ("_OBJ_PROTOCOLS_%s", name), 's', + return emit_structure (va (0, "_OBJ_PROTOCOLS_%s", name), 's', proto_list_struct, 0, protocols, 0, sc_static); } diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index d3299a0ab..7ac1d0822 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -187,7 +187,7 @@ alias_def (def_t *def, type_t *type, int offset) return alias; } ALLOC (16384, def_t, defs, alias); - alias->name = save_string (va ("[%s:%d]", def->name, offset)); + alias->name = save_string (va (0, "[%s:%d]", def->name, offset)); alias->return_addr = __builtin_return_address (0); alias->offset = offset; alias->offset_reloc = 1; @@ -222,7 +222,7 @@ temp_def (type_t *type) temp->offset = defspace_alloc_aligned_loc (space, size, alignment); *space->def_tail = temp; space->def_tail = &temp->next; - temp->name = save_string (va (".tmp%d", current_func->temp_num++)); + temp->name = save_string (va (0, ".tmp%d", current_func->temp_num++)); } temp->return_addr = __builtin_return_address (0); temp->type = type; @@ -424,7 +424,7 @@ init_vector_components (symbol_t *vector_sym, int is_field) symbol_t *sym; const char *name; - name = va ("%s_%s", vector_sym->name, fields[i]); + name = va (0, "%s_%s", vector_sym->name, fields[i]); sym = symtab_lookup (current_symtab, name); if (sym) { if (sym->table == current_symtab) { diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index 4db09bc39..84bae7aa2 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -180,13 +180,13 @@ print_bool (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) for ( ; i < tl_count; i++) dasprintf (dstr, "%*st%s\n", indent, "", i, - i == count ? va ("", + i == count ? va (0, "", bool->true_list->size - count) : ""); for ( ; i < fl_count; i++) dasprintf (dstr, "%*s%sf\n", indent, "", - i == count ? va ("", + i == count ? va (0, "", bool->false_list->size - count) : "", i); @@ -449,22 +449,23 @@ print_value (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) switch (e->e.value->lltype) { case ev_string: - label = va ("\\\"%s\\\"", quote_string (e->e.value->v.string_val)); + label = va (0, "\\\"%s\\\"", + quote_string (e->e.value->v.string_val)); break; case ev_double: - label = va ("f %g", e->e.value->v.double_val); + label = va (0, "f %g", e->e.value->v.double_val); break; case ev_float: - label = va ("f %g", e->e.value->v.float_val); + label = va (0, "f %g", e->e.value->v.float_val); break; case ev_vector: - label = va ("'%g %g %g'", + label = va (0, "'%g %g %g'", e->e.value->v.vector_val[0], e->e.value->v.vector_val[1], e->e.value->v.vector_val[2]); break; case ev_quat: - label = va ("'%g %g %g %g'", + label = va (0, "'%g %g %g %g'", e->e.value->v.quaternion_val[0], e->e.value->v.quaternion_val[1], e->e.value->v.quaternion_val[2], @@ -477,32 +478,32 @@ print_value (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) print_type_str (type_str, type); } if (e->e.value->v.pointer.def) - label = va ("(*%s)[%d]<%s>", + label = va (0, "(*%s)[%d]<%s>", type ? type_str->str : "???", e->e.value->v.pointer.val, e->e.value->v.pointer.def->name); else - label = va ("(*%s)[%d]", + label = va (0, "(*%s)[%d]", type ? type_str->str : "???", e->e.value->v.pointer.val); break; case ev_field: - label = va ("field %d", e->e.value->v.pointer.val); + label = va (0, "field %d", e->e.value->v.pointer.val); break; case ev_entity: - label = va ("ent %d", e->e.value->v.integer_val); + label = va (0, "ent %d", e->e.value->v.integer_val); break; case ev_func: - label = va ("func %d", e->e.value->v.integer_val); + label = va (0, "func %d", e->e.value->v.integer_val); break; case ev_integer: - label = va ("i %d", e->e.value->v.integer_val); + label = va (0, "i %d", e->e.value->v.integer_val); break; case ev_uinteger: - label = va ("u %u", e->e.value->v.uinteger_val); + label = va (0, "u %u", e->e.value->v.uinteger_val); break; case ev_short: - label = va ("s %d", e->e.value->v.short_val); + label = va (0, "s %d", e->e.value->v.short_val); break; case ev_void: label = ""; diff --git a/tools/qfcc/source/dot_flow.c b/tools/qfcc/source/dot_flow.c index 0320ebb2d..ecfbcc01f 100644 --- a/tools/qfcc/source/dot_flow.c +++ b/tools/qfcc/source/dot_flow.c @@ -114,7 +114,7 @@ print_flow_node_dag (dstring_t *dstr, flowgraph_t *graph, flownode_t *node, int level) { if (node->dag) - print_dag (dstr, node->dag, va ("%d (%d)", node->id, node->dfn)); + print_dag (dstr, node->dag, va (0, "%d (%d)", node->id, node->dfn)); else print_flow_node (dstr, graph, node, level); } diff --git a/tools/qfcc/source/dot_type.c b/tools/qfcc/source/dot_type.c index ae58552b4..522fa91fb 100644 --- a/tools/qfcc/source/dot_type.c +++ b/tools/qfcc/source/dot_type.c @@ -175,7 +175,7 @@ print_struct (dstring_t *dstr, type_t *t, int level, int id) continue; } val = sym->s.offset; - port = va (" port=\"f%d\"", pnum++); + port = va (0, " port=\"f%d\"", pnum++); } dasprintf (dstr, "%*s%s%d\n", indent + 4, "", diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index fe166885c..317e70c03 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -93,20 +93,20 @@ dump_def (progs_t *pr, pr_def_t *def, int indent) if (string < 0 || (pr_uint_t) string >= pr->progs->numstrings) { str = "invalid string offset"; - comment = va (" %d %s", string, str); + comment = va (0, " %d %s", string, str); } else { str = quote_string (pr->pr_strings + G_INT (pr, offset)); - comment = va (" %d \"%s\"", string, str); + comment = va (0, " %d \"%s\"", string, str); } break; case ev_float: - comment = va (" %g", G_FLOAT (pr, offset)); + comment = va (0, " %g", G_FLOAT (pr, offset)); break; case ev_double: - comment = va (" %.17g", G_DOUBLE (pr, offset)); + comment = va (0, " %.17g", G_DOUBLE (pr, offset)); break; case ev_vector: - comment = va (" '%g %g %g'", + comment = va (0, " '%g %g %g'", G_VECTOR (pr, offset)[0], G_VECTOR (pr, offset)[1], G_VECTOR (pr, offset)[2]); @@ -114,7 +114,7 @@ dump_def (progs_t *pr, pr_def_t *def, int indent) case ev_entity: break; case ev_field: - comment = va (" %x", G_INT (pr, offset)); + comment = va (0, " %x", G_INT (pr, offset)); break; case ev_func: { @@ -123,26 +123,26 @@ dump_def (progs_t *pr, pr_def_t *def, int indent) if (func < pr->progs->numfunctions) { start = pr->pr_functions[func].first_statement; if (start > 0) - comment = va (" %d @ %x", func, start); + comment = va (0, " %d @ %x", func, start); else - comment = va (" %d = #%d", func, -start); + comment = va (0, " %d = #%d", func, -start); } else { - comment = va (" %d = illegal function", func); + comment = va (0, " %d = illegal function", func); } } break; case ev_pointer: - comment = va (" %x", G_INT (pr, offset)); + comment = va (0, " %x", G_INT (pr, offset)); break; case ev_quat: - comment = va (" '%g %g %g %g'", + comment = va (0, " '%g %g %g %g'", G_QUAT (pr, offset)[0], G_QUAT (pr, offset)[1], G_QUAT (pr, offset)[2], G_QUAT (pr, offset)[3]); break; case ev_integer: - comment = va (" %d", G_INT (pr, offset)); + comment = va (0, " %d", G_INT (pr, offset)); break; case ev_short: break; @@ -255,9 +255,9 @@ dump_functions (progs_t *pr) start = func->first_statement; if (start > 0) - comment = va (" @ %x", start); + comment = va (0, " @ %x", start); else - comment = va (" = #%d", -start); + comment = va (0, " = #%d", -start); printf ("%-5d %s%s: %d (", i, name, comment, func->numparms); if (func->numparms < 0) @@ -537,7 +537,7 @@ dump_qfo_types (qfo_t *qfo, int base_address) continue; } if (type->meta < 0 || type->meta >= NUM_META) - meta = va ("invalid meta: %d", type->meta); + meta = va (0, "invalid meta: %d", type->meta); else meta = ty_meta_names[type->meta]; printf ("%-5x %-9s %-20s", type_ptr + base_address, meta, diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index a8684a83b..f86e9dece 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -479,7 +479,7 @@ new_label_name (void) const char *fname = current_func->sym->name; const char *lname; - lname = save_string (va ("$%s_%d", fname, lnum)); + lname = save_string (va (0, "$%s_%d", fname, lnum)); return lname; } @@ -543,7 +543,8 @@ named_label_expr (symbol_t *label) return sym->s.expr; } l = new_label_expr (); - l->e.label.name = save_string (va ("%s_%s", l->e.label.name, label->name)); + l->e.label.name = save_string (va (0, "%s_%s", l->e.label.name, + label->name)); l->e.label.symbol = label; label->sy_type = sy_expr; label->s.expr = l; @@ -1268,7 +1269,7 @@ new_ret_expr (type_t *type) expr_t * new_param_expr (type_t *type, int num) { - return param_expr (va (".param_%d", num), type); + return param_expr (va (0, ".param_%d", num), type); } expr_t * diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 86f6dc9d5..3a1bb54c1 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -1607,7 +1607,7 @@ flow_build_graph (function_t *func) flow_make_edges (graph); flow_build_dfst (graph); if (options.block_dot.flow) - dump_dot (va ("flow-%d", pass), graph, dump_dot_flow); + dump_dot (va (0, "flow-%d", pass), graph, dump_dot_flow); pass++; } while (flow_remove_unreachable_nodes (graph)); flow_find_predecessors (graph); diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 940abf11e..4e7ef61f3 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -249,7 +249,7 @@ get_function (const char *name, const type_t *type, int overload, int create) name = save_string (name); - full_name = save_string (va ("%s|%s", name, encode_params (type))); + full_name = save_string (va (0, "%s|%s", name, encode_params (type))); func = Hash_Find (overloaded_functions, full_name); if (func) { @@ -382,7 +382,7 @@ find_function (expr_t *fexpr, expr_t *params) dummy.type = find_type (&type); qsort (funcs, func_count, sizeof (void *), func_compare); - dummy.full_name = save_string (va ("%s|%s", fexpr->e.symbol->name, + dummy.full_name = save_string (va (0, "%s|%s", fexpr->e.symbol->name, encode_params (&type))); dummy_p = bsearch (&dummy_p, funcs, func_count, sizeof (void *), func_compare); @@ -526,7 +526,7 @@ build_scope (symbol_t *fsym, symtab_t *parent) if (args) { while (i < MAX_PARMS) { - param = new_symbol_type (va (".par%d", i), &type_param); + param = new_symbol_type (va (0, ".par%d", i), &type_param); initialize_def (param, 0, symtab->space, sc_param); i++; } diff --git a/tools/qfcc/source/linker.c b/tools/qfcc/source/linker.c index 2f6e4a565..eb5aeb2bb 100644 --- a/tools/qfcc/source/linker.c +++ b/tools/qfcc/source/linker.c @@ -1106,7 +1106,7 @@ linker_add_lib (const char *libname) if (strncmp (libname, "-l", 2) == 0) { while (path) { - path_name = va ("%s/lib%s.a", path->path, libname + 2); + path_name = va (0, "%s/lib%s.a", path->path, libname + 2); pack = pack_open (path_name); if (pack) break; diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 1c461af85..a1d05ce9d 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -609,7 +609,7 @@ emit_methods (methodlist_t *methods, const char *name, int instance) methods->instance = instance; methods_struct[2].type = array_type (&type_method, count); - return emit_structure (va ("_OBJ_%s_METHODS_%s", type, name), 's', + return emit_structure (va (0, "_OBJ_%s_METHODS_%s", type, name), 's', methods_struct, 0, methods, 0, sc_static); } @@ -677,7 +677,7 @@ emit_method_descriptions (methodlist_t *methods, const char *name, methods->instance = instance; method_list_struct[1].type = array_type (&type_method_description, count); - return emit_structure (va ("_OBJ_%s_METHODS_%s", type, name), 's', + return emit_structure (va (0, "_OBJ_%s_METHODS_%s", type, name), 's', method_list_struct, 0, methods, 0, sc_static); } diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 76a5219d4..a8e6ae5fb 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -455,7 +455,7 @@ qfo_write (qfo_t *qfo, const char *filename) file = Qopen (filename, options.gzip ? "wbz9" : "wb"); if (!file) { - perror (va ("failed to open %s for writing", filename)); + perror (va (0, "failed to open %s for writing", filename)); return -1; } @@ -1168,7 +1168,7 @@ qfo_to_progs (qfo_t *qfo, int *size) if (options.verbosity >= 0) { const char *big_function = ""; if (big_func) - big_function = va (" (%s)", strings + qfo->funcs[big_func].name); + big_function = va (0, " (%s)", strings + qfo->funcs[big_func].name); printf ("%6i strofs\n", progs->numstrings); printf ("%6i statements\n", progs->numstatements); printf ("%6i functions\n", progs->numfunctions); diff --git a/tools/qfcc/source/options.c b/tools/qfcc/source/options.c index 758e388a3..09989684c 100644 --- a/tools/qfcc/source/options.c +++ b/tools/qfcc/source/options.c @@ -341,7 +341,7 @@ DecodeArgs (int argc, char **argv) } break; case 'l': // lib file - add_file (va ("-l%s", NORMALIZE (optarg))); + add_file (va (0, "-l%s", NORMALIZE (optarg))); break; case 'L': linker_add_path (NORMALIZE (optarg)); diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index b08884b92..32161c4b7 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -741,7 +741,8 @@ struct_def } else if (is_anonymous_struct ($1)) { // anonymous struct/union // type->name always begins with "tag " - $1.sym = new_symbol (va (".anonymous.%s", $1.type->name + 4)); + $1.sym = new_symbol (va (0, ".anonymous.%s", + $1.type->name + 4)); $1.sym->type = $1.type; $1.sym->sy_type = sy_var; $1.sym->visibility = vis_anonymous; @@ -1924,7 +1925,8 @@ ivar_decl if (is_anonymous_struct ($1)) { // anonymous struct/union // type->name always begins with "tag " - $1.sym = new_symbol (va (".anonymous.%s", $1.type->name + 4)); + $1.sym = new_symbol (va (0, ".anonymous.%s", + $1.type->name + 4)); $1.sym->type = $1.type; $1.sym->sy_type = sy_var; $1.sym->visibility = vis_anonymous; diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index e6c3b7946..1a8406186 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -411,7 +411,7 @@ compile_to_obj (const char *file, const char *obj, lang_t lang) } } if (options.frames_files) { - write_frame_macros (va ("%s.frame", file_basename (file, 0))); + write_frame_macros (va (0, "%s.frame", file_basename (file, 0))); } if (!err) { qfo_t *qfo; @@ -777,7 +777,7 @@ progs_src_compile (void) if (compile_file (qc_filename->str)) return 1; if (options.frames_files) { - write_frame_macros (va ("%s.frame", + write_frame_macros (va (0, "%s.frame", file_basename (qc_filename->str, 0))); } diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index 03d09123d..54b98b62a 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -183,7 +183,7 @@ load_file (progs_t *pr, const char *name, off_t *_size) file = open_file (name, &size); if (!file) { - file = open_file (va ("%s.gz", name), &size); + file = open_file (va (0, "%s.gz", name), &size); if (!file) return 0; } @@ -233,7 +233,7 @@ init_qf (void) { Sys_Init (); - Cvar_Get ("pr_debug", va ("%d", 1+verbosity), 0, 0, ""); + Cvar_Get ("pr_debug", va (0, "%d", 1+verbosity), 0, 0, ""); Cvar_Get ("pr_source_path", source_path, 0, 0, ""); PR_Init_Cvars (); diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 2383dcc84..0743c5c40 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -97,14 +97,14 @@ tempop_string (operand_t *tmpop) { tempop_t *tempop = &tmpop->o.tempop; if (tempop->alias) { - return va ("", + return va (0, "", pr_type_name[tempop->type->type], tmpop, tempop->users, tempop->alias, tempop->offset, tempop->alias->o.tempop.users); } - return va ("", pr_type_name[tempop->type->type], + return va (0, "", pr_type_name[tempop->type->type], tmpop, tempop->users); } @@ -119,47 +119,47 @@ operand_string (operand_t *op) case op_value: switch (op->o.value->lltype) { case ev_string: - return va ("\"%s\"", + return va (0, "\"%s\"", quote_string (op->o.value->v.string_val)); case ev_double: - return va ("%g", op->o.value->v.double_val); + return va (0, "%g", op->o.value->v.double_val); case ev_float: - return va ("%g", op->o.value->v.float_val); + return va (0, "%g", op->o.value->v.float_val); case ev_vector: - return va ("'%g %g %g'", + return va (0, "'%g %g %g'", op->o.value->v.vector_val[0], op->o.value->v.vector_val[1], op->o.value->v.vector_val[2]); case ev_quat: - return va ("'%g %g %g %g'", + return va (0, "'%g %g %g %g'", op->o.value->v.quaternion_val[0], op->o.value->v.quaternion_val[1], op->o.value->v.quaternion_val[2], op->o.value->v.quaternion_val[3]); case ev_pointer: if (op->o.value->v.pointer.def) { - return va ("ptr %s+%d", + return va (0, "ptr %s+%d", op->o.value->v.pointer.def->name, op->o.value->v.pointer.val); } else if(op->o.value->v.pointer.tempop) { operand_t *tempop = op->o.value->v.pointer.tempop; - return va ("ptr %s+%d", tempop_string (tempop), + return va (0, "ptr %s+%d", tempop_string (tempop), op->o.value->v.pointer.val); } else { - return va ("ptr %d", op->o.value->v.pointer.val); + return va (0, "ptr %d", op->o.value->v.pointer.val); } case ev_field: - return va ("field %d", op->o.value->v.pointer.val); + return va (0, "field %d", op->o.value->v.pointer.val); case ev_entity: - return va ("ent %d", op->o.value->v.integer_val); + return va (0, "ent %d", op->o.value->v.integer_val); case ev_func: - return va ("func %d", op->o.value->v.integer_val); + return va (0, "func %d", op->o.value->v.integer_val); case ev_integer: - return va ("int %d", op->o.value->v.integer_val); + return va (0, "int %d", op->o.value->v.integer_val); case ev_uinteger: - return va ("uint %u", op->o.value->v.uinteger_val); + return va (0, "uint %u", op->o.value->v.uinteger_val); case ev_short: - return va ("short %d", op->o.value->v.short_val); + return va (0, "short %d", op->o.value->v.short_val); case ev_void: return "(void)"; case ev_invalid: @@ -177,10 +177,11 @@ operand_string (operand_t *op) const char *alias = operand_string (op->o.alias); char *buf = alloca (strlen (alias) + 1); strcpy (buf, alias); - return va ("alias(%s,%s)", pr_type_name[op->type->type], buf); + return va (0, "alias(%s,%s)", pr_type_name[op->type->type], + buf); } case op_nil: - return va ("nil"); + return va (0, "nil"); } return ("??"); } @@ -1036,7 +1037,7 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op) } } } - opcode = va ("<%sCALL%d>", pref, count); + opcode = va (0, "<%sCALL%d>", pref, count); s = new_statement (st_func, opcode, call); sblock = statement_subexpr (sblock, func, &s->opa); s->opb = arguments[0]; @@ -2076,11 +2077,11 @@ make_statements (expr_t *e) do { did_something = thread_jumps (sblock); if (options.block_dot.thread) - dump_dot (va ("thread-%d", pass), sblock, dump_dot_sblock); + dump_dot (va (0, "thread-%d", pass), sblock, dump_dot_sblock); did_something |= remove_dead_blocks (sblock); sblock = merge_blocks (sblock); if (options.block_dot.dead) - dump_dot (va ("dead-%d", pass), sblock, dump_dot_sblock); + dump_dot (va (0, "dead-%d", pass), sblock, dump_dot_sblock); pass++; } while (did_something); check_final_block (sblock); diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index c42935dd2..ef9bd7389 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -70,13 +70,13 @@ find_tag (ty_meta_e meta, symbol_t *tag, type_t *type) symbol_t *sym; if (tag) { - tag_name = va ("tag %s", tag->name); + tag_name = va (0, "tag %s", tag->name); } else { const char *path = GETSTR (pr.source_file); const char *file = strrchr (path, '/'); if (!file++) file = path; - tag_name = va ("tag .%s.%d", file, pr.source_line); + tag_name = va (0, "tag .%s.%d", file, pr.source_line); } sym = symtab_lookup (current_symtab, tag_name); if (sym) { @@ -355,7 +355,7 @@ emit_structure (const char *name, int su, struct_def_t *defs, type_t *type, for (i = 0, field_sym = type->t.symtab->symbols; field_sym; i++, field_sym = field_sym->next) { field_def.type = field_sym->type; - field_def.name = save_string (va ("%s.%s", name, field_sym->name)); + field_def.name = save_string (va (0, "%s.%s", name, field_sym->name)); field_def.space = struct_def->space; field_def.offset = struct_def->offset + field_sym->s.offset; if (!defs[i].emit) { diff --git a/tools/qflight/source/entities.c b/tools/qflight/source/entities.c index d2bd2711c..1383004df 100644 --- a/tools/qflight/source/entities.c +++ b/tools/qflight/source/entities.c @@ -125,7 +125,8 @@ MatchTargets (void) // set the style on the source ent for switchable lights if (entities[j].style) { entities[i].style = entities[j].style; - SetKeyValue (&entities[i], "style", va ("%i", entities[i].style)); + SetKeyValue (&entities[i], "style", va (0, "%i", + entities[i].style)); } if (entities[i].spotcone >= 0) { diff --git a/tools/qflight/source/qflight.c b/tools/qflight/source/qflight.c index 4d2acfb73..75b9941d7 100644 --- a/tools/qflight/source/qflight.c +++ b/tools/qflight/source/qflight.c @@ -150,7 +150,7 @@ FindFaceOffsets (void) surfaceorgs = (vec3_t *) calloc (bsp->numfaces, sizeof (vec3_t)); for (i = 1; i < bsp->nummodels; i++) { - ent = FindEntityWithKeyPair ("model", name = va ("*%d", i)); + ent = FindEntityWithKeyPair ("model", name = va (0, "*%d", i)); VectorZero (org); if (!ent) Sys_Error ("FindFaceOffsets: Couldn't find entity for model %s.\n", diff --git a/tools/wad/script.c b/tools/wad/script.c index b4eaeeeff..e93efe0ac 100644 --- a/tools/wad/script.c +++ b/tools/wad/script.c @@ -159,7 +159,7 @@ write_file (void) QFile *file; const char *name; - name = va ("%s/%s.lmp", destfile.str, lumpname->str); + name = va (0, "%s/%s.lmp", destfile.str, lumpname->str); if (!(file = Qopen (name, "wb"))) Sys_Error ("couldn't open %s. %s", name, strerror(errno)); Qwrite (file, lumpbuffer, lump_p - lumpbuffer); From eeda04e3c95475b25308841dde1bcb77415d5b85 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 31 Jan 2021 19:58:55 +0900 Subject: [PATCH 312/435] [vulkan] Name most resources This makes debugging with renderdoc and validation messages much easier (no more "what buffer is that?"). --- include/QF/Vulkan/debug.h | 115 ++++++++++++++++++ include/QF/Vulkan/funclist.h | 19 +++ include/QF/Vulkan/qf_texture.h | 3 +- include/QF/Vulkan/scrap.h | 5 +- include/QF/Vulkan/staging.h | 3 +- libs/models/alias/vulkan_model_alias.c | 20 ++- libs/models/brush/vulkan_model_brush.c | 28 ++++- libs/video/renderer/vulkan/device.c | 4 +- libs/video/renderer/vulkan/scrap.c | 13 +- libs/video/renderer/vulkan/staging.c | 17 ++- libs/video/renderer/vulkan/vkparse.c | 3 + libs/video/renderer/vulkan/vulkan_alias.c | 25 +++- libs/video/renderer/vulkan/vulkan_bsp.c | 42 ++++++- libs/video/renderer/vulkan/vulkan_draw.c | 5 +- libs/video/renderer/vulkan/vulkan_texture.c | 19 ++- .../video/renderer/vulkan/vulkan_vid_common.c | 16 ++- 16 files changed, 310 insertions(+), 27 deletions(-) create mode 100644 include/QF/Vulkan/debug.h diff --git a/include/QF/Vulkan/debug.h b/include/QF/Vulkan/debug.h new file mode 100644 index 000000000..3250d5aca --- /dev/null +++ b/include/QF/Vulkan/debug.h @@ -0,0 +1,115 @@ +#ifndef __QF_Vulkan_debug_h +#define __QF_Vulkan_debug_h + +#define QFV_duCmdBeginLabel(device, cmd, name...)\ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkCmdBeginDebugUtilsLabelEXT) { \ + VkDebugUtilsLabelEXT label = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, 0, name \ + }; \ + dfunc->vkCmdBeginDebugUtilsLabelEXT (cmd, &label); \ + } \ + } while (0) + +#define QFV_duCmdEndLabel(device, cmd) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkCmdEndDebugUtilsLabelEXT) { \ + dfunc->vkCmdEndDebugUtilsLabelEXT (cmd); \ + } \ + } while (0) + +#define QFV_duCmdInsertLabel(device, cmd, name...) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkCmdInsertDebugUtilsLabelEXT) { \ + VkDebugUtilsLabelEXT label = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, 0, name \ + }; \ + dfunc->vkCmdInsertDebugUtilsLabelEXT (cmd, &label); \ + } \ + } while (0) + +#define QFV_duCreateMessenger(inst, severity, type, callback, data, messenger)\ + do { \ + if (inst->funcs->vkCreateDebugUtilsMessengerEXT) { \ + VkDebugUtilsMessengerCreateInfoEXT createInfo = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 0, 0,\ + severity, type, callback, data \ + }; \ + inst->funcs->vkCreateDebugUtilsMessengerEXT (inst, &createInfo, 0,\ + messenger); \ + } \ + } while (0) + +#define QFV_duDestroyMessenger(inst, messenger) \ + do { \ + if (inst->funcs->vkDestroyDebugUtilsMessengerEXT) { \ + inst->funcs->vkDestroyDebugUtilsMessengerEXT (inst, messenger, 0);\ + } \ + } while (0) + +#define QFV_duQueueBeginLabel(device, queue, name...) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkQueueBeginDebugUtilsLabelEXT) { \ + VkDebugUtilsLabelEXT label = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, 0, name \ + }; \ + dfunc->vkQueueBeginDebugUtilsLabelEXT (queue, &label); \ + } \ + } while (0) + +#define QFV_duQueueEndLabel(device, queue) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkQueueEndDebugUtilsLabelEXT) { \ + dfunc->vkQueueEndDebugUtilsLabelEXT (queue); \ + } \ + } while (0) + +#define QFV_duQueueInsertLabel(device, queue, name...) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkQueueInsertDebugUtilsLabelEXT) { \ + VkDebugUtilsLabelEXT label = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, 0, name \ + }; \ + dfunc->vkQueueInsertDebugUtilsLabelEXT (queue, &label); \ + } \ + } while (0) + +#define QFV_duSetObjectName(device, type, handle, name) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkSetDebugUtilsObjectNameEXT) { \ + VkDebugUtilsObjectNameInfoEXT nameInfo = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, 0, \ + type, (uint64_t) handle, name \ + }; \ + dfunc->vkSetDebugUtilsObjectNameEXT (device->dev, &nameInfo); \ + } \ + } while (0) + +#define QFV_duSetObjectTag(device, type, handle, name, size, tag) \ + do { \ + qfv_devfuncs_t *dfunc = device->funcs; \ + if (dfunc->vkSetDebugUtilsObjectTagEXT) { \ + VkDebugUtilsObjectTagInfoEXT tagInfo = { \ + VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT, 0, \ + type, handle, name, size, tag \ + }; \ + dfunc->vkSetDebugUtilsObjectTagEXT (device->dev, &tagInfo); \ + } \ + } while (0) + +#define QFV_duSubmitMessage(inst, severity, types, data) \ + do { \ + if (inst->funcs->vkSubmitDebugUtilsMessageEXT) { \ + inst->funcs->vkSubmitDebugUtilsMessageEXT (inst, severity, types, \ + data); \ + } \ + } while (0) + +#endif//__QF_Vulkan_debug_h diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index 90c3a51d2..a1601f814 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -43,6 +43,8 @@ INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkCreateDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkDestroyDebugUtilsMessengerEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkSubmitDebugUtilsMessageEXT, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkGetPhysicalDeviceSurfaceSupportKHR, VK_KHR_SURFACE_EXTENSION_NAME) INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION @@ -196,4 +198,21 @@ DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION (vkQueuePresentKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCmdBeginDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCmdEndDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkCmdInsertDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkQueueBeginDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkQueueEndDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkQueueInsertDebugUtilsLabelEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkSetDebugUtilsObjectNameEXT, 0) +DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + (vkSetDebugUtilsObjectTagEXT, 0) + #undef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION diff --git a/include/QF/Vulkan/qf_texture.h b/include/QF/Vulkan/qf_texture.h index d08fc0a46..a70ba1116 100644 --- a/include/QF/Vulkan/qf_texture.h +++ b/include/QF/Vulkan/qf_texture.h @@ -13,7 +13,8 @@ typedef struct qfv_tex_s { void Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, int alpha, int count); -qfv_tex_t *Vulkan_LoadTex (struct vulkan_ctx_s *ctx, tex_t *tex, int mip); +qfv_tex_t *Vulkan_LoadTex (struct vulkan_ctx_s *ctx, tex_t *tex, int mip, + const char *name); VkImageView Vulkan_TexImageView (qfv_tex_t *tex) __attribute__((pure)); void Vulkan_UnloadTex (struct vulkan_ctx_s *ctx, qfv_tex_t *tex); void Vulkan_Texture_Init (struct vulkan_ctx_s *ctx); diff --git a/include/QF/Vulkan/scrap.h b/include/QF/Vulkan/scrap.h index b4818d558..31ceba506 100644 --- a/include/QF/Vulkan/scrap.h +++ b/include/QF/Vulkan/scrap.h @@ -8,8 +8,9 @@ typedef struct scrap_s scrap_t; struct qfv_stagebuf_s; struct qfv_device_s; -scrap_t *QFV_CreateScrap (struct qfv_device_s *device, int size, - QFFormat format, struct qfv_stagebuf_s *stage); +scrap_t *QFV_CreateScrap (struct qfv_device_s *device, const char *name, + int size, QFFormat format, + struct qfv_stagebuf_s *stage); size_t QFV_ScrapSize (scrap_t *scrap) __attribute__((pure)); void QFV_ScrapClear (scrap_t *scrap); void QFV_DestroyScrap (scrap_t *scrap); diff --git a/include/QF/Vulkan/staging.h b/include/QF/Vulkan/staging.h index ee3678625..9058e3c9a 100644 --- a/include/QF/Vulkan/staging.h +++ b/include/QF/Vulkan/staging.h @@ -26,7 +26,8 @@ typedef struct qfv_stagebuf_s { qfv_stagebuf_t *QFV_CreateStagingBuffer (struct qfv_device_s *device, - size_t size, VkCommandPool cmdPool); + const char *name, size_t size, + VkCommandPool cmdPool); void QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage); void QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size); qfv_packet_t *QFV_PacketAcquire (qfv_stagebuf_t *stage); diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index 91ae665d0..07c63bee1 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -48,6 +48,7 @@ #include "QF/Vulkan/qf_texture.h" #include "QF/Vulkan/buffer.h" #include "QF/Vulkan/device.h" +#include "QF/Vulkan/debug.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/staging.h" @@ -252,6 +253,15 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, VkBuffer ibuff = QFV_CreateBuffer (device, ind_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, vbuff, + va (ctx->va_ctx, "buffer:alias:vertex:%s", + loadmodel->name)); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, uvbuff, + va (ctx->va_ctx, "buffer:alias:uv:%s", + loadmodel->name)); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, ibuff, + va (ctx->va_ctx, "buffer:alias:index:%s", + loadmodel->name)); size_t voffs = 0; size_t uvoffs = voffs + get_buffer_size (device, vbuff); size_t ioffs = uvoffs + get_buffer_size (device, uvbuff); @@ -260,12 +270,18 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, mem = QFV_AllocBufferMemory (device, vbuff, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, buff_size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, mem, + va (ctx->va_ctx, "memory:alias:vuvi:%s", + loadmodel->name)); QFV_BindBufferMemory (device, vbuff, mem, voffs); QFV_BindBufferMemory (device, uvbuff, mem, uvoffs); QFV_BindBufferMemory (device, ibuff, mem, ioffs); - qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, buff_size, - ctx->cmdpool); + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, + va (ctx->va_ctx, + "alias:%s", + loadmodel->name), + buff_size, ctx->cmdpool); qfv_packet_t *packet = QFV_PacketAcquire (stage); verts = QFV_PacketExtend (packet, vert_size); uv = QFV_PacketExtend (packet, uv_size); diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index 3d45dd63c..ea08a25a4 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -50,6 +50,7 @@ #include "QF/Vulkan/qf_texture.h" #include "QF/Vulkan/barrier.h" #include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/staging.h" @@ -209,10 +210,16 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) mem = QFV_AllocImageMemory (device, image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, memsize, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + mem, va (ctx->va_ctx, "memory:%s:texture", + loadmodel->name)); mctx->texture_memory = mem; - qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, memsize, - ctx->cmdpool); + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, + va (ctx->va_ctx, + "brush:%s", + loadmodel->name), + memsize, ctx->cmdpool); qfv_packet_t *packet = QFV_PacketAcquire (stage); buffer = QFV_PacketExtend (packet, memsize); @@ -239,6 +246,10 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) tex->tex->view = QFV_CreateImageView (device, tex->tex->image, type, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, + tex->tex->view, + va (ctx->va_ctx, "iview:%s:%s:tex", + loadmodel->name, tx->name)); transfer_mips (buffer + tex->tex->offset, tx + 1, tx, palette); if (tex->glow) { dfunc->vkBindImageMemory (device->dev, tex->glow->image, mem, @@ -249,6 +260,11 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, + tex->glow->view, + va (ctx->va_ctx, "iview:%s:%s:glow", + loadmodel->name, + tx->name)); transfer_mips (buffer + tex->glow->offset, tex->glow->memory, tx, palette); } @@ -351,6 +367,10 @@ Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx) VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, + tex->tex->image, + va (ctx->va_ctx, "image:%s:%s:tex", loadmodel->name, + tx->name)); if (layers > 1) { // skys are unlit, so no fullbrights return; @@ -372,6 +392,10 @@ Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx) VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, + tex->glow->image, + va (ctx->va_ctx, "image:%s:%s:glow", loadmodel->name, + tx->name)); // store the pointer to the fullbright data: memory will never be set to // actual device memory because all of the textures will be loaded in one // big buffer diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index 86ba71f73..4cfceb999 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -112,10 +112,12 @@ load_device_funcs (qfv_instance_t *inst, qfv_device_t *dev) } #define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(name, ext) \ - if (dev->extension_enabled (dev, ext)) { \ + if (!ext || dev->extension_enabled (dev, ext)) { \ dfunc->name = (PFN_##name) ifunc->vkGetDeviceProcAddr (device, #name); \ if (!dfunc->name) { \ Sys_Printf ("Couldn't find device level function %s", #name); \ + } else { \ + Sys_Printf ("Found device level function %s\n", #name); \ } \ } diff --git a/libs/video/renderer/vulkan/scrap.c b/libs/video/renderer/vulkan/scrap.c index 27c2ea3bd..01eed4bf8 100644 --- a/libs/video/renderer/vulkan/scrap.c +++ b/libs/video/renderer/vulkan/scrap.c @@ -51,6 +51,7 @@ #include "QF/Vulkan/barrier.h" #include "QF/Vulkan/buffer.h" #include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" @@ -76,12 +77,13 @@ struct scrap_s { }; scrap_t * -QFV_CreateScrap (qfv_device_t *device, int size, QFFormat format, - qfv_stagebuf_t *stage) +QFV_CreateScrap (qfv_device_t *device, const char *name, int size, + QFFormat format, qfv_stagebuf_t *stage) { qfv_devfuncs_t *dfunc = device->funcs; int bpp = 0; VkFormat fmt = VK_FORMAT_UNDEFINED; + dstring_t *str = dstring_new (); switch (format) { case tex_l: @@ -119,13 +121,20 @@ QFV_CreateScrap (qfv_device_t *device, int size, QFFormat format, extent, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, scrap->image, + dsprintf (str, "image:scrap:%s", name)); scrap->memory = QFV_AllocImageMemory (device, scrap->image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, scrap->memory, + dsprintf (str, "memory:scrap:%s", name)); QFV_BindImageMemory (device, scrap->image, scrap->memory, 0); scrap->view = QFV_CreateImageView (device, scrap->image, VK_IMAGE_VIEW_TYPE_2D, fmt, VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, scrap->view, + dsprintf (str, "iview:scrap:%s", name)); + dstring_delete (str); scrap->bpp = bpp; scrap->subpics = 0; scrap->device = device; diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c index 836a08e5e..cb3bb8ad0 100644 --- a/libs/video/renderer/vulkan/staging.c +++ b/libs/video/renderer/vulkan/staging.c @@ -48,6 +48,7 @@ #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/buffer.h" #include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/staging.h" @@ -55,11 +56,12 @@ #include "vid_vulkan.h" qfv_stagebuf_t * -QFV_CreateStagingBuffer (qfv_device_t *device, size_t size, +QFV_CreateStagingBuffer (qfv_device_t *device, const char * name, size_t size, VkCommandPool cmdPool) { size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; qfv_devfuncs_t *dfunc = device->funcs; + dstring_t *str = dstring_new (); qfv_stagebuf_t *stage = calloc (1, sizeof (qfv_stagebuf_t)); stage->atom_mask = atom - 1; @@ -67,9 +69,13 @@ QFV_CreateStagingBuffer (qfv_device_t *device, size_t size, stage->device = device; stage->buffer = QFV_CreateBuffer (device, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, stage->buffer, + dsprintf (str, "staging:buffer:%s", name)); stage->memory = QFV_AllocBufferMemory (device, stage->buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, stage->memory, + dsprintf (str, "staging:memory:%s", name)); stage->size = size; stage->end = size; @@ -85,9 +91,18 @@ QFV_CreateStagingBuffer (qfv_device_t *device, size_t size, packet->stage = stage; packet->cmd = bufferset->a[i]; packet->fence = QFV_CreateFence (device, 1); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + packet->cmd, + dsprintf (str, "staging:packet:cmd:%s:%d", + name, i)); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_FENCE, + packet->fence, + dsprintf (str, "staging:packet:fence:%s:%d", + name, i)); packet->offset = 0; packet->length = 0; } + dstring_delete (str); return stage; } diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 3c2447702..4108a75f5 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -54,6 +54,7 @@ #include "QF/simd/vec4f.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/debug.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/command.h" #include "QF/Vulkan/instance.h" @@ -391,6 +392,8 @@ parse_VkShaderModule_resource (const plitem_t *item, void **data, PL_Message (messages, item, "could not find shader %s", shader_path); return 0; } + QFV_duSetObjectName (device, VK_OBJECT_TYPE_SHADER_MODULE, *handle, + va (ctx->va_ctx, "shader:%s", shader_path)); return 1; } diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index a31267cfb..65fa232cc 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -57,6 +57,7 @@ #include "QF/Vulkan/qf_texture.h" #include "QF/Vulkan/buffer.h" #include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" @@ -270,15 +271,25 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) actx->pipeline = Vulkan_CreatePipeline (ctx, "alias"); actx->layout = QFV_GetPipelineLayout (ctx, "alias.layout"); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, actx->layout, + va (ctx->va_ctx, "layout:%s", "alias.layout")); actx->sampler = QFV_GetSampler (ctx, "alias.sampler"); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_SAMPLER, actx->sampler, + va (ctx->va_ctx, "sampler:%s", "alias.sampler")); - __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (2 * frames, alloca); + /*__auto_type layouts = QFV_AllocDescriptorSetLayoutSet (2 * frames, alloca); for (size_t i = 0; i < layouts->size / 2; i++) { __auto_type mats = QFV_GetDescriptorSetLayout (ctx, "alias.matrices"); __auto_type lights = QFV_GetDescriptorSetLayout (ctx, "alias.lights"); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, + mats, va (ctx->va_ctx, "set_layout:%s:%d", + "alias.matrices", i)); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, + lights, va (ctx->va_ctx, "set_layout:%s:%d", + "alias.lights", i)); layouts->a[2 * i + 0] = mats; layouts->a[2 * i + 1] = lights; - } + }*/ //__auto_type pool = QFV_GetDescriptorPool (ctx, "alias.pool"); __auto_type cmdBuffers = QFV_AllocCommandBufferSet (frames, alloca); @@ -288,6 +299,10 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) for (size_t i = 0; i < frames; i++) { lbuffers->a[i] = QFV_CreateBuffer (device, sizeof (qfv_light_buffer_t), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, + lbuffers->a[i], + va (ctx->va_ctx, "buffer:alias:%s:%zd", + "lights", i)); } VkMemoryRequirements requirements; dfunc->vkGetBufferMemoryRequirements (device->dev, lbuffers->a[0], @@ -295,6 +310,9 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) actx->light_memory = QFV_AllocBufferMemory (device, lbuffers->a[0], VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, frames * requirements.size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + actx->light_memory, va (ctx->va_ctx, + "memory:alias:%s", "lights")); byte *light_data; dfunc->vkMapMemory (device->dev, actx->light_memory, 0, frames * requirements.size, 0, (void **) &light_data); @@ -303,6 +321,9 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) for (size_t i = 0; i < frames; i++) { __auto_type aframe = &actx->frames.a[i]; aframe->cmd = cmdBuffers->a[i]; + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + aframe->cmd, + va (ctx->va_ctx, "cmd:alias:%zd", i)); aframe->light_buffer = lbuffers->a[i]; aframe->lights = (qfv_light_buffer_t *) (light_data + i * requirements.size); QFV_BindBufferMemory (device, lbuffers->a[i], actx->light_memory, diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index c95a14c97..a923f854a 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -58,6 +58,7 @@ #include "QF/Vulkan/buffer.h" #include "QF/Vulkan/barrier.h" #include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" @@ -467,7 +468,8 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) size_t vertex_buffer_size = vertex_count * sizeof (bspvert_t); index_buffer_size = (index_buffer_size + atom_mask) & ~atom_mask; - stage = QFV_CreateStagingBuffer (device, vertex_buffer_size, ctx->cmdpool); + stage = QFV_CreateStagingBuffer (device, "bsp", vertex_buffer_size, + ctx->cmdpool); qfv_packet_t *packet = QFV_PacketAcquire (stage); vertices = QFV_PacketExtend (packet, vertex_buffer_size); vertex_index_base = 0; @@ -518,10 +520,14 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) = QFV_CreateBuffer (device, index_buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, bctx->index_buffer, + "buffer:bsp:index"); bctx->index_memory = QFV_AllocBufferMemory (device, bctx->index_buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, index_buffer_size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + bctx->index_memory, "memory:bsp:index"); QFV_BindBufferMemory (device, bctx->index_buffer, bctx->index_memory, 0); bctx->index_buffer_size = index_buffer_size; @@ -545,10 +551,14 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) = QFV_CreateBuffer (device, vertex_buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, + bctx->vertex_buffer, "buffer:bsp:vertex"); bctx->vertex_memory = QFV_AllocBufferMemory (device, bctx->vertex_buffer, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertex_buffer_size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + bctx->vertex_memory, "memory:bsp:vertex"); QFV_BindBufferMemory (device, bctx->vertex_buffer, bctx->vertex_memory, 0); bctx->vertex_buffer_size = vertex_buffer_size; @@ -1290,12 +1300,17 @@ create_default_skys (vulkan_ctx_t *ctx) VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, skybox, + "bsp:image:default_skybox"); skysheet = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, VK_FORMAT_B8G8R8A8_UNORM, extents, 1, 2, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, skysheet, + "bsp:image:default_skysheet"); + VkMemoryRequirements requirements; dfunc->vkGetImageMemoryRequirements (device->dev, skybox, &requirements); size_t boxsize = requirements.size; @@ -1307,6 +1322,8 @@ create_default_skys (vulkan_ctx_t *ctx) boxsize + sheetsize, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, memory, + "bsp:memory:default_skys"); QFV_BindImageMemory (device, skybox, memory, 0); QFV_BindImageMemory (device, skysheet, memory, boxsize); @@ -1314,11 +1331,15 @@ create_default_skys (vulkan_ctx_t *ctx) boxview = QFV_CreateImageView (device, skybox, VK_IMAGE_VIEW_TYPE_CUBE, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, boxview, + "bsp:iview:default_skysheet"); sheetview = QFV_CreateImageView (device, skysheet, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, sheetview, + "bsp:iview:default_skysheet"); bctx->default_skybox->image = skybox; bctx->default_skybox->view = boxview; @@ -1405,9 +1426,11 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bctx->elementss_tail = &bctx->elementss; bctx->instsurfs_tail = &bctx->instsurfs; - bctx->light_scrap = QFV_CreateScrap (device, 2048, tex_frgba, ctx->staging); + bctx->light_scrap = QFV_CreateScrap (device, "lightmap_atlas", 2048, + tex_frgba, ctx->staging); size_t size = QFV_ScrapSize (bctx->light_scrap); - bctx->light_stage = QFV_CreateStagingBuffer (device, size, ctx->cmdpool); + bctx->light_stage = QFV_CreateStagingBuffer (device, "lightmap", size, + ctx->cmdpool); create_default_skys (ctx); @@ -1421,7 +1444,11 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bctx->main = Vulkan_CreatePipeline (ctx, "quakebsp.main"); bctx->sky = Vulkan_CreatePipeline (ctx, "quakebsp.skysheet"); bctx->layout = QFV_GetPipelineLayout (ctx, "quakebsp.layout"); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, bctx->layout, + va (ctx->va_ctx, "layout:%s", "quakebsp.layout")); bctx->sampler = QFV_GetSampler (ctx, "quakebsp.sampler"); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_SAMPLER, bctx->sampler, + va (ctx->va_ctx, "sampler:%s", "quakebsp.sampler")); __auto_type cmdBuffers = QFV_AllocCommandBufferSet (3 * frames, alloca); QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); @@ -1431,6 +1458,15 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bframe->bsp_cmd = cmdBuffers->a[i * 3 + 0]; bframe->turb_cmd = cmdBuffers->a[i * 3 + 1]; bframe->sky_cmd = cmdBuffers->a[i * 3 + 2]; + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + bframe->bsp_cmd, + va (ctx->va_ctx, "cmd:bsp:%zd", i)); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + bframe->turb_cmd, + va (ctx->va_ctx, "cmd:turb:%zd", i)); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + bframe->sky_cmd, + va (ctx->va_ctx, "cmd:sky:%zd", i)); for (int j = 0; j < BSP_BUFFER_INFOS; j++) { bframe->bufferInfo[j] = base_buffer_info; diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 3fc563cb2..16b563600 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -367,9 +367,10 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) 0, 0); create_quad_buffers (ctx); - dctx->stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024, + dctx->stage = QFV_CreateStagingBuffer (device, "draw", 4 * 1024 * 1024, ctx->cmdpool); - dctx->scrap = QFV_CreateScrap (device, 2048, tex_rgba, dctx->stage); + dctx->scrap = QFV_CreateScrap (device, "draw_atlas", 2048, tex_rgba, + dctx->stage); dctx->sampler = QFV_GetSampler (ctx, "quakepic"); qpic_t *charspic = Draw_Font8x8Pic (); diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index 0129f886c..9bff6e72b 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -48,11 +48,13 @@ #include "QF/quakefs.h" #include "QF/render.h" #include "QF/sys.h" +#include "QF/va.h" #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/qf_texture.h" #include "QF/Vulkan/barrier.h" #include "QF/Vulkan/buffer.h" #include "QF/Vulkan/command.h" +#include "QF/Vulkan/debug.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" @@ -199,7 +201,7 @@ blit_mips (int mips, VkImage image, tex_t *tex, } qfv_tex_t * -Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) +Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip, const char *name) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; @@ -256,14 +258,20 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip) VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, qtex->image, + va (ctx->va_ctx, "image:%s", name)); qtex->memory = QFV_AllocImageMemory (device, qtex->image, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, qtex->memory, + va (ctx->va_ctx, "memory:%s", name)); QFV_BindImageMemory (device, qtex->image, qtex->memory, 0); qtex->view = QFV_CreateImageView (device, qtex->image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, qtex->view, + va (ctx->va_ctx, "iview:%s", name)); size_t bytes = bpp * tex->width * tex->height; qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); @@ -337,9 +345,12 @@ static tex_t default_magenta_tex = {1, 1, tex_rgba, 1, 0, magenta_data}; void Vulkan_Texture_Init (vulkan_ctx_t *ctx) { - ctx->default_black = Vulkan_LoadTex (ctx, &default_black_tex, 1); - ctx->default_white = Vulkan_LoadTex (ctx, &default_white_tex, 1); - ctx->default_magenta = Vulkan_LoadTex (ctx, &default_magenta_tex, 1); + ctx->default_black = Vulkan_LoadTex (ctx, &default_black_tex, 1, + "default_black"); + ctx->default_white = Vulkan_LoadTex (ctx, &default_white_tex, 1, + "default_white"); + ctx->default_magenta = Vulkan_LoadTex (ctx, &default_magenta_tex, 1, + "default_magenta"); } void diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 2ab5fc166..ddd20e82c 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -54,6 +54,7 @@ #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/barrier.h" #include "QF/Vulkan/buffer.h" +#include "QF/Vulkan/debug.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/command.h" @@ -204,8 +205,8 @@ Vulkan_CreateDevice (vulkan_ctx_t *ctx) void Vulkan_CreateStagingBuffers (vulkan_ctx_t *ctx) { - ctx->staging = QFV_CreateStagingBuffer (ctx->device, 4*1024*1024, - ctx->cmdpool); + ctx->staging = QFV_CreateStagingBuffer (ctx->device, "vulkan_ctx", + 4*1024*1024, ctx->cmdpool); } void @@ -238,9 +239,10 @@ void Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) { qfv_load_pipeline (ctx); + const char *name = "renderpass";//FIXME plitem_t *item = ctx->pipelineDef; - if (!item || !(item = PL_ObjectForKey (item, "renderpass"))) { + if (!item || !(item = PL_ObjectForKey (item, name))) { Sys_Printf ("error loading renderpass\n"); return; } else { @@ -340,6 +342,9 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) ctx->renderpass.colorImage = colorImage; ctx->renderpass.depthImage = depthImage; ctx->renderpass.renderpass = QFV_ParseRenderPass (ctx, item); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_RENDER_PASS, + ctx->renderpass.renderpass, + va (ctx->va_ctx, "pipeline:%s", name)); } void @@ -382,7 +387,10 @@ Vulkan_CreatePipeline (vulkan_ctx_t *ctx, const char *name) } else { Sys_Printf ("Found pipeline def %s\n", name); } - return QFV_ParsePipeline (ctx, item); + VkPipeline pipeline = QFV_ParsePipeline (ctx, item); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_PIPELINE, pipeline, + va (ctx->va_ctx, "pipeline:%s", name)); + return pipeline; } void From 08b1d75582b37e245299b39ca2f34b804e34b6d5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 1 Feb 2021 10:54:49 +0900 Subject: [PATCH 313/435] [nq] Put the fps lock back in That wasn't meant to be removed yet as there are physics problems, but it's useful for renderer testing. It snuck in with the va patch. --- nq/source/host.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nq/source/host.c b/nq/source/host.c index 861e9d06b..65266f801 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -529,7 +529,7 @@ Host_FilterTime (float time) //FIXME not having the framerate cap is nice, but it breaks net play timedifference = (timescale / 72.0) - (realtime - oldrealtime); - if (0 && !cls.timedemo && (timedifference > 0)) + if (!cls.timedemo && (timedifference > 0)) return timedifference; // framerate is too high host_frametime = realtime - oldrealtime; @@ -541,7 +541,7 @@ Host_FilterTime (float time) if (host_framerate->value > 0) host_frametime = host_framerate->value; else // don't allow really long or short frames - host_frametime = bound (0.000, host_frametime, 0.1); + host_frametime = bound (0.001, host_frametime, 0.1); return 0; } From c7eafd92547591b1f9e1e4e0607c5ccf88841177 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 1 Feb 2021 12:16:05 +0900 Subject: [PATCH 314/435] [vulkan] Make the mip map generation public I've decided that alias model skins should be in a single four-level array texture rather than spread over four textures, but there's no way I want to write that code again: getting it right was hard enough the first time :P --- include/QF/Vulkan/image.h | 26 +++++++ libs/video/renderer/vulkan/image.c | 83 +++++++++++++++++++++ libs/video/renderer/vulkan/vulkan_texture.c | 82 +------------------- 3 files changed, 111 insertions(+), 80 deletions(-) diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index 489c86e40..71ca57389 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -57,4 +57,30 @@ VkImageView QFV_CreateImageView (struct qfv_device_s *device, VkImage image, VkImageViewType type, VkFormat format, VkImageAspectFlags aspect); +/** Generate all mipmaps for a given texture down to a 1x1 pixel. + * + * Uses the GPU blit command from one mip level to the next, thus the base mip + * level data must have already been transfered to the image and the image is + * expected to be in VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. This includes any + * array levels. + * + * \param device The device owning the command buffer. + * \param cmd The command buffer to which the barrier and blit commands + * will be written. + * \param image The image to be processed. All array layers of the base mip + * level must be initialized and in "transfer dst optimal" + * layout. All remaining mip levels must be in "undefined" + * oayout. + * \param mips The total number of mip levels of the processed image. + * \param width The pixel width of the base image. + * \param height The pixel height of the base image. + * \param layers The number of array layers in the mbase image. + * + * \note The processed image will be in "shader read only optimal" layout on + * completion. + */ +void QFV_GenerateMipMaps (struct qfv_device_s *device, VkCommandBuffer cmd, + VkImage image, unsigned mips, + unsigned width, unsigned height, unsigned layers); + #endif//__QF_Vulkan_image_h diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index bd71cc162..92d584f80 100644 --- a/libs/video/renderer/vulkan/image.c +++ b/libs/video/renderer/vulkan/image.c @@ -49,6 +49,7 @@ #include "QF/va.h" #include "QF/vid.h" #include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/barrier.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" @@ -192,3 +193,85 @@ QFV_CreateImageView (qfv_device_t *device, VkImage image, dfunc->vkCreateImageView (dev, &createInfo, 0, &view); return view; } + +void +QFV_GenerateMipMaps (qfv_device_t *device, VkCommandBuffer cmd, + VkImage image, unsigned mips, + unsigned width, unsigned height, unsigned layers) +{ + qfv_devfuncs_t *dfunc = device->funcs; + + qfv_pipelinestagepair_t pre_stages = { + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + }; + qfv_pipelinestagepair_t post_stages = { + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + }; + qfv_pipelinestagepair_t final_stages = { + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + }; + VkImageMemoryBarrier pre_barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + image, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers } + }; + VkImageMemoryBarrier post_barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + image, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers } + }; + VkImageMemoryBarrier final_barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + image, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers } + }; + + VkImageBlit blit = { + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, layers}, + {{0, 0, 0}, {width, height, 1}}, + {VK_IMAGE_ASPECT_COLOR_BIT, 1, 0, layers}, + {{0, 0, 0}, {max (width >> 1, 1), max (height >> 1, 1), 1}}, + }; + + while (--mips > 0) { + dfunc->vkCmdPipelineBarrier (cmd, pre_stages.src, pre_stages.dst, 0, + 0, 0, 0, 0, + 1, &pre_barrier); + dfunc->vkCmdBlitImage (cmd, + image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &blit, VK_FILTER_LINEAR); + + dfunc->vkCmdPipelineBarrier (cmd, post_stages.src, post_stages.dst, 0, + 0, 0, 0, 0, + 1, &post_barrier); + + blit.srcSubresource.mipLevel++; + blit.srcOffsets[1].x = blit.dstOffsets[1].x; + blit.srcOffsets[1].y = blit.dstOffsets[1].y; + blit.dstSubresource.mipLevel++; + blit.dstOffsets[1].x = max (blit.dstOffsets[1].x >> 1, 1); + blit.dstOffsets[1].y = max (blit.dstOffsets[1].y >> 1, 1); + pre_barrier.subresourceRange.baseMipLevel++; + post_barrier.subresourceRange.baseMipLevel++; + final_barrier.subresourceRange.baseMipLevel++; + } + dfunc->vkCmdPipelineBarrier (cmd, final_stages.src, final_stages.dst, 0, + 0, 0, 0, 0, + 1, &final_barrier); +} diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index 9bff6e72b..4a1e2d2ab 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -121,85 +121,6 @@ Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, } } -static void -blit_mips (int mips, VkImage image, tex_t *tex, - qfv_devfuncs_t *dfunc, VkCommandBuffer cmd) -{ - qfv_pipelinestagepair_t pre_stages = { - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - }; - qfv_pipelinestagepair_t post_stages = { - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - }; - qfv_pipelinestagepair_t final_stages = { - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - }; - VkImageMemoryBarrier pre_barrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, - image, - { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } - }; - VkImageMemoryBarrier post_barrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, - VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, - image, - { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } - }; - VkImageMemoryBarrier final_barrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, - VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, - image, - { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } - }; - - VkImageBlit blit = { - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, - {{0, 0, 0}, {tex->width, tex->height, 1}}, - {VK_IMAGE_ASPECT_COLOR_BIT, 1, 0, 1}, - {{0, 0, 0}, {max (tex->width >> 1, 1), max (tex->height >> 1, 1), 1}}, - }; - - while (--mips > 0) { - dfunc->vkCmdPipelineBarrier (cmd, pre_stages.src, pre_stages.dst, 0, - 0, 0, 0, 0, - 1, &pre_barrier); - dfunc->vkCmdBlitImage (cmd, - image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &blit, VK_FILTER_LINEAR); - - dfunc->vkCmdPipelineBarrier (cmd, post_stages.src, post_stages.dst, 0, - 0, 0, 0, 0, - 1, &post_barrier); - - blit.srcSubresource.mipLevel++; - blit.srcOffsets[1].x = blit.dstOffsets[1].x; - blit.srcOffsets[1].y = blit.dstOffsets[1].y; - blit.dstSubresource.mipLevel++; - blit.dstOffsets[1].x = max (blit.dstOffsets[1].x >> 1, 1); - blit.dstOffsets[1].y = max (blit.dstOffsets[1].y >> 1, 1); - pre_barrier.subresourceRange.baseMipLevel++; - post_barrier.subresourceRange.baseMipLevel++; - final_barrier.subresourceRange.baseMipLevel++; - } - dfunc->vkCmdPipelineBarrier (cmd, final_stages.src, final_stages.dst, 0, - 0, 0, 0, 0, - 1, &final_barrier); -} - qfv_tex_t * Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip, const char *name) { @@ -311,7 +232,8 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip, const char *name) 0, 0, 0, 0, 0, 1, &barrier); } else { - blit_mips (mip, qtex->image, tex, dfunc, packet->cmd); + QFV_GenerateMipMaps (device, packet->cmd, qtex->image, + mip, tex->width, tex->height, 1); } QFV_PacketSubmit (packet); return qtex; From afe8e9633e3c38e8d3a6ebf168d2f737015a0544 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 1 Feb 2021 12:24:27 +0900 Subject: [PATCH 315/435] [vulkan] Silence the matrix dump It got annoying and has served its purpose. However, the code is still there (#if 0) in case it's needed again. --- libs/video/renderer/vulkan/vulkan_matrices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_matrices.c b/libs/video/renderer/vulkan/vulkan_matrices.c index e1a1dd13e..ffd36219a 100644 --- a/libs/video/renderer/vulkan/vulkan_matrices.c +++ b/libs/video/renderer/vulkan/vulkan_matrices.c @@ -175,7 +175,7 @@ Vulkan_CalcProjectionMatrices (vulkan_ctx_t *ctx, float aspect) ortho_mat (mat->projection_2d, 0, width, 0, height, -99999, 99999); persp_mat (mat->projection_3d, 0, width, 0, height, aspect); - +#if 0 Sys_MaskPrintf (SYS_VULKAN, "ortho:\n"); Sys_MaskPrintf (SYS_VULKAN, " [[%g, %g, %g, %g],\n", QuatExpand (mat->projection_2d + 0)); @@ -194,7 +194,7 @@ Vulkan_CalcProjectionMatrices (vulkan_ctx_t *ctx, float aspect) QuatExpand (mat->projection_3d + 8)); Sys_MaskPrintf (SYS_VULKAN, " [%g, %g, %g, %g]]\n", QuatExpand (mat->projection_3d + 12)); - +#endif VkMappedMemoryRange ranges[] = { { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, mat->memory, 0, MAT_SIZE }, { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, mat->memory, From bb6c6963d2b6cb45f42a0b3cc0e841183a76603d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 1 Feb 2021 14:39:00 +0900 Subject: [PATCH 316/435] [model] Clean up the globals around model loading Covers only the generic load code (alias etc to follow), but this should take care of a lot of issues in the future. --- include/QF/Vulkan/qf_alias.h | 7 +- include/QF/model.h | 36 +-- include/QF/plugin/vid_render.h | 12 +- include/mod_internal.h | 54 ++-- libs/models/alias/gl_mesh.c | 6 +- libs/models/alias/gl_model_alias.c | 18 +- libs/models/alias/glsl_model_alias.c | 6 +- libs/models/alias/model_alias.c | 44 +-- libs/models/alias/sw_model_alias.c | 20 +- libs/models/alias/vulkan_model_alias.c | 24 +- libs/models/brush/gl_model_brush.c | 35 ++- libs/models/brush/glsl_model_brush.c | 12 +- libs/models/brush/model_brush.c | 285 ++++++++++--------- libs/models/brush/sw_model_brush.c | 8 +- libs/models/brush/vulkan_model_brush.c | 71 +++-- libs/models/clip_hull.c | 1 + libs/models/fullbright.c | 2 +- libs/models/gl_model_fullbright.c | 2 +- libs/models/iqm/model_iqm.c | 10 +- libs/models/model.c | 33 +-- libs/models/sprite/gl_model_sprite.c | 5 +- libs/models/sprite/glsl_model_sprite.c | 7 +- libs/models/sprite/model_sprite.c | 27 +- libs/models/sprite/sw_model_sprite.c | 3 +- libs/video/renderer/gl/gl_dyn_part.c | 2 +- libs/video/renderer/gl/gl_lightmap.c | 4 +- libs/video/renderer/gl/gl_rmisc.c | 2 +- libs/video/renderer/glsl/glsl_bsp.c | 4 +- libs/video/renderer/glsl/glsl_lightmap.c | 4 +- libs/video/renderer/glsl/glsl_particles.c | 2 +- libs/video/renderer/sw/sw_ralias.c | 2 +- libs/video/renderer/sw/sw_rpart.c | 2 +- libs/video/renderer/sw32/sw32_ralias.c | 2 +- libs/video/renderer/sw32/sw32_rpart.c | 2 +- libs/video/renderer/vid_render_vulkan.c | 25 +- libs/video/renderer/vulkan/vulkan_bsp.c | 4 +- libs/video/renderer/vulkan/vulkan_lightmap.c | 4 +- nq/source/cl_demo.c | 2 +- nq/source/cl_main.c | 2 +- nq/source/sv_main.c | 2 +- qw/source/cl_demo.c | 2 +- qw/source/sbar.c | 2 +- qw/source/sv_init.c | 2 +- qw/source/teamplay.c | 8 +- 44 files changed, 408 insertions(+), 399 deletions(-) diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index bcc5be337..dac8f4ca7 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -102,13 +102,14 @@ typedef struct aliasctx_s { struct vulkan_ctx_s; struct entity_s; -void *Vulkan_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc, +void *Vulkan_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, + int gnum, qboolean group, + maliasskindesc_t *skindesc, struct vulkan_ctx_s *ctx); void Vulkan_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr, struct vulkan_ctx_s *ctx); void Vulkan_Mod_LoadExternalSkins (model_t *mod, struct vulkan_ctx_s *ctx); -void Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, +void Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, int _s, int extra, struct vulkan_ctx_s *ctx); diff --git a/include/QF/model.h b/include/QF/model.h index 5512506f3..c7fc9190f 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -346,6 +346,8 @@ typedef enum {mod_brush, mod_sprite, mod_alias, mod_iqm} modtype_t; #define EF_GLOWTRAIL 4096 // glowcolor particle trail typedef struct model_s { + //FIXME use pointers. needs care in bsp submodel loading + char path[MAX_QPATH]; char name[MAX_QPATH]; const struct vpath_s *vpath;// virtual path where this model was found qboolean needload; // bmodels and sprites don't cache normally @@ -431,40 +433,20 @@ typedef struct model_s { // ============================================================================ -extern float RadiusFromBounds (const vec3_t mins, const vec3_t maxs) __attribute__((pure)); -void Mod_Init (void); -void Mod_Init_Cvars (void); -void Mod_ClearAll (void); +void Mod_Init (void); +void Mod_Init_Cvars (void); +void Mod_ClearAll (void); model_t *Mod_ForName (const char *name, qboolean crash); -void *Mod_Extradata (model_t *mod); // handles caching -void Mod_TouchModel (const char *name); - +void Mod_TouchModel (const char *name); +// brush specific mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model) __attribute__((pure)); -byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model); -model_t *Mod_FindName (const char *name); -int Mod_CalcFullbright (const byte *in, byte *out, int pixels); -void Mod_ClearFullbright (const byte *in, byte *out, int pixels); -int Mod_Fullbright (byte * skin, int width, int height, const char *name); - -void *Mod_LoadAliasFrame (void *pin, int *posenum, maliasframedesc_t *frame, - int extra); -void *Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame, - int extra); - -void Mod_FindClipDepth (hull_t *hull); -void Mod_LoadBrushModel (model_t *mod, void *buffer); -void Mod_FloodFillSkin (byte *skin, int skinwidth, int skinheight); - -void Mod_Print (void); +byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model); +void Mod_Print (void); extern struct cvar_s *gl_mesh_cache; extern struct cvar_s *gl_subdivide_size; extern struct cvar_s *gl_alias_render_tri; extern struct cvar_s *gl_textures_external; -extern model_t *loadmodel; -extern char *loadname; -extern byte *mod_base; -extern byte mod_novis[MAX_MAP_LEAFS / 8]; extern int mod_lightmap_bytes; #endif//__QF_model_h diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index b2ea3d224..cc634e562 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -81,22 +81,24 @@ typedef struct vid_particle_funcs_s { typedef struct vid_model_funcs_s { size_t texture_render_size;// size of renderer specific texture data - void (*Mod_LoadLighting) (bsp_t *bsp); - void (*Mod_SubdivideSurface) (msurface_t *fa); - void (*Mod_ProcessTexture) (texture_t *tx); + void (*Mod_LoadLighting) (model_t *mod, bsp_t *bsp); + void (*Mod_SubdivideSurface) (model_t *mod, msurface_t *fa); + void (*Mod_ProcessTexture) (model_t *mod, texture_t *tx); void (*Mod_LoadIQM) (model_t *mod, void *buffer); void (*Mod_LoadAliasModel) (model_t *mod, void *buffer, cache_allocator_t allocator); void (*Mod_LoadSpriteModel) (model_t *mod, void *buffer); void (*Mod_MakeAliasModelDisplayLists) (model_t *m, aliashdr_t *hdr, void *_m, int _s, int extra); - void *(*Mod_LoadSkin) (byte *skin, int skinsize, int snum, int gnum, + void *(*Mod_LoadSkin) (model_t *mod, byte *skin, int skinsize, int snum, + int gnum, qboolean group, maliasskindesc_t *skindesc); void (*Mod_FinalizeAliasModel) (model_t *m, aliashdr_t *hdr); void (*Mod_LoadExternalSkins) (model_t *mod); void (*Mod_IQMFinish) (model_t *mod); int alias_cache; - void (*Mod_SpriteLoadTexture) (mspriteframe_t *pspriteframe, int framenum); + void (*Mod_SpriteLoadTexture) (model_t *mod, mspriteframe_t *pspriteframe, + int framenum); struct skin_s *(*Skin_SetColormap) (struct skin_s *skin, int cmap); struct skin_s *(*Skin_SetSkin) (struct skin_s *skin, int cmap, diff --git a/include/mod_internal.h b/include/mod_internal.h index 382a8985f..f459bbeaa 100644 --- a/include/mod_internal.h +++ b/include/mod_internal.h @@ -6,50 +6,68 @@ #include "QF/skin.h" #include "QF/plugin/vid_render.h" +int Mod_CalcFullbright (const byte *in, byte *out, int pixels); +void Mod_ClearFullbright (const byte *in, byte *out, int pixels); +void Mod_FloodFillSkin (byte *skin, int skinwidth, int skinheight); +//FIXME gl specific. rewrite to use above +int Mod_Fullbright (byte * skin, int width, int height, const char *name); + +void Mod_LoadBrushModel (model_t *mod, void *buffer); +void Mod_FindClipDepth (hull_t *hull); + +model_t *Mod_FindName (const char *name); +float RadiusFromBounds (const vec3_t mins, const vec3_t maxs) __attribute__((pure)); + struct vulkan_ctx_s; extern vid_model_funcs_t *m_funcs; void gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, int _s, int extra); -void *gl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc); +void *gl_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, + int gnum, qboolean group, maliasskindesc_t *skindesc); void gl_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr); void gl_Mod_LoadExternalSkins (model_t *mod); void gl_Mod_IQMFinish (model_t *mod); void glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, int _s, int extra); -void *glsl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc); +void *glsl_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, + int gnum, qboolean group, maliasskindesc_t *skindesc); void glsl_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr); void glsl_Mod_LoadExternalSkins (model_t *mod); void glsl_Mod_IQMFinish (model_t *mod); void sw_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, int _s, int extra); -void *sw_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc); +void *sw_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, + int gnum, qboolean group, maliasskindesc_t *skindesc); void sw_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr); void sw_Mod_LoadExternalSkins (model_t *mod); void sw_Mod_IQMFinish (model_t *mod); -void gl_Mod_LoadLighting (bsp_t *bsp); -void gl_Mod_SubdivideSurface (msurface_t *fa); -void gl_Mod_ProcessTexture(texture_t *tx); +void gl_Mod_LoadLighting (model_t *mod, bsp_t *bsp); +void gl_Mod_SubdivideSurface (model_t *mod, msurface_t *fa); +void gl_Mod_ProcessTexture (model_t *mod, texture_t *tx); -void glsl_Mod_LoadLighting (bsp_t *bsp); -void glsl_Mod_ProcessTexture(texture_t *tx); +void glsl_Mod_LoadLighting (model_t *mod, bsp_t *bsp); +void glsl_Mod_ProcessTexture (model_t *mod, texture_t *tx); -void sw_Mod_LoadLighting (bsp_t *bsp); +void sw_Mod_LoadLighting (model_t *mod, bsp_t *bsp); -void Vulkan_Mod_LoadLighting (bsp_t *bsp, struct vulkan_ctx_s *ctx); -void Vulkan_Mod_SubdivideSurface (msurface_t *fa, struct vulkan_ctx_s *ctx); -void Vulkan_Mod_ProcessTexture(texture_t *tx, struct vulkan_ctx_s *ctx); +void Vulkan_Mod_LoadLighting (model_t *mod, bsp_t *bsp, + struct vulkan_ctx_s *ctx); +void Vulkan_Mod_SubdivideSurface (model_t *mod, msurface_t *fa, + struct vulkan_ctx_s *ctx); +void Vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx, + struct vulkan_ctx_s *ctx); -void gl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum); -void glsl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum); -void sw_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum); +void gl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum); +void glsl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum); +void sw_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum); void Mod_LoadIQM (model_t *mod, void *buffer); void Mod_FreeIQM (iqm_t *iqm); diff --git a/libs/models/alias/gl_mesh.c b/libs/models/alias/gl_mesh.c index c55225057..6820000cf 100644 --- a/libs/models/alias/gl_mesh.c +++ b/libs/models/alias/gl_mesh.c @@ -361,8 +361,8 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // look for a cached version dstring_copystr (cache, "glquake/"); - dstring_appendstr (cache, m->name); - QFS_StripExtension (m->name + strlen ("progs/"), + dstring_appendstr (cache, m->path); + QFS_StripExtension (m->path + strlen ("progs/"), cache->str + strlen ("glquake/")); dstring_appendstr (cache, ".qfms"); @@ -433,7 +433,7 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, } if (remesh) { // build it from scratch - Sys_MaskPrintf (SYS_DEV, "meshing %s...\n", m->name); + Sys_MaskPrintf (SYS_DEV, "meshing %s...\n", m->path); BuildTris (); // trifans or lists diff --git a/libs/models/alias/gl_model_alias.c b/libs/models/alias/gl_model_alias.c index ff5d62347..dec3a6e98 100644 --- a/libs/models/alias/gl_model_alias.c +++ b/libs/models/alias/gl_model_alias.c @@ -53,15 +53,15 @@ #include "compat.h" void * -gl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, qboolean group, - maliasskindesc_t *skindesc) +gl_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, int gnum, + qboolean group, maliasskindesc_t *skindesc) { byte *pskin; char modname[MAX_QPATH + 4]; int fb_texnum = 0, texnum = 0; dstring_t *name = dstring_new (); - pskin = Hunk_AllocName (skinsize, loadname); + pskin = Hunk_AllocName (skinsize, mod->name); skindesc->skin = (byte *) pskin - (byte *) pheader; memcpy (pskin, skin, skinsize); @@ -69,13 +69,13 @@ gl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, qboolean group, Mod_FloodFillSkin (pskin, pheader->mdl.skinwidth, pheader->mdl.skinheight); // save 8 bit texels for the player model to remap // FIXME remove model restriction - if (strequal (loadmodel->name, "progs/player.mdl")) + if (strequal (mod->path, "progs/player.mdl")) gl_Skin_SetPlayerSkin (pheader->mdl.skinwidth, pheader->mdl.skinheight, pskin); - QFS_StripExtension (loadmodel->name, modname); + QFS_StripExtension (mod->path, modname); - if (!loadmodel->fullbright) { + if (!mod->fullbright) { if (group) { dsprintf (name, "fb_%s_%i_%i", modname, snum, gnum); } else { @@ -95,7 +95,7 @@ gl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, qboolean group, Sys_MaskPrintf (SYS_GLT, "%s %d\n", name->str, texnum); skindesc->texnum = texnum; skindesc->fb_texnum = fb_texnum; - loadmodel->hasfullbrights = fb_texnum; + mod->hasfullbrights = fb_texnum; dstring_delete (name); // alpha param was true for non group skins return skin + skinsize; @@ -104,7 +104,7 @@ gl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, qboolean group, void gl_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr) { - if (strequal (m->name, "progs/eyes.mdl")) { + if (strequal (m->path, "progs/eyes.mdl")) { hdr->mdl.scale_origin[2] -= (22 + 8); VectorScale (hdr->mdl.scale, 2, hdr->mdl.scale); } @@ -158,7 +158,7 @@ gl_Mod_LoadExternalSkins (model_t *mod) maliasskingroup_t *pskingroup; dstring_t *filename = dstring_new (); - QFS_StripExtension (mod->name, modname); + QFS_StripExtension (mod->path, modname); for (i = 0; i < pheader->mdl.numskins; i++) { pskindesc = ((maliasskindesc_t *) diff --git a/libs/models/alias/glsl_model_alias.c b/libs/models/alias/glsl_model_alias.c index 796b3f346..609fa01b7 100644 --- a/libs/models/alias/glsl_model_alias.c +++ b/libs/models/alias/glsl_model_alias.c @@ -91,7 +91,7 @@ glsl_alias_clear (model_t *m, void *data) } void * -glsl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, +glsl_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc) { byte *tskin; @@ -104,9 +104,9 @@ glsl_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, memcpy (tskin, skin, skinsize); Mod_FloodFillSkin (tskin, w, h); if (group) - name = va (0, "%s_%i_%i", loadmodel->name, snum, gnum); + name = va (0, "%s_%i_%i", mod->path, snum, gnum); else - name = va (0, "%s_%i", loadmodel->name, snum); + name = va (0, "%s_%i", mod->path, snum); skindesc->texnum = GLSL_LoadQuakeTexture (name, w, h, tskin); free (tskin); return skin + skinsize; diff --git a/libs/models/alias/model_alias.c b/libs/models/alias/model_alias.c index c5018f929..e4225daea 100644 --- a/libs/models/alias/model_alias.c +++ b/libs/models/alias/model_alias.c @@ -62,7 +62,8 @@ int aliasbboxmins[3], aliasbboxmaxs[3]; static void * -Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex) +Mod_LoadAllSkins (model_t *mod, int numskins, daliasskintype_t *pskintype, + int *pskinindex) { byte *skin; float *poutskinintervals; @@ -77,7 +78,7 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex) skinsize = pheader->mdl.skinwidth * pheader->mdl.skinheight; pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t), - loadname); + mod->name); *pskinindex = (byte *) pskindesc - (byte *) pheader; @@ -85,7 +86,7 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex) pskindesc[snum].type = pskintype->type; if (pskintype->type == ALIAS_SKIN_SINGLE) { skin = (byte *) (pskintype + 1); - skin = m_funcs->Mod_LoadSkin (skin, skinsize, snum, 0, false, + skin = m_funcs->Mod_LoadSkin (mod, skin, skinsize, snum, 0, false, &pskindesc[snum]); } else { pskintype++; @@ -93,14 +94,14 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex) groupskins = LittleLong (pinskingroup->numskins); t = field_offset (maliasskingroup_t, skindescs[groupskins]); - paliasskingroup = Hunk_AllocName (t, loadname); + paliasskingroup = Hunk_AllocName (t, mod->name); paliasskingroup->numskins = groupskins; pskindesc[snum].skin = (byte *) paliasskingroup - (byte *) pheader; pinskinintervals = (daliasskininterval_t *) (pinskingroup + 1); poutskinintervals = Hunk_AllocName (groupskins * sizeof (float), - loadname); + mod->name); paliasskingroup->intervals = (byte *) poutskinintervals - (byte *) pheader; for (gnum = 0; gnum < groupskins; gnum++) { @@ -117,8 +118,9 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex) for (gnum = 0; gnum < groupskins; gnum++) { paliasskingroup->skindescs[gnum].type = ALIAS_SKIN_SINGLE; - skin = mod_funcs->Mod_LoadSkin (skin, skinsize, snum, gnum, - true, &paliasskingroup->skindescs[gnum]); + skin = mod_funcs->Mod_LoadSkin (mod, skin, skinsize, snum, + gnum, true, + &paliasskingroup->skindescs[gnum]); } } pskintype = (daliasskintype_t *) skin; @@ -127,9 +129,9 @@ Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype, int *pskinindex) return pskintype; } -void * -Mod_LoadAliasFrame (void *pin, int *posenum, maliasframedesc_t *frame, - int extra) +static void * +Mod_LoadAliasFrame (model_t *mod, void *pin, int *posenum, + maliasframedesc_t *frame, int extra) { daliasframe_t *pdaliasframe; trivertx_t *pinframe; @@ -159,9 +161,9 @@ Mod_LoadAliasFrame (void *pin, int *posenum, maliasframedesc_t *frame, return pinframe; } -void * -Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame, - int extra) +static void * +Mod_LoadAliasGroup (model_t *mod, void *pin, int *posenum, + maliasframedesc_t *frame, int extra) { daliasgroup_t *pingroup; daliasinterval_t *pin_intervals; @@ -178,7 +180,7 @@ Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame, frame->numposes = numframes; paliasgroup = Hunk_AllocName (field_offset (maliasgroup_t, - frames[numframes]), loadname); + frames[numframes]), mod->name); paliasgroup->numframes = numframes; frame->frame = (byte *) paliasgroup - (byte *) pheader; @@ -189,7 +191,7 @@ Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame, VectorCompMax (frame->bboxmax.v, aliasbboxmaxs, aliasbboxmaxs); pin_intervals = (daliasinterval_t *) (pingroup + 1); - poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname); + poutintervals = Hunk_AllocName (numframes * sizeof (float), mod->name); paliasgroup->intervals = (byte *) poutintervals - (byte *) pheader; frame->interval = LittleFloat (pin_intervals->interval); for (i = 0; i < numframes; i++) { @@ -203,7 +205,7 @@ Mod_LoadAliasGroup (void *pin, int *posenum, maliasframedesc_t *frame, ptemp = (void *) pin_intervals; for (i = 0; i < numframes; i++) { maliasframedesc_t temp_frame; - ptemp = Mod_LoadAliasFrame (ptemp, posenum, &temp_frame, extra); + ptemp = Mod_LoadAliasFrame (mod, ptemp, posenum, &temp_frame, extra); memcpy (&paliasgroup->frames[i], &temp_frame, sizeof (paliasgroup->frames[i])); } @@ -242,7 +244,7 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) // allocate space for a working header, plus all the data except the // frames, skin and group info size = field_offset (aliashdr_t, frames[LittleLong (pinmodel->numframes)]); - pheader = Hunk_AllocName (size, loadname); + pheader = Hunk_AllocName (size, mod->name); memset (pheader, 0, size); pmodel = &pheader->mdl; pheader->model = (byte *) pmodel - (byte *) pheader; @@ -294,7 +296,7 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) // load the skins pskintype = (daliasskintype_t *) &pinmodel[1]; - pskintype = Mod_LoadAllSkins (pheader->mdl.numskins, pskintype, + pskintype = Mod_LoadAllSkins (mod, pheader->mdl.numskins, pskintype, &pheader->skindesc); // load base s and t vertices @@ -332,11 +334,11 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) if (frametype == ALIAS_SINGLE) { pframetype = (daliasframetype_t *) - Mod_LoadAliasFrame (pframetype + 1, &posenum, + Mod_LoadAliasFrame (mod, pframetype + 1, &posenum, &pheader->frames[i], extra); } else { pframetype = (daliasframetype_t *) - Mod_LoadAliasGroup (pframetype + 1, &posenum, + Mod_LoadAliasGroup (mod, pframetype + 1, &posenum, &pheader->frames[i], extra); } } @@ -367,7 +369,7 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) end = Hunk_LowMark (); total = end - start; - mem = allocator (&mod->cache, total, loadname); + mem = allocator (&mod->cache, total, mod->name); if (mem) memcpy (mem, pheader, total); diff --git a/libs/models/alias/sw_model_alias.c b/libs/models/alias/sw_model_alias.c index e021278a4..61122298b 100644 --- a/libs/models/alias/sw_model_alias.c +++ b/libs/models/alias/sw_model_alias.c @@ -50,12 +50,12 @@ void * -sw_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, +sw_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc) { byte *pskin; - pskin = Hunk_AllocName (skinsize, loadname); + pskin = Hunk_AllocName (skinsize, mod->name); skindesc->skin = (byte *) pskin - (byte *) pheader; memcpy (pskin, skin, skinsize); @@ -64,7 +64,7 @@ sw_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, } static void -process_frame (maliasframedesc_t *frame, int posenum, int extra) +process_frame (model_t *mod, maliasframedesc_t *frame, int posenum, int extra) { int size = pheader->mdl.numverts * sizeof (trivertx_t); trivertx_t *frame_verts; @@ -72,7 +72,7 @@ process_frame (maliasframedesc_t *frame, int posenum, int extra) if (extra) size *= 2; - frame_verts = Hunk_AllocName (size, loadname); + frame_verts = Hunk_AllocName (size, mod->name); frame->frame = (byte *) frame_verts - (byte *) pheader; // The low-order 8 bits (actually, fractional) are completely separate @@ -83,7 +83,7 @@ process_frame (maliasframedesc_t *frame, int posenum, int extra) } void -sw_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, +sw_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, int _s, int extra) { int i, j; @@ -93,9 +93,9 @@ sw_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, mtriangle_t *ptri; pstverts = (stvert_t *) Hunk_AllocName (numv * sizeof (stvert_t), - loadname); + mod->name); ptri = (mtriangle_t *) Hunk_AllocName (numt * sizeof (mtriangle_t), - loadname); + mod->name); hdr->stverts = (byte *) pstverts - (byte *) hdr; hdr->triangles = (byte *) ptri - (byte *) hdr; @@ -117,16 +117,16 @@ sw_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, maliasgroup_t *group; group = (maliasgroup_t *) ((byte *) pheader + frame->frame); for (j = 0; j < group->numframes; j++) - process_frame ((maliasframedesc_t *) &group->frames[j], + process_frame (mod, (maliasframedesc_t *) &group->frames[j], posenum++, extra); } else { - process_frame (frame, posenum++, extra); + process_frame (mod, frame, posenum++, extra); } } } void -sw_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr) +sw_Mod_FinalizeAliasModel (model_t *mod, aliashdr_t *hdr) { } diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index 07c63bee1..97e8a63d0 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -110,8 +110,8 @@ vulkan_alias_clear (model_t *m, void *data) } void * -Vulkan_Mod_LoadSkin (byte *skinpix, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc, +Vulkan_Mod_LoadSkin (model_t *mod, byte *skinpix, int skinsize, int snum, + int gnum, qboolean group, maliasskindesc_t *skindesc, vulkan_ctx_t *ctx) { aliasskin_t *skin; @@ -131,25 +131,25 @@ Vulkan_Mod_LoadSkin (byte *skinpix, int skinsize, int snum, int gnum, if (Mod_CalcFullbright (tskin, tskin + skinsize, skinsize)) { skin->glow = Vulkan_LoadTex (ctx, &skin_tex, 1, va (ctx->va_ctx, "%s:%d:%d:glow", - loadmodel->name, snum, gnum)); + mod->name, snum, gnum)); Mod_ClearFullbright (tskin, tskin, skinsize); } if (Skin_CalcTopColors (tskin, tskin + skinsize, skinsize)) { skin->colora = Vulkan_LoadTex (ctx, &skin_tex, 1, va (ctx->va_ctx, "%s:%d:%d:colora", - loadmodel->name, snum, gnum)); + mod->name, snum, gnum)); Skin_ClearTopColors (tskin, tskin, skinsize); } if (Skin_CalcBottomColors (tskin, tskin + skinsize, skinsize)) { skin->colorb = Vulkan_LoadTex (ctx, &skin_tex, 1, va (ctx->va_ctx, "%s:%d:%d:colorb", - loadmodel->name, snum, gnum)); + mod->name, snum, gnum)); Skin_ClearBottomColors (tskin, tskin, skinsize); } skin_tex.data = tskin; skin->tex = Vulkan_LoadTex (ctx, &skin_tex, 1, va (ctx->va_ctx, "%s:%d:%d:tex", - loadmodel->name, + mod->name, snum, gnum)); free (tskin); @@ -185,7 +185,7 @@ get_buffer_size (qfv_device_t *device, VkBuffer buffer) } void -Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, +Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, int _s, int extra, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; @@ -255,13 +255,13 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, vbuff, va (ctx->va_ctx, "buffer:alias:vertex:%s", - loadmodel->name)); + mod->name)); QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, uvbuff, va (ctx->va_ctx, "buffer:alias:uv:%s", - loadmodel->name)); + mod->name)); QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, ibuff, va (ctx->va_ctx, "buffer:alias:index:%s", - loadmodel->name)); + mod->name)); size_t voffs = 0; size_t uvoffs = voffs + get_buffer_size (device, vbuff); size_t ioffs = uvoffs + get_buffer_size (device, uvbuff); @@ -272,7 +272,7 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, buff_size, 0); QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, mem, va (ctx->va_ctx, "memory:alias:vuvi:%s", - loadmodel->name)); + mod->name)); QFV_BindBufferMemory (device, vbuff, mem, voffs); QFV_BindBufferMemory (device, uvbuff, mem, uvoffs); QFV_BindBufferMemory (device, ibuff, mem, ioffs); @@ -280,7 +280,7 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, va (ctx->va_ctx, "alias:%s", - loadmodel->name), + mod->name), buff_size, ctx->cmdpool); qfv_packet_t *packet = QFV_PacketAcquire (stage); verts = QFV_PacketExtend (packet, vert_size); diff --git a/libs/models/brush/gl_model_brush.c b/libs/models/brush/gl_model_brush.c index 878d2c344..05b3c0b94 100644 --- a/libs/models/brush/gl_model_brush.c +++ b/libs/models/brush/gl_model_brush.c @@ -86,7 +86,7 @@ Mod_LoadExternalTextures (model_t *mod, texture_t *tx) int external = 0; gltx = tx->render; - if ((base = Mod_LoadAnExternalTexture (tx->name, mod->name))) { + if ((base = Mod_LoadAnExternalTexture (tx->name, mod->path))) { external = 1; gltx->gl_texturenum = GL_LoadTexture (tx->name, base->width, base->height, @@ -94,10 +94,10 @@ Mod_LoadExternalTextures (model_t *mod, texture_t *tx) base->format > 2 ? base->format : 1); luma = Mod_LoadAnExternalTexture (va (0, "%s_luma", tx->name), - mod->name); + mod->path); if (!luma) luma = Mod_LoadAnExternalTexture (va (0, "%s_glow", tx->name), - mod->name); + mod->path); gltx->gl_fb_texturenum = 0; @@ -116,7 +116,7 @@ Mod_LoadExternalTextures (model_t *mod, texture_t *tx) } void -gl_Mod_ProcessTexture (texture_t *tx) +gl_Mod_ProcessTexture (model_t *mod, texture_t *tx) { const char *name; @@ -125,7 +125,7 @@ gl_Mod_ProcessTexture (texture_t *tx) return; } if (gl_textures_external && gl_textures_external->int_val) { - if (Mod_LoadExternalTextures (loadmodel, tx)) { + if (Mod_LoadExternalTextures (mod, tx)) { return; } } @@ -142,7 +142,7 @@ gl_Mod_ProcessTexture (texture_t *tx) } void -gl_Mod_LoadLighting (bsp_t *bsp) +gl_Mod_LoadLighting (model_t *mod, bsp_t *bsp) { byte d; byte *in, *out, *data; @@ -151,13 +151,13 @@ gl_Mod_LoadLighting (bsp_t *bsp) int ver; QFile *lit_file; - dstring_copystr (litfilename, loadmodel->name); - loadmodel->lightdata = NULL; + dstring_copystr (litfilename, mod->path); + mod->lightdata = NULL; if (mod_lightmap_bytes > 1) { // LordHavoc: check for a .lit file to load QFS_StripExtension (litfilename->str, litfilename->str); dstring_appendstr (litfilename, ".lit"); - lit_file = QFS_VOpenFile (litfilename->str, 0, loadmodel->vpath); + lit_file = QFS_VOpenFile (litfilename->str, 0, mod->vpath); data = (byte *) QFS_LoadHunkFile (lit_file); if (data) { if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' @@ -165,7 +165,7 @@ gl_Mod_LoadLighting (bsp_t *bsp) ver = LittleLong (((int32_t *) data)[1]); if (ver == 1) { Sys_MaskPrintf (SYS_DEV, "%s loaded", litfilename->str); - loadmodel->lightdata = data + 8; + mod->lightdata = data + 8; return; } else Sys_MaskPrintf (SYS_DEV, @@ -179,11 +179,10 @@ gl_Mod_LoadLighting (bsp_t *bsp) dstring_delete (litfilename); return; } - loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize - * mod_lightmap_bytes, - litfilename->str); + mod->lightdata = Hunk_AllocName (bsp->lightdatasize * mod_lightmap_bytes, + litfilename->str); in = bsp->lightdata; - out = loadmodel->lightdata; + out = mod->lightdata; if (mod_lightmap_bytes > 1) for (i = 0; i < bsp->lightdatasize ; i++) { @@ -304,7 +303,7 @@ SubdividePolygon (int numverts, float *verts) can be done reasonably. */ void -gl_Mod_SubdivideSurface (msurface_t *fa) +gl_Mod_SubdivideSurface (model_t *mod, msurface_t *fa) { float *vec; int lindex, numverts, i; @@ -315,12 +314,12 @@ gl_Mod_SubdivideSurface (msurface_t *fa) // convert edges back to a normal polygon numverts = 0; for (i = 0; i < fa->numedges; i++) { - lindex = loadmodel->surfedges[fa->firstedge + i]; + lindex = mod->surfedges[fa->firstedge + i]; if (lindex > 0) - vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position; + vec = mod->vertexes[mod->edges[lindex].v[0]].position; else - vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position; + vec = mod->vertexes[mod->edges[-lindex].v[1]].position; VectorCopy (vec, verts[numverts]); numverts++; } diff --git a/libs/models/brush/glsl_model_brush.c b/libs/models/brush/glsl_model_brush.c index 23bb683ad..3a2717f57 100644 --- a/libs/models/brush/glsl_model_brush.c +++ b/libs/models/brush/glsl_model_brush.c @@ -101,7 +101,7 @@ load_skytex (texture_t *tx, byte *data) } void -glsl_Mod_ProcessTexture (texture_t *tx) +glsl_Mod_ProcessTexture (model_t *mod, texture_t *tx) { if (!tx) { r_notexture_mip->render = &glsl_notexture; @@ -145,15 +145,15 @@ glsl_Mod_ProcessTexture (texture_t *tx) } void -glsl_Mod_LoadLighting (bsp_t *bsp) +glsl_Mod_LoadLighting (model_t *mod, bsp_t *bsp) { // a bit hacky, but it's as good a place as any - loadmodel->clear = glsl_brush_clear; + mod->clear = glsl_brush_clear; mod_lightmap_bytes = 1; if (!bsp->lightdatasize) { - loadmodel->lightdata = NULL; + mod->lightdata = NULL; return; } - loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize, loadname); - memcpy (loadmodel->lightdata, bsp->lightdata, bsp->lightdatasize); + mod->lightdata = Hunk_AllocName (bsp->lightdatasize, mod->name); + memcpy (mod->lightdata, bsp->lightdata, bsp->lightdatasize); } diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index 24af26c95..38a33c893 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -53,8 +53,9 @@ #include "QF/plugin/vid_render.h" #include "compat.h" +#include "mod_internal.h" -byte mod_novis[MAX_MAP_LEAFS / 8]; +static byte mod_novis[MAX_MAP_LEAFS / 8]; VISIBLE cvar_t *gl_sky_divide; //FIXME visibility? VISIBLE int mod_lightmap_bytes = 1; //FIXME should this be visible? @@ -122,8 +123,12 @@ Mod_DecompressVis (byte * in, model_t *model) VISIBLE byte * Mod_LeafPVS (mleaf_t *leaf, model_t *model) { - if (leaf == model->leafs) + if (leaf == model->leafs) { + if (!mod_novis[0]) { + memset (mod_novis, 0xff, sizeof (mod_novis)); + } return mod_novis; + } return Mod_DecompressVis (leaf->compressed_vis, model); } @@ -158,7 +163,7 @@ mod_unique_miptex_name (texture_t **textures, texture_t *tx, int ind) } static void -Mod_LoadTextures (bsp_t *bsp) +Mod_LoadTextures (model_t *mod, bsp_t *bsp) { dmiptexlump_t *m; int i, j, pixels, num, max, altmax; @@ -167,14 +172,14 @@ Mod_LoadTextures (bsp_t *bsp) texture_t *anims[10], *altanims[10]; if (!bsp->texdatasize) { - loadmodel->textures = NULL; + mod->textures = NULL; return; } m = (dmiptexlump_t *) bsp->texdata; - loadmodel->numtextures = m->nummiptex; - loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof - (*loadmodel->textures), loadname); + mod->numtextures = m->nummiptex; + mod->textures = Hunk_AllocName (m->nummiptex * sizeof (*mod->textures), + mod->name); for (i = 0; i < m->nummiptex; i++) { if (m->dataofs[i] == -1) @@ -188,12 +193,12 @@ Mod_LoadTextures (bsp_t *bsp) if ((mt->width & 15) || (mt->height & 15)) Sys_Error ("Texture %s is not 16 aligned", mt->name); pixels = mt->width * mt->height / 64 * 85; - tx = Hunk_AllocName (sizeof (texture_t) + pixels, loadname); + tx = Hunk_AllocName (sizeof (texture_t) + pixels, mod->name); - loadmodel->textures[i] = tx; + mod->textures[i] = tx; tx->name = strndup(mt->name, sizeof (mt->name)); - mod_unique_miptex_name (loadmodel->textures, tx, i); + mod_unique_miptex_name (mod->textures, tx, i); tx->width = mt->width; tx->height = mt->height; for (j = 0; j < MIPLEVELS; j++) @@ -203,28 +208,28 @@ Mod_LoadTextures (bsp_t *bsp) memcpy (tx + 1, mt + 1, pixels); if (!strncmp (mt->name, "sky", 3)) - loadmodel->skytexture = tx; + mod->skytexture = tx; } if (mod_funcs && mod_funcs->Mod_ProcessTexture) { size_t render_size = mod_funcs->texture_render_size; byte *render_data = 0; if (render_size) { render_data = Hunk_AllocName (m->nummiptex * render_size, - loadname); + mod->name); } for (i = 0; i < m->nummiptex; i++) { - tx = loadmodel->textures[i]; + tx = mod->textures[i]; tx->render = render_data; render_data += render_size; - mod_funcs->Mod_ProcessTexture (tx); + mod_funcs->Mod_ProcessTexture (mod, tx); } // signal the end of the textures - mod_funcs->Mod_ProcessTexture (0); + mod_funcs->Mod_ProcessTexture (mod, 0); } // sequence the animations for (i = 0; i < m->nummiptex; i++) { - tx = loadmodel->textures[i]; + tx = mod->textures[i]; if (!tx || tx->name[0] != '+') continue; if (tx->anim_next) @@ -251,7 +256,7 @@ Mod_LoadTextures (bsp_t *bsp) Sys_Error ("Bad animating texture %s", tx->name); for (j = i + 1; j < m->nummiptex; j++) { - tx2 = loadmodel->textures[j]; + tx2 = mod->textures[j]; if (!tx2 || tx2->name[0] != '+') continue; if (strcmp (tx2->name + 2, tx->name + 2)) @@ -302,29 +307,29 @@ Mod_LoadTextures (bsp_t *bsp) } static void -Mod_LoadVisibility (bsp_t *bsp) +Mod_LoadVisibility (model_t *mod, bsp_t *bsp) { if (!bsp->visdatasize) { - loadmodel->visdata = NULL; + mod->visdata = NULL; return; } - loadmodel->visdata = Hunk_AllocName (bsp->visdatasize, loadname); - memcpy (loadmodel->visdata, bsp->visdata, bsp->visdatasize); + mod->visdata = Hunk_AllocName (bsp->visdatasize, mod->name); + memcpy (mod->visdata, bsp->visdata, bsp->visdatasize); } static void -Mod_LoadEntities (bsp_t *bsp) +Mod_LoadEntities (model_t *mod, bsp_t *bsp) { if (!bsp->entdatasize) { - loadmodel->entities = NULL; + mod->entities = NULL; return; } - loadmodel->entities = Hunk_AllocName (bsp->entdatasize, loadname); - memcpy (loadmodel->entities, bsp->entdata, bsp->entdatasize); + mod->entities = Hunk_AllocName (bsp->entdatasize, mod->name); + memcpy (mod->entities, bsp->entdata, bsp->entdatasize); } static void -Mod_LoadVertexes (bsp_t *bsp) +Mod_LoadVertexes (model_t *mod, bsp_t *bsp) { dvertex_t *in; int count, i; @@ -332,27 +337,27 @@ Mod_LoadVertexes (bsp_t *bsp) in = bsp->vertexes; count = bsp->numvertexes; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); - loadmodel->vertexes = out; - loadmodel->numvertexes = count; + mod->vertexes = out; + mod->numvertexes = count; for (i = 0; i < count; i++, in++, out++) VectorCopy (in->point, out->position); } static void -Mod_LoadSubmodels (bsp_t *bsp) +Mod_LoadSubmodels (model_t *mod, bsp_t *bsp) { dmodel_t *in, *out; int count, i, j; in = bsp->models; count = bsp->nummodels; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); - loadmodel->submodels = out; - loadmodel->numsubmodels = count; + mod->submodels = out; + mod->numsubmodels = count; for (i = 0; i < count; i++, in++, out++) { static vec3_t offset = {1, 1, 1}; @@ -367,11 +372,11 @@ Mod_LoadSubmodels (bsp_t *bsp) out->numfaces = in->numfaces; } - out = loadmodel->submodels; + out = mod->submodels; if (out->visleafs > MAX_MAP_LEAFS) { Sys_Error ("Mod_LoadSubmodels: too many visleafs (%d, max = %d) in %s", - out->visleafs, MAX_MAP_LEAFS, loadmodel->name); + out->visleafs, MAX_MAP_LEAFS, mod->path); } if (out->visleafs > 8192) @@ -381,7 +386,7 @@ Mod_LoadSubmodels (bsp_t *bsp) } static void -Mod_LoadEdges (bsp_t *bsp) +Mod_LoadEdges (model_t *mod, bsp_t *bsp) { dedge_t *in; int count, i; @@ -389,10 +394,10 @@ Mod_LoadEdges (bsp_t *bsp) in = bsp->edges; count = bsp->numedges; - out = Hunk_AllocName ((count + 1) * sizeof (*out), loadname); + out = Hunk_AllocName ((count + 1) * sizeof (*out), mod->name); - loadmodel->edges = out; - loadmodel->numedges = count; + mod->edges = out; + mod->numedges = count; for (i = 0; i < count; i++, in++, out++) { out->v[0] = in->v[0]; @@ -401,7 +406,7 @@ Mod_LoadEdges (bsp_t *bsp) } static void -Mod_LoadTexinfo (bsp_t *bsp) +Mod_LoadTexinfo (model_t *mod, bsp_t *bsp) { float len1, len2; int count, miptex, i, j; @@ -410,10 +415,10 @@ Mod_LoadTexinfo (bsp_t *bsp) in = bsp->texinfo; count = bsp->numtexinfo; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); - loadmodel->texinfo = out; - loadmodel->numtexinfo = count; + mod->texinfo = out; + mod->numtexinfo = count; for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 4; j++) { @@ -436,13 +441,13 @@ Mod_LoadTexinfo (bsp_t *bsp) miptex = in->miptex; out->flags = in->flags; - if (!loadmodel->textures) { + if (!mod->textures) { out->texture = r_notexture_mip; // checkerboard texture out->flags = 0; } else { - if (miptex >= loadmodel->numtextures) - Sys_Error ("miptex >= loadmodel->numtextures"); - out->texture = loadmodel->textures[miptex]; + if (miptex >= mod->numtextures) + Sys_Error ("miptex >= mod->numtextures"); + out->texture = mod->textures[miptex]; if (!out->texture) { out->texture = r_notexture_mip; // texture not found out->flags = 0; @@ -457,7 +462,7 @@ Mod_LoadTexinfo (bsp_t *bsp) Fills in s->texturemins[] and s->extents[] */ static void -CalcSurfaceExtents (msurface_t *s) +CalcSurfaceExtents (model_t *mod, msurface_t *s) { float mins[2], maxs[2], val; int e, i, j; @@ -471,11 +476,11 @@ CalcSurfaceExtents (msurface_t *s) tex = s->texinfo; for (i = 0; i < s->numedges; i++) { - e = loadmodel->surfedges[s->firstedge + i]; + e = mod->surfedges[s->firstedge + i]; if (e >= 0) - v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; + v = &mod->vertexes[mod->edges[e].v[0]]; else - v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; + v = &mod->vertexes[mod->edges[-e].v[1]]; for (j = 0; j < 2; j++) { val = v->position[0] * tex->vecs[j][0] + @@ -502,7 +507,7 @@ CalcSurfaceExtents (msurface_t *s) } static void -Mod_LoadFaces (bsp_t *bsp) +Mod_LoadFaces (model_t *mod, bsp_t *bsp) { dface_t *in; int count, planenum, side, surfnum, i; @@ -510,15 +515,15 @@ Mod_LoadFaces (bsp_t *bsp) in = bsp->faces; count = bsp->numfaces; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); if (count > 32767) { Sys_MaskPrintf (SYS_WARN, "%i faces exceeds standard limit of 32767.\n", count); } - loadmodel->surfaces = out; - loadmodel->numsurfaces = count; + mod->surfaces = out; + mod->numsurfaces = count; for (surfnum = 0; surfnum < count; surfnum++, in++, out++) { out->firstedge = in->firstedge; @@ -530,11 +535,11 @@ Mod_LoadFaces (bsp_t *bsp) if (side) out->flags |= SURF_PLANEBACK; - out->plane = loadmodel->planes + planenum; + out->plane = mod->planes + planenum; - out->texinfo = loadmodel->texinfo + in->texinfo; + out->texinfo = mod->texinfo + in->texinfo; - CalcSurfaceExtents (out); + CalcSurfaceExtents (mod, out); // lighting info @@ -544,7 +549,7 @@ Mod_LoadFaces (bsp_t *bsp) if (i == -1) out->samples = NULL; else - out->samples = loadmodel->lightdata + (i * mod_lightmap_bytes); + out->samples = mod->lightdata + (i * mod_lightmap_bytes); // set the drawing flags flag if (!out->texinfo->texture || !out->texinfo->texture->name) @@ -554,7 +559,7 @@ Mod_LoadFaces (bsp_t *bsp) out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); if (gl_sky_divide && gl_sky_divide->int_val) if (mod_funcs && mod_funcs->Mod_SubdivideSurface) - mod_funcs->Mod_SubdivideSurface (out); + mod_funcs->Mod_SubdivideSurface (mod, out); continue; } @@ -568,7 +573,7 @@ Mod_LoadFaces (bsp_t *bsp) } if (mod_funcs && mod_funcs->Mod_SubdivideSurface) { // cut up polygon for warps - mod_funcs->Mod_SubdivideSurface (out); + mod_funcs->Mod_SubdivideSurface (mod, out); } continue; } @@ -586,7 +591,7 @@ Mod_SetParent (mnode_t *node, mnode_t *parent) } static void -Mod_LoadNodes (bsp_t *bsp) +Mod_LoadNodes (model_t *mod, bsp_t *bsp) { dnode_t *in; int count, i, j, p; @@ -594,15 +599,15 @@ Mod_LoadNodes (bsp_t *bsp) in = bsp->nodes; count = bsp->numnodes; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); if (count > 32767) { Sys_MaskPrintf (SYS_WARN, "%i nodes exceeds standard limit of 32767.\n", count); } - loadmodel->nodes = out; - loadmodel->numnodes = count; + mod->nodes = out; + mod->numnodes = count; for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 3; j++) { @@ -611,7 +616,7 @@ Mod_LoadNodes (bsp_t *bsp) } p = in->planenum; - out->plane = loadmodel->planes + p; + out->plane = mod->planes + p; out->firstsurface = in->firstface; out->numsurfaces = in->numfaces; @@ -620,27 +625,27 @@ Mod_LoadNodes (bsp_t *bsp) p = in->children[j]; // this check is for extended bsp 29 files if (p >= 0) { - out->children[j] = loadmodel->nodes + p; + out->children[j] = mod->nodes + p; } else { p = ~p; - if (p < loadmodel->numleafs) { - out->children[j] = (mnode_t *) (loadmodel->leafs + p); + if (p < mod->numleafs) { + out->children[j] = (mnode_t *) (mod->leafs + p); } else { Sys_Printf ("Mod_LoadNodes: invalid leaf index %i " "(file has only %i leafs)\n", p, - loadmodel->numleafs); + mod->numleafs); //map it to the solid leaf - out->children[j] = (mnode_t *)(loadmodel->leafs); + out->children[j] = (mnode_t *)(mod->leafs); } } } } - Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs + Mod_SetParent (mod->nodes, NULL); // sets nodes and leafs } static void -Mod_LoadLeafs (bsp_t *bsp) +Mod_LoadLeafs (model_t *mod, bsp_t *bsp) { dleaf_t *in; int count, i, j, p; @@ -649,13 +654,13 @@ Mod_LoadLeafs (bsp_t *bsp) in = bsp->leafs; count = bsp->numleafs; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); - loadmodel->leafs = out; - loadmodel->numleafs = count; + mod->leafs = out; + mod->numleafs = count; // snprintf(s, sizeof (s), "maps/%s.bsp", // Info_ValueForKey(cl.serverinfo,"map")); - if (!strncmp ("maps/", loadmodel->name, 5)) + if (!strncmp ("maps/", mod->path, 5)) isnotmap = false; for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 3; j++) { @@ -666,14 +671,14 @@ Mod_LoadLeafs (bsp_t *bsp) p = in->contents; out->contents = p; - out->firstmarksurface = loadmodel->marksurfaces + in->firstmarksurface; + out->firstmarksurface = mod->marksurfaces + in->firstmarksurface; out->nummarksurfaces = in->nummarksurfaces; p = in->visofs; if (p == -1) out->compressed_vis = NULL; else - out->compressed_vis = loadmodel->visdata + p; + out->compressed_vis = mod->visdata + p; out->efrags = NULL; for (j = 0; j < 4; j++) @@ -692,7 +697,7 @@ Mod_LoadLeafs (bsp_t *bsp) } static void -Mod_LoadClipnodes (bsp_t *bsp) +Mod_LoadClipnodes (model_t *mod, bsp_t *bsp) { dclipnode_t *in; mclipnode_t *out; @@ -701,7 +706,7 @@ Mod_LoadClipnodes (bsp_t *bsp) in = bsp->clipnodes; count = bsp->numclipnodes; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); if (count > 32767) { Sys_MaskPrintf (SYS_WARN, @@ -709,15 +714,15 @@ Mod_LoadClipnodes (bsp_t *bsp) count); } - loadmodel->clipnodes = out; - loadmodel->numclipnodes = count; + mod->clipnodes = out; + mod->numclipnodes = count; - hull = &loadmodel->hulls[1]; - loadmodel->hull_list[1] = hull; + hull = &mod->hulls[1]; + mod->hull_list[1] = hull; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count - 1; - hull->planes = loadmodel->planes; + hull->planes = mod->planes; hull->clip_mins[0] = -16; hull->clip_mins[1] = -16; hull->clip_mins[2] = -24; @@ -725,12 +730,12 @@ Mod_LoadClipnodes (bsp_t *bsp) hull->clip_maxs[1] = 16; hull->clip_maxs[2] = 32; - hull = &loadmodel->hulls[2]; - loadmodel->hull_list[2] = hull; + hull = &mod->hulls[2]; + mod->hull_list[2] = hull; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count - 1; - hull->planes = loadmodel->planes; + hull->planes = mod->planes; hull->clip_mins[0] = -32; hull->clip_mins[1] = -32; hull->clip_mins[2] = -24; @@ -740,7 +745,7 @@ Mod_LoadClipnodes (bsp_t *bsp) for (i = 0; i < count; i++, out++, in++) { out->planenum = in->planenum; - if (out->planenum < 0 || out->planenum >= loadmodel->numplanes) + if (out->planenum < 0 || out->planenum >= mod->numplanes) Sys_Error ("Mod_LoadClipnodes: planenum out of bounds"); out->children[0] = in->children[0]; out->children[1] = in->children[1]; @@ -765,39 +770,39 @@ Mod_LoadClipnodes (bsp_t *bsp) Replicate the drawing hull structure as a clipping hull */ static void -Mod_MakeHull0 (void) +Mod_MakeHull0 (model_t *mod) { mclipnode_t *out; hull_t *hull; int count, i, j; mnode_t *in, *child; - hull = &loadmodel->hulls[0]; - loadmodel->hull_list[0] = hull; + hull = &mod->hulls[0]; + mod->hull_list[0] = hull; - in = loadmodel->nodes; - count = loadmodel->numnodes; - out = Hunk_AllocName (count * sizeof (*out), loadname); + in = mod->nodes; + count = mod->numnodes; + out = Hunk_AllocName (count * sizeof (*out), mod->name); hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count - 1; - hull->planes = loadmodel->planes; + hull->planes = mod->planes; for (i = 0; i < count; i++, out++, in++) { - out->planenum = in->plane - loadmodel->planes; + out->planenum = in->plane - mod->planes; for (j = 0; j < 2; j++) { child = in->children[j]; if (child->contents < 0) out->children[j] = child->contents; else - out->children[j] = child - loadmodel->nodes; + out->children[j] = child - mod->nodes; } } } static void -Mod_LoadMarksurfaces (bsp_t *bsp) +Mod_LoadMarksurfaces (model_t *mod, bsp_t *bsp) { int count, i, j; msurface_t **out; @@ -805,7 +810,7 @@ Mod_LoadMarksurfaces (bsp_t *bsp) in = bsp->marksurfaces; count = bsp->nummarksurfaces; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); if (count > 32767) { Sys_MaskPrintf (SYS_WARN, @@ -813,19 +818,19 @@ Mod_LoadMarksurfaces (bsp_t *bsp) count); } - loadmodel->marksurfaces = out; - loadmodel->nummarksurfaces = count; + mod->marksurfaces = out; + mod->nummarksurfaces = count; for (i = 0; i < count; i++) { j = in[i]; - if (j >= loadmodel->numsurfaces) + if (j >= mod->numsurfaces) Sys_Error ("Mod_ParseMarksurfaces: bad surface number"); - out[i] = loadmodel->surfaces + j; + out[i] = mod->surfaces + j; } } static void -Mod_LoadSurfedges (bsp_t *bsp) +Mod_LoadSurfedges (model_t *mod, bsp_t *bsp) { int count, i; int32_t *in; @@ -833,17 +838,17 @@ Mod_LoadSurfedges (bsp_t *bsp) in = bsp->surfedges; count = bsp->numsurfedges; - out = Hunk_AllocName (count * sizeof (*out), loadname); + out = Hunk_AllocName (count * sizeof (*out), mod->name); - loadmodel->surfedges = out; - loadmodel->numsurfedges = count; + mod->surfedges = out; + mod->numsurfedges = count; for (i = 0; i < count; i++) out[i] = in[i]; } static void -Mod_LoadPlanes (bsp_t *bsp) +Mod_LoadPlanes (model_t *mod, bsp_t *bsp) { dplane_t *in; int bits, count, i, j; @@ -851,10 +856,10 @@ Mod_LoadPlanes (bsp_t *bsp) in = bsp->planes; count = bsp->numplanes; - out = Hunk_AllocName (count * 2 * sizeof (*out), loadname); + out = Hunk_AllocName (count * 2 * sizeof (*out), mod->name); - loadmodel->planes = out; - loadmodel->numplanes = count; + mod->planes = out; + mod->numplanes = count; for (i = 0; i < count; i++, in++, out++) { bits = 0; @@ -897,22 +902,22 @@ do_checksums (const bsp_t *bsp, void *_mod) } static void -recurse_draw_tree (mnode_t *node, int depth) +recurse_draw_tree (model_t *mod, mnode_t *node, int depth) { if (!node || node->contents < 0) { - if (depth > loadmodel->depth) - loadmodel->depth = depth; + if (depth > mod->depth) + mod->depth = depth; return; } - recurse_draw_tree (node->children[0], depth + 1); - recurse_draw_tree (node->children[1], depth + 1); + recurse_draw_tree (mod, node->children[0], depth + 1); + recurse_draw_tree (mod, node->children[1], depth + 1); } static void -Mod_FindDrawDepth (void) +Mod_FindDrawDepth (model_t *mod) { - loadmodel->depth = 0; - recurse_draw_tree (loadmodel->nodes, 1); + mod->depth = 0; + recurse_draw_tree (mod, mod->nodes, 1); } void @@ -922,34 +927,34 @@ Mod_LoadBrushModel (model_t *mod, void *buffer) int i, j; bsp_t *bsp; - loadmodel->type = mod_brush; + mod->type = mod_brush; bsp = LoadBSPMem (buffer, qfs_filesize, do_checksums, mod); // load into heap - Mod_LoadVertexes (bsp); - Mod_LoadEdges (bsp); - Mod_LoadSurfedges (bsp); - Mod_LoadTextures (bsp); + Mod_LoadVertexes (mod, bsp); + Mod_LoadEdges (mod, bsp); + Mod_LoadSurfedges (mod, bsp); + Mod_LoadTextures (mod, bsp); if (mod_funcs && mod_funcs->Mod_LoadLighting) { - mod_funcs->Mod_LoadLighting (bsp); + mod_funcs->Mod_LoadLighting (mod, bsp); } - Mod_LoadPlanes (bsp); - Mod_LoadTexinfo (bsp); - Mod_LoadFaces (bsp); - Mod_LoadMarksurfaces (bsp); - Mod_LoadVisibility (bsp); - Mod_LoadLeafs (bsp); - Mod_LoadNodes (bsp); - Mod_LoadClipnodes (bsp); - Mod_LoadEntities (bsp); - Mod_LoadSubmodels (bsp); + Mod_LoadPlanes (mod, bsp); + Mod_LoadTexinfo (mod, bsp); + Mod_LoadFaces (mod, bsp); + Mod_LoadMarksurfaces (mod, bsp); + Mod_LoadVisibility (mod, bsp); + Mod_LoadLeafs (mod, bsp); + Mod_LoadNodes (mod, bsp); + Mod_LoadClipnodes (mod, bsp); + Mod_LoadEntities (mod, bsp); + Mod_LoadSubmodels (mod, bsp); BSP_Free(bsp); - Mod_MakeHull0 (); + Mod_MakeHull0 (mod); - Mod_FindDrawDepth (); + Mod_FindDrawDepth (mod); for (i = 0; i < MAX_MAP_HULLS; i++) Mod_FindClipDepth (&mod->hulls[i]); @@ -984,7 +989,7 @@ Mod_LoadBrushModel (model_t *mod, void *buffer) snprintf (name, sizeof (name), "*%i", i + 1); model_t *m = Mod_FindName (name); *m = *mod; - strcpy (m->name, name); + strcpy (m->path, name); mod = m; // make sure clear is called only for the main model m->clear = 0; diff --git a/libs/models/brush/sw_model_brush.c b/libs/models/brush/sw_model_brush.c index 1f179bab2..65a0e4e48 100644 --- a/libs/models/brush/sw_model_brush.c +++ b/libs/models/brush/sw_model_brush.c @@ -41,13 +41,13 @@ #include "mod_internal.h" void -sw_Mod_LoadLighting (bsp_t *bsp) +sw_Mod_LoadLighting (model_t *mod, bsp_t *bsp) { mod_lightmap_bytes = 1; if (!bsp->lightdatasize) { - loadmodel->lightdata = NULL; + mod->lightdata = NULL; return; } - loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize, loadname); - memcpy (loadmodel->lightdata, bsp->lightdata, bsp->lightdatasize); + mod->lightdata = Hunk_AllocName (bsp->lightdatasize, mod->name); + memcpy (mod->lightdata, bsp->lightdata, bsp->lightdatasize); } diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index ea08a25a4..ce9fd1e7e 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -63,15 +63,15 @@ static vulktex_t vulkan_notexture = { }; -static void vulkan_brush_clear (model_t *model, void *data) +static void vulkan_brush_clear (model_t *mod, void *data) { modelctx_t *mctx = data; vulkan_ctx_t *ctx = mctx->ctx; qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - for (int i = 0; i < model->numtextures; i++) { - texture_t *tx = model->textures[i]; + for (int i = 0; i < mod->numtextures; i++) { + texture_t *tx = mod->textures[i]; if (!tx) { continue; } @@ -173,19 +173,19 @@ copy_mips (qfv_packet_t *packet, texture_t *tx, qfv_tex_t *tex, } static void -load_textures (model_t *model, vulkan_ctx_t *ctx) +load_textures (model_t *mod, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - modelctx_t *mctx = model->data; + modelctx_t *mctx = mod->data; VkImage image = 0; byte *buffer; size_t image_count = 0; size_t copy_count = 0; size_t memsize = 0; - for (int i = 0; i < model->numtextures; i++) { - texture_t *tx = model->textures[i]; + for (int i = 0; i < mod->numtextures; i++) { + texture_t *tx = mod->textures[i]; if (!tx) { continue; } @@ -211,20 +211,18 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, memsize, 0); QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, - mem, va (ctx->va_ctx, "memory:%s:texture", - loadmodel->name)); + mem, va (ctx->va_ctx, "memory:%s:texture", mod->name)); mctx->texture_memory = mem; qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, va (ctx->va_ctx, - "brush:%s", - loadmodel->name), + "brush:%s", mod->name), memsize, ctx->cmdpool); qfv_packet_t *packet = QFV_PacketAcquire (stage); buffer = QFV_PacketExtend (packet, memsize); - for (int i = 0; i < model->numtextures; i++) { - texture_t *tx = model->textures[i]; + for (int i = 0; i < mod->numtextures; i++) { + texture_t *tx = mod->textures[i]; byte *palette = vid.palette32; if (!tx) { continue; @@ -249,7 +247,7 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, tex->tex->view, va (ctx->va_ctx, "iview:%s:%s:tex", - loadmodel->name, tx->name)); + mod->name, tx->name)); transfer_mips (buffer + tex->tex->offset, tx + 1, tx, palette); if (tex->glow) { dfunc->vkBindImageMemory (device->dev, tex->glow->image, mem, @@ -263,8 +261,7 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, tex->glow->view, va (ctx->va_ctx, "iview:%s:%s:glow", - loadmodel->name, - tx->name)); + mod->name, tx->name)); transfer_mips (buffer + tex->glow->offset, tex->glow->memory, tx, palette); } @@ -278,8 +275,8 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) __auto_type barriers = QFV_AllocImageBarrierSet (image_count, malloc); barriers->size = 0; - for (int i = 0; i < model->numtextures; i++) { - texture_t *tx = model->textures[i]; + for (int i = 0; i < mod->numtextures; i++) { + texture_t *tx = mod->textures[i]; if (!tx) { continue; } @@ -299,8 +296,8 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, barriers->size, barriers->a); - for (int i = 0, j = 0; i < model->numtextures; i++) { - texture_t *tx = model->textures[i]; + for (int i = 0, j = 0; i < mod->numtextures; i++) { + texture_t *tx = mod->textures[i]; if (!tx) { continue; } @@ -330,19 +327,18 @@ load_textures (model_t *model, vulkan_ctx_t *ctx) } void -Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx) +Vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; if (!tx) { - modelctx_t *mctx = Hunk_AllocName (sizeof (modelctx_t), - loadmodel->name); + modelctx_t *mctx = Hunk_AllocName (sizeof (modelctx_t), mod->name); mctx->ctx = ctx; - loadmodel->clear = vulkan_brush_clear; - loadmodel->data = mctx; + mod->clear = vulkan_brush_clear; + mod->data = mctx; r_notexture_mip->render = &vulkan_notexture; - load_textures (loadmodel, ctx); + load_textures (mod, ctx); return; } @@ -369,7 +365,7 @@ Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx) | VK_IMAGE_USAGE_SAMPLED_BIT); QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, tex->tex->image, - va (ctx->va_ctx, "image:%s:%s:tex", loadmodel->name, + va (ctx->va_ctx, "image:%s:%s:tex", mod->name, tx->name)); if (layers > 1) { // skys are unlit, so no fullbrights @@ -394,7 +390,7 @@ Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx) | VK_IMAGE_USAGE_SAMPLED_BIT); QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, tex->glow->image, - va (ctx->va_ctx, "image:%s:%s:glow", loadmodel->name, + va (ctx->va_ctx, "image:%s:%s:glow", mod->name, tx->name)); // store the pointer to the fullbright data: memory will never be set to // actual device memory because all of the textures will be loaded in one @@ -403,11 +399,11 @@ Vulkan_Mod_ProcessTexture (texture_t *tx, vulkan_ctx_t *ctx) } void -Vulkan_Mod_LoadLighting (bsp_t *bsp, vulkan_ctx_t *ctx) +Vulkan_Mod_LoadLighting (model_t *mod, bsp_t *bsp, vulkan_ctx_t *ctx) { mod_lightmap_bytes = 3; if (!bsp->lightdatasize) { - loadmodel->lightdata = NULL; + mod->lightdata = NULL; return; } @@ -417,14 +413,14 @@ Vulkan_Mod_LoadLighting (bsp_t *bsp, vulkan_ctx_t *ctx) int ver; QFile *lit_file; - loadmodel->lightdata = 0; + mod->lightdata = 0; if (mod_lightmap_bytes > 1) { // LordHavoc: check for a .lit file to load dstring_t *litfilename = dstring_new (); - dstring_copystr (litfilename, loadmodel->name); + dstring_copystr (litfilename, mod->name); QFS_StripExtension (litfilename->str, litfilename->str); dstring_appendstr (litfilename, ".lit"); - lit_file = QFS_VOpenFile (litfilename->str, 0, loadmodel->vpath); + lit_file = QFS_VOpenFile (litfilename->str, 0, mod->vpath); data = (byte *) QFS_LoadHunkFile (lit_file); if (data) { if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' @@ -432,7 +428,7 @@ Vulkan_Mod_LoadLighting (bsp_t *bsp, vulkan_ctx_t *ctx) ver = LittleLong (((int32_t *) data)[1]); if (ver == 1) { Sys_MaskPrintf (SYS_DEV, "%s loaded", litfilename->str); - loadmodel->lightdata = data + 8; + mod->lightdata = data + 8; } else { Sys_MaskPrintf (SYS_DEV, "Unknown .lit file version (%d)\n", ver); @@ -443,14 +439,13 @@ Vulkan_Mod_LoadLighting (bsp_t *bsp, vulkan_ctx_t *ctx) } dstring_delete (litfilename); } - if (loadmodel->lightdata || !bsp->lightdatasize) { + if (mod->lightdata || !bsp->lightdatasize) { return; } // LordHavoc: oh well, expand the white lighting data - loadmodel->lightdata = Hunk_AllocName (bsp->lightdatasize * 3, - loadmodel->name); + mod->lightdata = Hunk_AllocName (bsp->lightdatasize * 3, mod->name); in = bsp->lightdata; - out = loadmodel->lightdata; + out = mod->lightdata; for (i = 0; i < bsp->lightdatasize ; i++) { d = *in++; diff --git a/libs/models/clip_hull.c b/libs/models/clip_hull.c index f47c1886d..0a01b62f1 100644 --- a/libs/models/clip_hull.c +++ b/libs/models/clip_hull.c @@ -36,6 +36,7 @@ #include "QF/clip_hull.h" #include "QF/model.h" +#include "mod_internal.h" VISIBLE clip_hull_t * MOD_Alloc_Hull (int nodes, int planes) diff --git a/libs/models/fullbright.c b/libs/models/fullbright.c index 22cef6a83..8d76b9db4 100644 --- a/libs/models/fullbright.c +++ b/libs/models/fullbright.c @@ -31,7 +31,7 @@ # include "config.h" #endif -#include "r_local.h" +#include "mod_internal.h" VISIBLE int Mod_CalcFullbright (const byte *in, byte *out, int pixels) diff --git a/libs/models/gl_model_fullbright.c b/libs/models/gl_model_fullbright.c index f319581ae..ef94e59ca 100644 --- a/libs/models/gl_model_fullbright.c +++ b/libs/models/gl_model_fullbright.c @@ -38,7 +38,7 @@ #include "QF/qendian.h" #include "QF/sys.h" -#include "r_local.h" +#include "mod_internal.h" int Mod_Fullbright (byte *skin, int width, int height, const char *name) diff --git a/libs/models/iqm/model_iqm.c b/libs/models/iqm/model_iqm.c index 4940da557..1091ee7d9 100644 --- a/libs/models/iqm/model_iqm.c +++ b/libs/models/iqm/model_iqm.c @@ -497,25 +497,25 @@ Mod_LoadIQM (model_t *mod, void *buffer) uint32_t *swap; if (!strequal (hdr->magic, IQM_MAGIC)) - Sys_Error ("%s: not an IQM", loadname); + Sys_Error ("%s: not an IQM", mod->path); // Byte swap the header. Everything is the same type, so no problem :) for (swap = &hdr->version; swap <= &hdr->ofs_extensions; swap++) *swap = LittleLong (*swap); //if (hdr->version < 1 || hdr->version > IQM_VERSION) if (hdr->version != IQM_VERSION) - Sys_Error ("%s: unable to handle iqm version %d", loadname, + Sys_Error ("%s: unable to handle iqm version %d", mod->path, hdr->version); if (hdr->filesize != (uint32_t) qfs_filesize) - Sys_Error ("%s: invalid filesize", loadname); + Sys_Error ("%s: invalid filesize", mod->path); iqm = calloc (1, sizeof (iqm_t)); iqm->text = malloc (hdr->num_text); memcpy (iqm->text, (byte *) buffer + hdr->ofs_text, hdr->num_text); mod->aliashdr = (aliashdr_t *) iqm; mod->type = mod_iqm; if (hdr->num_meshes && !load_iqm_meshes (mod, hdr, (byte *) buffer)) - Sys_Error ("%s: error loading meshes", loadname); + Sys_Error ("%s: error loading meshes", mod->path); if (hdr->num_anims && !load_iqm_anims (mod, hdr, (byte *) buffer)) - Sys_Error ("%s: error loading anims", loadname); + Sys_Error ("%s: error loading anims", mod->path); m_funcs->Mod_IQMFinish (mod); } diff --git a/libs/models/model.c b/libs/models/model.c index 8c5036278..7eb606930 100644 --- a/libs/models/model.c +++ b/libs/models/model.c @@ -48,12 +48,10 @@ #include "QF/plugin/vid_render.h" #include "compat.h" +#include "mod_internal.h" vid_model_funcs_t *mod_funcs; -model_t *loadmodel; -char *loadname; // for hunk tags - #define MOD_BLOCK 16 // allocate 16 models at a time model_t **mod_known; int mod_numknown; @@ -75,7 +73,6 @@ Mod_Init (void) int m, x, y; int mip0size = 16*16, mip1size = 8*8, mip2size = 4*4, mip3size = 2*2; - memset (mod_novis, 0xff, sizeof (mod_novis)); r_notexture_mip = Hunk_AllocName (sizeof (texture_t) + mip0size + mip1size + mip2size + mip3size, "notexture"); @@ -145,7 +142,7 @@ Mod_FindName (const char *name) // search the currently loaded models for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) - if (!strcmp ((*mod)->name, name)) + if (!strcmp ((*mod)->path, name)) break; if (i == mod_numknown) { @@ -158,7 +155,7 @@ Mod_FindName (const char *name) mod[i] = mod[0] + i; } memset ((*mod), 0, sizeof (model_t)); - strncpy ((*mod)->name, name, sizeof (*mod)->name - 1); + strncpy ((*mod)->path, name, sizeof (*mod)->path - 1); (*mod)->needload = true; mod_numknown++; Cache_Add (&(*mod)->cache, *mod, Mod_CallbackLoad); @@ -173,17 +170,17 @@ Mod_RealLoadModel (model_t *mod, qboolean crash, cache_allocator_t allocator) uint32_t *buf; // load the file - buf = (uint32_t *) QFS_LoadFile (QFS_FOpenFile (mod->name), 0); + buf = (uint32_t *) QFS_LoadFile (QFS_FOpenFile (mod->path), 0); if (!buf) { if (crash) - Sys_Error ("Mod_LoadModel: %s not found", mod->name); + Sys_Error ("Mod_LoadModel: %s not found", mod->path); return NULL; } - if (loadname) - free (loadname); - loadname = QFS_FileBase (mod->name); - loadmodel = mod; + char *name = QFS_FileBase (mod->path); + strncpy (mod->name, name, sizeof (mod->name - 1)); + mod->name[sizeof (mod->name) - 1] = 0; + free (name); // fill it in mod->vpath = qfs_foundfile.vpath; @@ -204,17 +201,17 @@ Mod_RealLoadModel (model_t *mod, qboolean crash, cache_allocator_t allocator) break; case IDHEADER_MDL: // Type 6: Quake 1 .mdl case HEADER_MDL16: // QF Type 6 extended for 16bit precision - if (strequal (mod->name, "progs/grenade.mdl")) { + if (strequal (mod->path, "progs/grenade.mdl")) { mod->fullbright = 0; mod->shadow_alpha = 255; - } else if (strnequal (mod->name, "progs/flame", 11) - || strnequal (mod->name, "progs/bolt", 10)) { + } else if (strnequal (mod->path, "progs/flame", 11) + || strnequal (mod->path, "progs/bolt", 10)) { mod->fullbright = 1; mod->shadow_alpha = 0; } - if (strnequal (mod->name, "progs/v_", 8)) { + if (strnequal (mod->path, "progs/v_", 8)) { mod->min_light = 0.12; - } else if (strequal (mod->name, "progs/player.mdl")) { + } else if (strequal (mod->path, "progs/player.mdl")) { mod->min_light = 0.04; } if (mod_funcs) @@ -309,7 +306,7 @@ Mod_Print (void) Sys_Printf ("Cached models:\n"); for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) { - Sys_Printf ("%8p : %s\n", (*mod)->cache.data, (*mod)->name); + Sys_Printf ("%8p : %s\n", (*mod)->cache.data, (*mod)->path); } } diff --git a/libs/models/sprite/gl_model_sprite.c b/libs/models/sprite/gl_model_sprite.c index 1d5d1597c..2abef1dfc 100644 --- a/libs/models/sprite/gl_model_sprite.c +++ b/libs/models/sprite/gl_model_sprite.c @@ -44,12 +44,13 @@ #include "mod_internal.h" void -gl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum) +gl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum) { tex_t *targa; const char *name; - targa = LoadImage (name = va (0, "%s_%i", loadmodel->name, framenum), 1); + targa = LoadImage (name = va (0, "%s_%i", mod->path, framenum), 1); if (targa) { if (targa->format < 4) pspriteframe->gl_texturenum = GL_LoadTexture (name, diff --git a/libs/models/sprite/glsl_model_sprite.c b/libs/models/sprite/glsl_model_sprite.c index 138b3d0d0..b5781124f 100644 --- a/libs/models/sprite/glsl_model_sprite.c +++ b/libs/models/sprite/glsl_model_sprite.c @@ -71,12 +71,13 @@ glsl_sprite_clear (model_t *m, void *data) } void -glsl_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum) +glsl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum) { const char *name; - loadmodel->clear = glsl_sprite_clear; - name = va (0, "%s_%i", loadmodel->name, framenum); + mod->clear = glsl_sprite_clear; + name = va (0, "%s_%i", mod->path, framenum); pspriteframe->gl_texturenum = GLSL_LoadQuakeTexture (name, pspriteframe->width, pspriteframe->height, pspriteframe->pixels); diff --git a/libs/models/sprite/model_sprite.c b/libs/models/sprite/model_sprite.c index ce962fec4..e4806bf6e 100644 --- a/libs/models/sprite/model_sprite.c +++ b/libs/models/sprite/model_sprite.c @@ -42,7 +42,8 @@ #include "mod_internal.h" static void * -Mod_LoadSpriteFrame (void *pin, mspriteframe_t **ppframe, int framenum) +Mod_LoadSpriteFrame (model_t *mod, void *pin, mspriteframe_t **ppframe, + int framenum) { dspriteframe_t *pinframe; int width, height, size, origin[2]; @@ -54,7 +55,7 @@ Mod_LoadSpriteFrame (void *pin, mspriteframe_t **ppframe, int framenum) height = LittleLong (pinframe->height); size = width * height; - pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t) + size, loadname); + pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t) + size, mod->name); memset (pspriteframe, 0, sizeof (mspriteframe_t) + size); @@ -72,13 +73,14 @@ Mod_LoadSpriteFrame (void *pin, mspriteframe_t **ppframe, int framenum) memcpy (pspriteframe->pixels, (byte *) (pinframe + 1), size); - m_funcs->Mod_SpriteLoadTexture (pspriteframe, framenum); + m_funcs->Mod_SpriteLoadTexture (mod, pspriteframe, framenum); return (void *) ((byte *) pinframe + sizeof (dspriteframe_t) + size); } static void * -Mod_LoadSpriteGroup (void *pin, mspriteframe_t **ppframe, int framenum) +Mod_LoadSpriteGroup (model_t *mod, void *pin, mspriteframe_t **ppframe, + int framenum) { dspritegroup_t *pingroup; dspriteinterval_t *pin_intervals; @@ -92,7 +94,8 @@ Mod_LoadSpriteGroup (void *pin, mspriteframe_t **ppframe, int framenum) numframes = LittleLong (pingroup->numframes); pspritegroup = Hunk_AllocName (field_offset (mspritegroup_t, - frames[numframes]), loadname); + frames[numframes]), + mod->name); pspritegroup->numframes = numframes; @@ -100,7 +103,7 @@ Mod_LoadSpriteGroup (void *pin, mspriteframe_t **ppframe, int framenum) pin_intervals = (dspriteinterval_t *) (pingroup + 1); - poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname); + poutintervals = Hunk_AllocName (numframes * sizeof (float), mod->name); pspritegroup->intervals = poutintervals; @@ -117,7 +120,7 @@ Mod_LoadSpriteGroup (void *pin, mspriteframe_t **ppframe, int framenum) for (i = 0; i < numframes; i++) { ptemp = - Mod_LoadSpriteFrame (ptemp, &pspritegroup->frames[i], + Mod_LoadSpriteFrame (mod, ptemp, &pspritegroup->frames[i], framenum * 100 + i); } @@ -136,14 +139,14 @@ Mod_LoadSpriteModel (model_t *mod, void *buffer) version = LittleLong (pin->version); if (version != SPR_VERSION) - Sys_Error ("%s has wrong version number " - "(%i should be %i)", mod->name, version, SPR_VERSION); + Sys_Error ("%s has wrong version number (%i should be %i)", + mod->path, version, SPR_VERSION); numframes = LittleLong (pin->numframes); size = field_offset (msprite_t, frames[numframes]); - psprite = Hunk_AllocName (size, loadname); + psprite = Hunk_AllocName (size, mod->name); mod->cache.data = psprite; @@ -175,11 +178,11 @@ Mod_LoadSpriteModel (model_t *mod, void *buffer) if (frametype == SPR_SINGLE) { pframetype = (dspriteframetype_t *) - Mod_LoadSpriteFrame (pframetype + 1, + Mod_LoadSpriteFrame (mod, pframetype + 1, &psprite->frames[i].frameptr, i); } else { pframetype = (dspriteframetype_t *) - Mod_LoadSpriteGroup (pframetype + 1, + Mod_LoadSpriteGroup (mod, pframetype + 1, &psprite->frames[i].frameptr, i); } } diff --git a/libs/models/sprite/sw_model_sprite.c b/libs/models/sprite/sw_model_sprite.c index 9d3f25bd2..8dc5a5461 100644 --- a/libs/models/sprite/sw_model_sprite.c +++ b/libs/models/sprite/sw_model_sprite.c @@ -31,6 +31,7 @@ #include "mod_internal.h" void -sw_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum) +sw_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum) { } diff --git a/libs/video/renderer/gl/gl_dyn_part.c b/libs/video/renderer/gl/gl_dyn_part.c index c3b0ddf68..5f510b26c 100644 --- a/libs/video/renderer/gl/gl_dyn_part.c +++ b/libs/video/renderer/gl/gl_dyn_part.c @@ -205,7 +205,7 @@ gl_R_ReadPointFile_f (void) vec3_t org; QFile *f; - mapname = strdup (r_worldentity.model->name); + mapname = strdup (r_worldentity.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); diff --git a/libs/video/renderer/gl/gl_lightmap.c b/libs/video/renderer/gl/gl_lightmap.c index 9dfa3df92..6eed72124 100644 --- a/libs/video/renderer/gl/gl_lightmap.c +++ b/libs/video/renderer/gl/gl_lightmap.c @@ -585,7 +585,7 @@ gl_overbright_f (cvar_t *var) if (m->type != mod_brush) continue; - if (m->name[0] == '*') + if (m->path[0] == '*') continue; for (j = 0, fa = m->surfaces; j < m->numsurfaces; j++, fa++) { @@ -732,7 +732,7 @@ GL_BuildLightmaps (model_t **models, int num_models) m = models[j]; if (!m) break; - if (m->name[0] == '*') { + if (m->path[0] == '*') { // sub model surfaces are processed as part of the main model continue; } diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index a47e6ba42..5946c98bd 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -226,7 +226,7 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) for (i = 0; i < num_models; i++) { if (!models[i]) continue; - if (*models[i]->name == '*') + if (*models[i]->path == '*') continue; if (models[i] != r_worldentity.model && models[i]->type == mod_brush) register_textures (models[i]); diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index 480c647a9..8a6ee73f5 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -436,7 +436,7 @@ glsl_R_RegisterTextures (model_t **models, int num_models) if (!m) continue; // sub-models are done as part of the main model - if (*m->name == '*') + if (*m->path == '*') continue; // world has already been done, not interested in non-brush models if (m == r_worldentity.model || m->type != mod_brush) @@ -561,7 +561,7 @@ glsl_R_BuildDisplayLists (model_t **models, int num_models) if (!m) continue; // sub-models are done as part of the main model - if (*m->name == '*') + if (*m->path == '*') continue; // non-bsp models don't have surfaces. dm = m->submodels; diff --git a/libs/video/renderer/glsl/glsl_lightmap.c b/libs/video/renderer/glsl/glsl_lightmap.c index b6f37142b..0776e015e 100644 --- a/libs/video/renderer/glsl/glsl_lightmap.c +++ b/libs/video/renderer/glsl/glsl_lightmap.c @@ -210,7 +210,7 @@ glsl_R_BuildLightmaps (model_t **models, int num_models) m = models[j]; if (!m) break; - if (m->name[0] == '*') { + if (m->path[0] == '*') { // sub model surfaces are processed as part of the main model continue; } @@ -231,7 +231,7 @@ glsl_R_BuildLightmaps (model_t **models, int num_models) m = models[j]; if (!m) break; - if (m->name[0] == '*') { + if (m->path[0] == '*') { // sub model surfaces are processed as part of the main model continue; } diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index 5a0dcd43a..139423bb7 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -313,7 +313,7 @@ glsl_R_ReadPointFile_f (void) vec3_t org; QFile *f; - mapname = strdup (r_worldentity.model->name); + mapname = strdup (r_worldentity.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); diff --git a/libs/video/renderer/sw/sw_ralias.c b/libs/video/renderer/sw/sw_ralias.c index a275873d3..d28e41b04 100644 --- a/libs/video/renderer/sw/sw_ralias.c +++ b/libs/video/renderer/sw/sw_ralias.c @@ -106,7 +106,7 @@ R_AliasCheckBBox (void) frame = currententity->frame; // TODO: don't repeat this check when drawing? if ((frame >= pmdl->numframes) || (frame < 0)) { - Sys_MaskPrintf (SYS_DEV, "No such frame %d %s\n", frame, pmodel->name); + Sys_MaskPrintf (SYS_DEV, "No such frame %d %s\n", frame, pmodel->path); frame = 0; } diff --git a/libs/video/renderer/sw/sw_rpart.c b/libs/video/renderer/sw/sw_rpart.c index c05281863..a5be06453 100644 --- a/libs/video/renderer/sw/sw_rpart.c +++ b/libs/video/renderer/sw/sw_rpart.c @@ -83,7 +83,7 @@ R_ReadPointFile_f (void) const char *name; char *mapname; - mapname = strdup (r_worldentity.model->name); + mapname = strdup (r_worldentity.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); diff --git a/libs/video/renderer/sw32/sw32_ralias.c b/libs/video/renderer/sw32/sw32_ralias.c index 167730ab1..4ead8055a 100644 --- a/libs/video/renderer/sw32/sw32_ralias.c +++ b/libs/video/renderer/sw32/sw32_ralias.c @@ -109,7 +109,7 @@ sw32_R_AliasCheckBBox (void) frame = currententity->frame; // TODO: don't repeat this check when drawing? if ((frame >= pmdl->numframes) || (frame < 0)) { - Sys_MaskPrintf (SYS_DEV, "No such frame %d %s\n", frame, pmodel->name); + Sys_MaskPrintf (SYS_DEV, "No such frame %d %s\n", frame, pmodel->path); frame = 0; } diff --git a/libs/video/renderer/sw32/sw32_rpart.c b/libs/video/renderer/sw32/sw32_rpart.c index 655467525..1364f5d1b 100644 --- a/libs/video/renderer/sw32/sw32_rpart.c +++ b/libs/video/renderer/sw32/sw32_rpart.c @@ -88,7 +88,7 @@ sw32_R_ReadPointFile_f (void) const char *name; char *mapname; - mapname = strdup (r_worldentity.model->name); + mapname = strdup (r_worldentity.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index fc8aebc11..3473a92cf 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -401,35 +401,35 @@ vulkan_r_particles_style_f (struct cvar_s *var) } static void -vulkan_Mod_LoadLighting (bsp_t *bsp) +vulkan_Mod_LoadLighting (model_t *mod, bsp_t *bsp) { - Vulkan_Mod_LoadLighting (bsp, vulkan_ctx); + Vulkan_Mod_LoadLighting (mod, bsp, vulkan_ctx); } static void -vulkan_Mod_SubdivideSurface (msurface_t *fa) +vulkan_Mod_SubdivideSurface (model_t *mod, msurface_t *fa) { } static void -vulkan_Mod_ProcessTexture (texture_t *tx) +vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx) { - Vulkan_Mod_ProcessTexture (tx, vulkan_ctx); + Vulkan_Mod_ProcessTexture (mod, tx, vulkan_ctx); } static void -vulkan_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, +vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, int _s, int extra) { - Vulkan_Mod_MakeAliasModelDisplayLists (m, hdr, _m, _s, extra, vulkan_ctx); + Vulkan_Mod_MakeAliasModelDisplayLists (mod, hdr, _m, _s, extra, vulkan_ctx); } static void * -vulkan_Mod_LoadSkin (byte *skin, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc) +vulkan_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, + int gnum, qboolean group, maliasskindesc_t *skindesc) { - return Vulkan_Mod_LoadSkin (skin, skinsize, snum, gnum, group, skindesc, - vulkan_ctx); + return Vulkan_Mod_LoadSkin (mod, skin, skinsize, snum, gnum, group, + skindesc, vulkan_ctx); } static void @@ -449,7 +449,8 @@ vulkan_Mod_IQMFinish (model_t *mod) } static void -vulkan_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum) +vulkan_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe, + int framenum) { } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index a923f854a..ff64990ee 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -280,7 +280,7 @@ Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx) if (!m) continue; // sub-models are done as part of the main model - if (*m->name == '*') + if (*m->path == '*') continue; // world has already been done, not interested in non-brush models if (m == r_worldentity.model || m->type != mod_brush) @@ -421,7 +421,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) if (!m) continue; // sub-models are done as part of the main model - if (*m->name == '*') + if (*m->path == '*') continue; // non-bsp models don't have surfaces. dm = m->submodels; diff --git a/libs/video/renderer/vulkan/vulkan_lightmap.c b/libs/video/renderer/vulkan/vulkan_lightmap.c index 0eeed8546..623bd9d94 100644 --- a/libs/video/renderer/vulkan/vulkan_lightmap.c +++ b/libs/video/renderer/vulkan/vulkan_lightmap.c @@ -228,7 +228,7 @@ Vulkan_BuildLightmaps (model_t **models, int num_models, vulkan_ctx_t *ctx) m = models[j]; if (!m) break; - if (m->name[0] == '*') { + if (m->path[0] == '*') { // sub model surfaces are processed as part of the main model continue; } @@ -251,7 +251,7 @@ Vulkan_BuildLightmaps (model_t **models, int num_models, vulkan_ctx_t *ctx) if (!m) { break; } - if (m->name[0] == '*') { + if (m->path[0] == '*') { // sub model surfaces are processed as part of the main model continue; } diff --git a/nq/source/cl_demo.c b/nq/source/cl_demo.c index 2b264d850..772778b92 100644 --- a/nq/source/cl_demo.c +++ b/nq/source/cl_demo.c @@ -338,7 +338,7 @@ demo_default_name (const char *argv1) strftime (timestring, 19, "%Y-%m-%d-%H-%M", localtime (&tim)); // the leading path-name is to be removed from cl.worldmodel->name - mapname = QFS_SkipPath (cl.worldmodel->name); + mapname = QFS_SkipPath (cl.worldmodel->path); // the map name is cut off after any "." because this would prevent // an extension being appended diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index 9424a670e..739e4a61c 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -408,7 +408,7 @@ CL_PrintEntities_f (void) continue; } Sys_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n", - ent->model->name, ent->frame, VectorExpand (ent->origin), + ent->model->path, ent->frame, VectorExpand (ent->origin), VectorExpand (ent->angles)); } } diff --git a/nq/source/sv_main.c b/nq/source/sv_main.c index 60ede5d87..9ee006e3b 100644 --- a/nq/source/sv_main.c +++ b/nq/source/sv_main.c @@ -1198,7 +1198,7 @@ SV_SpawnServer (const char *server) ent = EDICT_NUM (&sv_pr_state, 0); memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4); ent->free = false; - SVstring (ent, model) = PR_SetString (&sv_pr_state, sv.worldmodel->name); + SVstring (ent, model) = PR_SetString (&sv_pr_state, sv.worldmodel->path); SVfloat (ent, modelindex) = 1; // world model SVfloat (ent, solid) = SOLID_BSP; SVfloat (ent, movetype) = MOVETYPE_PUSH; diff --git a/qw/source/cl_demo.c b/qw/source/cl_demo.c index b6e0049e7..6151b6bd0 100644 --- a/qw/source/cl_demo.c +++ b/qw/source/cl_demo.c @@ -634,7 +634,7 @@ demo_default_name (const char *argv1) strftime (timestring, 19, "%Y-%m-%d-%H-%M", localtime (&tim)); // the leading path-name is to be removed from cl.worldmodel->name - mapname = QFS_SkipPath (cl.worldmodel->name); + mapname = QFS_SkipPath (cl.worldmodel->path); // the map name is cut off after any "." because this would prevent // an extension being appended diff --git a/qw/source/sbar.c b/qw/source/sbar.c index a7b3ab415..4a517887e 100644 --- a/qw/source/sbar.c +++ b/qw/source/sbar.c @@ -1108,7 +1108,7 @@ Sbar_LogFrags (void) if (t) Qwrite (file, t, strlen (t)); - Qprintf (file, "%s\n%s %s\n", cls.servername->str, cl.worldmodel->name, + Qprintf (file, "%s\n%s %s\n", cls.servername->str, cl.worldmodel->path, cl.levelname); // scores diff --git a/qw/source/sv_init.c b/qw/source/sv_init.c index 6e8b7bae5..8535dacb6 100644 --- a/qw/source/sv_init.c +++ b/qw/source/sv_init.c @@ -420,7 +420,7 @@ SV_SpawnServer (const char *server) ent = EDICT_NUM (&sv_pr_state, 0); ent->free = false; - SVstring (ent, model) = PR_SetString (&sv_pr_state, sv.worldmodel->name); + SVstring (ent, model) = PR_SetString (&sv_pr_state, sv.worldmodel->path); SVfloat (ent, modelindex) = 1; // world model SVfloat (ent, solid) = SOLID_BSP; SVfloat (ent, movetype) = MOVETYPE_PUSH; diff --git a/qw/source/teamplay.c b/qw/source/teamplay.c index b8158cbdb..e8a38606d 100644 --- a/qw/source/teamplay.c +++ b/qw/source/teamplay.c @@ -288,8 +288,8 @@ Team_NewMap (void) died = false; recorded_location = false; - mapname = strdup (cl.worldmodel->name); - t2 = malloc (sizeof (cl.worldmodel->name)); + mapname = strdup (cl.worldmodel->path); + t2 = malloc (sizeof (cl.worldmodel->path)); if (!mapname || !t2) Sys_Error ("Can't duplicate mapname!"); map_to_loc (mapname,t2); @@ -345,10 +345,10 @@ locs_loc (void) } if (Cmd_Argc () >= 3) desc = Cmd_Args (2); - mapname = malloc (sizeof (cl.worldmodel->name)); + mapname = malloc (sizeof (cl.worldmodel->path)); if (!mapname) Sys_Error ("Can't duplicate mapname!"); - map_to_loc (cl.worldmodel->name, mapname); + map_to_loc (cl.worldmodel->path, mapname); snprintf (locfile, sizeof (locfile), "%s/%s", qfs_gamedir->dir.def, mapname); free (mapname); From f02b35a20cfbbd26472600e77fcfd004a30e0e80 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 1 Feb 2021 15:02:42 +0900 Subject: [PATCH 317/435] [model] Clean up the model array a little Probably not really necessary, but I think I found a small opportunity for a buffer overflow in there while I was modifying the code, so this is probably better anyway. --- libs/models/model.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/libs/models/model.c b/libs/models/model.c index 7eb606930..4c2d4ac30 100644 --- a/libs/models/model.c +++ b/libs/models/model.c @@ -39,6 +39,7 @@ #endif #include "QF/cvar.h" +#include "QF/darray.h" #include "QF/iqm.h" #include "QF/model.h" #include "QF/qendian.h" @@ -53,9 +54,8 @@ vid_model_funcs_t *mod_funcs; #define MOD_BLOCK 16 // allocate 16 models at a time -model_t **mod_known; -int mod_numknown; -int mod_maxknown; +static struct DARRAY_TYPE (model_t *) mod_known = {0, 0, MOD_BLOCK}; +static size_t mod_numknown; VISIBLE texture_t *r_notexture_mip; @@ -115,10 +115,10 @@ Mod_Init_Cvars (void) VISIBLE void Mod_ClearAll (void) { - int i; + size_t i; model_t **mod; - for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) { + for (i = 0, mod = mod_known.a; i < mod_numknown; i++, mod++) { //FIXME this seems to be correct but need to double check the behavior //with alias models if (!(*mod)->needload && (*mod)->clear) { @@ -134,25 +134,24 @@ Mod_ClearAll (void) model_t * Mod_FindName (const char *name) { - int i; + size_t i; model_t **mod; if (!name[0]) Sys_Error ("Mod_FindName: empty name"); // search the currently loaded models - for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) + for (i = 0, mod = mod_known.a; i < mod_numknown; i++, mod++) if (!strcmp ((*mod)->path, name)) break; if (i == mod_numknown) { - if (mod_numknown == mod_maxknown) { - mod_maxknown += MOD_BLOCK; - mod_known = realloc (mod_known, mod_maxknown * sizeof (model_t *)); - mod = mod_known + mod_numknown; - *mod = calloc (MOD_BLOCK, sizeof (model_t)); - for (i = 1; i < MOD_BLOCK; i++) - mod[i] = mod[0] + i; + if (mod_numknown == mod_known.size) { + model_t *block = calloc (MOD_BLOCK, sizeof (model_t)); + for (i = 0; i < MOD_BLOCK; i++) { + DARRAY_APPEND (&mod_known, &block[i]); + } + mod = &mod_known.a[mod_numknown]; } memset ((*mod), 0, sizeof (model_t)); strncpy ((*mod)->path, name, sizeof (*mod)->path - 1); @@ -301,11 +300,11 @@ Mod_TouchModel (const char *name) VISIBLE void Mod_Print (void) { - int i; + size_t i; model_t **mod; Sys_Printf ("Cached models:\n"); - for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) { + for (i = 0, mod = mod_known.a; i < mod_numknown; i++, mod++) { Sys_Printf ("%8p : %s\n", (*mod)->cache.data, (*mod)->path); } } From 6969adf02c6a7209f70f91d0c8cdd6b73af2b8cb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 1 Feb 2021 19:19:18 +0900 Subject: [PATCH 318/435] [models] Fix black models with fullbrights in GL I had missed the breakage when I got vulkan alias model skins working. --- libs/models/gl_model_fullbright.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libs/models/gl_model_fullbright.c b/libs/models/gl_model_fullbright.c index ef94e59ca..60df0d50c 100644 --- a/libs/models/gl_model_fullbright.c +++ b/libs/models/gl_model_fullbright.c @@ -55,6 +55,13 @@ Mod_Fullbright (byte *skin, int width, int height, const char *name) // Check for fullbright pixels if (Mod_CalcFullbright (skin, ptexels, pixels)) { + //FIXME black should be transparent for fullbrights (or just fix + //fullbright rendering in gl) + for (int i = 0; i < pixels; i++) { + if (!ptexels[i]) { + ptexels[i] = 255; + } + } Sys_MaskPrintf (SYS_DEV, "FB Model ID: '%s'\n", name); texnum = GL_LoadTexture (name, width, height, ptexels, true, true, 1); } From 34dc7cf2df3253459c951508e61f6a5294b6dca0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 1 Feb 2021 19:31:11 +0900 Subject: [PATCH 319/435] [models] Move brush data into its own struct This is a big step towards a cleaner api. The struct reference in model_t really should be a pointer, but bsp submodel(?) loading messed that up, though that's just a matter of taking more care in the loading code. It seems sensible to make that a separate step. --- include/QF/GL/qf_lightmap.h | 2 +- include/QF/GLSL/qf_lightmap.h | 2 +- include/QF/Vulkan/qf_lightmap.h | 3 +- include/QF/model.h | 104 ++++----- include/QF/plugin/vid_render.h | 2 +- include/r_internal.h | 2 +- include/r_local.h | 8 +- libs/models/brush/gl_model_brush.c | 18 +- libs/models/brush/glsl_model_brush.c | 21 +- libs/models/brush/model_brush.c | 222 ++++++++++--------- libs/models/brush/sw_model_brush.c | 6 +- libs/models/brush/vulkan_model_brush.c | 36 +-- libs/video/renderer/gl/gl_lightmap.c | 46 ++-- libs/video/renderer/gl/gl_mod_alias.c | 2 +- libs/video/renderer/gl/gl_rmisc.c | 22 +- libs/video/renderer/gl/gl_rsurf.c | 53 ++--- libs/video/renderer/glsl/glsl_alias.c | 2 +- libs/video/renderer/glsl/glsl_bsp.c | 96 ++++---- libs/video/renderer/glsl/glsl_iqm.c | 2 +- libs/video/renderer/glsl/glsl_lightmap.c | 23 +- libs/video/renderer/glsl/namehack.h | 1 - libs/video/renderer/r_bsp.c | 6 +- libs/video/renderer/r_efrag.c | 4 +- libs/video/renderer/r_light.c | 34 +-- libs/video/renderer/sw/sw_rbsp.c | 40 ++-- libs/video/renderer/sw/sw_rdraw.c | 17 +- libs/video/renderer/sw/sw_rmain.c | 27 ++- libs/video/renderer/sw/sw_rsurf.c | 2 +- libs/video/renderer/sw32/sw32_rbsp.c | 40 ++-- libs/video/renderer/sw32/sw32_rdraw.c | 17 +- libs/video/renderer/sw32/sw32_rmain.c | 28 ++- libs/video/renderer/sw32/sw32_rsurf.c | 2 +- libs/video/renderer/vulkan/vulkan_alias.c | 2 +- libs/video/renderer/vulkan/vulkan_bsp.c | 96 ++++---- libs/video/renderer/vulkan/vulkan_lightmap.c | 21 +- nq/source/cl_chase.c | 2 +- nq/source/cl_ents.c | 6 +- nq/source/cl_parse.c | 6 +- nq/source/cl_tent.c | 4 +- nq/source/sv_main.c | 8 +- nq/source/sv_pr_cmds.c | 4 +- nq/source/world.c | 12 +- qw/source/cl_chase.c | 2 +- qw/source/cl_entparse.c | 2 +- qw/source/cl_ents.c | 10 +- qw/source/cl_parse.c | 8 +- qw/source/cl_tent.c | 6 +- qw/source/pmovetst.c | 6 +- qw/source/sv_ents.c | 6 +- qw/source/sv_init.c | 9 +- qw/source/sv_pr_cmds.c | 4 +- qw/source/sv_send.c | 9 +- qw/source/sv_user.c | 9 +- qw/source/world.c | 12 +- 54 files changed, 607 insertions(+), 527 deletions(-) diff --git a/include/QF/GL/qf_lightmap.h b/include/QF/GL/qf_lightmap.h index c048b181a..e0a05d4dd 100644 --- a/include/QF/GL/qf_lightmap.h +++ b/include/QF/GL/qf_lightmap.h @@ -50,6 +50,6 @@ void gl_lightmap_init (void); void GL_BuildLightmaps (struct model_s **models, int num_models); void R_BlendLightmaps (void); void R_CalcLightmaps (void); -extern void (*R_BuildLightMap) (msurface_t *surf); +extern void (*R_BuildLightMap) (mod_brush_t *brush, msurface_t *surf); #endif // __QF_GL_lightmap_h diff --git a/include/QF/GLSL/qf_lightmap.h b/include/QF/GLSL/qf_lightmap.h index 7619ed890..507eaeae6 100644 --- a/include/QF/GLSL/qf_lightmap.h +++ b/include/QF/GLSL/qf_lightmap.h @@ -36,7 +36,7 @@ void glsl_lightmap_init (void); void glsl_R_BuildLightmaps (struct model_s **models, int num_models); void glsl_R_CalcLightmaps (void); -extern void (*glsl_R_BuildLightMap) (msurface_t *surf); +extern void (*glsl_R_BuildLightMap) (mod_brush_t *brush, msurface_t *surf); int glsl_R_LightmapTexture (void) __attribute__((pure)); void glsl_R_FlushLightmaps (void); diff --git a/include/QF/Vulkan/qf_lightmap.h b/include/QF/Vulkan/qf_lightmap.h index 649a5b139..eaca4e35f 100644 --- a/include/QF/Vulkan/qf_lightmap.h +++ b/include/QF/Vulkan/qf_lightmap.h @@ -36,12 +36,13 @@ struct vulkan_ctx_s; struct model_s; +struct mod_brush_s; struct msurface_s; void Vulkan_lightmap_init (struct vulkan_ctx_s *ctx); void Vulkan_BuildLightmaps (struct model_s **models, int num_models, struct vulkan_ctx_s *ctx); void Vulkan_CalcLightmaps (struct vulkan_ctx_s *ctx); -void Vulkan_BuildLightMap (struct msurface_s *surf, struct vulkan_ctx_s *ctx); +void Vulkan_BuildLightMap (struct mod_brush_s *brush, struct msurface_s *surf, struct vulkan_ctx_s *ctx); VkImageView Vulkan_LightmapImageView (struct vulkan_ctx_s *ctx) __attribute__((pure)); void Vulkan_FlushLightmaps (struct vulkan_ctx_s *ctx); diff --git a/include/QF/model.h b/include/QF/model.h index c7fc9190f..6d7dfe61d 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -62,7 +62,6 @@ typedef struct efrag_s { struct efrag_s *entnext; } efrag_t; - // in memory representation =================================================== // !!! if this is changed, it must be changed in asm_draw.h too !!! @@ -228,6 +227,58 @@ typedef struct hull_s { int depth; ///< maximum depth of the tree } hull_t; +typedef struct mod_brush_s { + int firstmodelsurface, nummodelsurfaces; + + int numsubmodels; + dmodel_t *submodels; + + int numplanes; + plane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + mleaf_t *leafs; + + int numvertexes; + mvertex_t *vertexes; + + int numedges; + medge_t *edges; + + int numnodes; + mnode_t *nodes; + int depth; ///< maximum depth of the tree + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int numclipnodes; + mclipnode_t *clipnodes; + + int nummarksurfaces; + msurface_t **marksurfaces; + + hull_t hulls[MAX_MAP_HULLS]; + hull_t *hull_list[MAX_MAP_HULLS]; + + int numtextures; + texture_t **textures; + texture_t *skytexture; + + byte *visdata; + byte *lightdata; + char *entities; //FIXME should not be here + + unsigned int checksum; + unsigned int checksum2; +} mod_brush_t; + // SPRITE MODELS ============================================================== // FIXME: shorten these? @@ -375,55 +426,8 @@ typedef struct model_s { vec3_t clipmins, clipmaxs; // brush model - int firstmodelsurface, nummodelsurfaces; - - int numsubmodels; - dmodel_t *submodels; - - int numplanes; - plane_t *planes; - - int numleafs; // number of visible leafs, not counting 0 - mleaf_t *leafs; - - int numvertexes; - mvertex_t *vertexes; - - int numedges; - medge_t *edges; - - int numnodes; - mnode_t *nodes; - int depth; ///< maximum depth of the tree - - int numtexinfo; - mtexinfo_t *texinfo; - - int numsurfaces; - msurface_t *surfaces; - - int numsurfedges; - int *surfedges; - - int numclipnodes; - mclipnode_t *clipnodes; - - int nummarksurfaces; - msurface_t **marksurfaces; - - hull_t hulls[MAX_MAP_HULLS]; - hull_t *hull_list[MAX_MAP_HULLS]; - - int numtextures; - texture_t **textures; - texture_t *skytexture; - - byte *visdata; - byte *lightdata; - char *entities; - - unsigned int checksum; - unsigned int checksum2; + //FIXME should be a pointer (submodels make things tricky) + mod_brush_t brush; // additional model data cache_user_t cache; diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index cc634e562..bc80780e4 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -149,7 +149,7 @@ typedef struct vid_render_funcs_s { void (*R_ClearState) (void); void (*R_LoadSkys) (const char *); void (*R_NewMap) (model_t *worldmodel, model_t **models, int num_models); - void (*R_AddEfrags) (entity_t *ent); + void (*R_AddEfrags) (mod_brush_t *brush, entity_t *ent); void (*R_RemoveEfrags) (entity_t *ent); void (*R_EnqueueEntity) (struct entity_s *ent); //FIXME should not be here void (*R_LineGraph) (int x, int y, int *h_vals, int count); diff --git a/include/r_internal.h b/include/r_internal.h index 01c9af001..651946140 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -83,7 +83,7 @@ void R_RenderView (void); // must set r_refdef first void R_ViewChanged (float aspect); // must set r_refdef first // called whenever r_refdef or vid change -void R_AddEfrags (entity_t *ent); +void R_AddEfrags (mod_brush_t *, entity_t *ent); void R_RemoveEfrags (entity_t *ent); void R_NewMap (model_t *worldmodel, model_t **models, int num_models); diff --git a/include/r_local.h b/include/r_local.h index 4a3645ded..9e56b7343 100644 --- a/include/r_local.h +++ b/include/r_local.h @@ -182,7 +182,7 @@ void R_RemoveEdges (edge_t *pedge); void R_AddTexture (texture_t *tex); struct vulkan_ctx_s; void R_ClearTextures (void); -void R_InitSurfaceChains (model_t *model); +void R_InitSurfaceChains (mod_brush_t *brush); extern void R_Surf8Start (void); extern void R_Surf8End (void); @@ -303,13 +303,13 @@ void R_ZGraph (void); void R_PrintAliasStats (void); void R_PrintTimes (void); void R_AnimateLight (void); -int R_LightPoint (const vec3_t p); +int R_LightPoint (mod_brush_t *brush, const vec3_t p); void R_SetupFrame (void); void R_cshift_f (void); void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1); void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip); -void R_RecursiveMarkLights (const vec3_t lightorigin, struct dlight_s *light, - int bit, mnode_t *node); +void R_RecursiveMarkLights (mod_brush_t *brush, const vec3_t lightorigin, + struct dlight_s *light, int bit, mnode_t *node); void R_MarkLights (const vec3_t lightorigin, struct dlight_s *light, int bit, model_t *model); diff --git a/libs/models/brush/gl_model_brush.c b/libs/models/brush/gl_model_brush.c index 05b3c0b94..9585bb108 100644 --- a/libs/models/brush/gl_model_brush.c +++ b/libs/models/brush/gl_model_brush.c @@ -150,9 +150,10 @@ gl_Mod_LoadLighting (model_t *mod, bsp_t *bsp) size_t i; int ver; QFile *lit_file; + mod_brush_t *brush = &mod->brush; dstring_copystr (litfilename, mod->path); - mod->lightdata = NULL; + brush->lightdata = NULL; if (mod_lightmap_bytes > 1) { // LordHavoc: check for a .lit file to load QFS_StripExtension (litfilename->str, litfilename->str); @@ -165,7 +166,7 @@ gl_Mod_LoadLighting (model_t *mod, bsp_t *bsp) ver = LittleLong (((int32_t *) data)[1]); if (ver == 1) { Sys_MaskPrintf (SYS_DEV, "%s loaded", litfilename->str); - mod->lightdata = data + 8; + brush->lightdata = data + 8; return; } else Sys_MaskPrintf (SYS_DEV, @@ -179,10 +180,10 @@ gl_Mod_LoadLighting (model_t *mod, bsp_t *bsp) dstring_delete (litfilename); return; } - mod->lightdata = Hunk_AllocName (bsp->lightdatasize * mod_lightmap_bytes, - litfilename->str); + brush->lightdata = Hunk_AllocName (bsp->lightdatasize * mod_lightmap_bytes, + litfilename->str); in = bsp->lightdata; - out = mod->lightdata; + out = brush->lightdata; if (mod_lightmap_bytes > 1) for (i = 0; i < bsp->lightdatasize ; i++) { @@ -308,18 +309,19 @@ gl_Mod_SubdivideSurface (model_t *mod, msurface_t *fa) float *vec; int lindex, numverts, i; vec3_t verts[64]; + mod_brush_t *brush = &mod->brush; warpface = fa; // convert edges back to a normal polygon numverts = 0; for (i = 0; i < fa->numedges; i++) { - lindex = mod->surfedges[fa->firstedge + i]; + lindex = brush->surfedges[fa->firstedge + i]; if (lindex > 0) - vec = mod->vertexes[mod->edges[lindex].v[0]].position; + vec = brush->vertexes[brush->edges[lindex].v[0]].position; else - vec = mod->vertexes[mod->edges[-lindex].v[1]].position; + vec = brush->vertexes[brush->edges[-lindex].v[1]].position; VectorCopy (vec, verts[numverts]); numverts++; } diff --git a/libs/models/brush/glsl_model_brush.c b/libs/models/brush/glsl_model_brush.c index 3a2717f57..f44327acd 100644 --- a/libs/models/brush/glsl_model_brush.c +++ b/libs/models/brush/glsl_model_brush.c @@ -65,13 +65,14 @@ static void glsl_brush_clear (model_t *m, void *data) { int i; + mod_brush_t *brush = &m->brush; m->needload = true; - for (i = 0; i < m->numtextures; i++) { + for (i = 0; i < brush->numtextures; i++) { // NOTE: some maps (eg e1m2) have empty texture slots glsltex_t *tex = 0; - if (m->textures[i]) { - tex = m->textures[i]->render; + if (brush->textures[i]) { + tex = brush->textures[i]->render; } if (tex && tex->gl_texturenum) { GLSL_ReleaseTexture (tex->gl_texturenum); @@ -80,10 +81,10 @@ glsl_brush_clear (model_t *m, void *data) tex->gl_texturenum = 0; } } - for (i = 0; i < m->numsurfaces; i++) { - if (m->surfaces[i].polys) { - free (m->surfaces[i].polys); - m->surfaces[i].polys = 0; + for (i = 0; i < brush->numsurfaces; i++) { + if (brush->surfaces[i].polys) { + free (brush->surfaces[i].polys); + brush->surfaces[i].polys = 0; } } } @@ -151,9 +152,9 @@ glsl_Mod_LoadLighting (model_t *mod, bsp_t *bsp) mod->clear = glsl_brush_clear; mod_lightmap_bytes = 1; if (!bsp->lightdatasize) { - mod->lightdata = NULL; + mod->brush.lightdata = NULL; return; } - mod->lightdata = Hunk_AllocName (bsp->lightdatasize, mod->name); - memcpy (mod->lightdata, bsp->lightdata, bsp->lightdatasize); + mod->brush.lightdata = Hunk_AllocName (bsp->lightdatasize, mod->name); + memcpy (mod->brush.lightdata, bsp->lightdata, bsp->lightdatasize); } diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index 38a33c893..8a703050d 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -67,10 +67,10 @@ Mod_PointInLeaf (const vec3_t p, model_t *model) mnode_t *node; plane_t *plane; - if (!model || !model->nodes) + if (!model || !model->brush.nodes) Sys_Error ("Mod_PointInLeaf: bad model"); - node = model->nodes; + node = model->brush.nodes; while (1) { if (node->contents < 0) return (mleaf_t *) node; @@ -86,13 +86,13 @@ Mod_PointInLeaf (const vec3_t p, model_t *model) } static inline byte * -Mod_DecompressVis (byte * in, model_t *model) +Mod_DecompressVis (byte * in, mod_brush_t *brush) { static byte decompressed[MAX_MAP_LEAFS / 8]; byte *out; int row, c; - row = (model->numleafs + 7) >> 3; + row = (brush->numleafs + 7) >> 3; out = decompressed; if (!in) { // no vis info, so make all visible @@ -123,13 +123,13 @@ Mod_DecompressVis (byte * in, model_t *model) VISIBLE byte * Mod_LeafPVS (mleaf_t *leaf, model_t *model) { - if (leaf == model->leafs) { + if (leaf == model->brush.leafs) { if (!mod_novis[0]) { memset (mod_novis, 0xff, sizeof (mod_novis)); } return mod_novis; } - return Mod_DecompressVis (leaf->compressed_vis, model); + return Mod_DecompressVis (leaf->compressed_vis, &model->brush); } // BRUSHMODEL LOADING ========================================================= @@ -170,16 +170,17 @@ Mod_LoadTextures (model_t *mod, bsp_t *bsp) miptex_t *mt; texture_t *tx, *tx2; texture_t *anims[10], *altanims[10]; + mod_brush_t *brush = &mod->brush; if (!bsp->texdatasize) { - mod->textures = NULL; + brush->textures = NULL; return; } m = (dmiptexlump_t *) bsp->texdata; - mod->numtextures = m->nummiptex; - mod->textures = Hunk_AllocName (m->nummiptex * sizeof (*mod->textures), - mod->name); + brush->numtextures = m->nummiptex; + brush->textures = Hunk_AllocName (m->nummiptex * sizeof (*brush->textures), + mod->name); for (i = 0; i < m->nummiptex; i++) { if (m->dataofs[i] == -1) @@ -195,10 +196,10 @@ Mod_LoadTextures (model_t *mod, bsp_t *bsp) pixels = mt->width * mt->height / 64 * 85; tx = Hunk_AllocName (sizeof (texture_t) + pixels, mod->name); - mod->textures[i] = tx; + brush->textures[i] = tx; tx->name = strndup(mt->name, sizeof (mt->name)); - mod_unique_miptex_name (mod->textures, tx, i); + mod_unique_miptex_name (brush->textures, tx, i); tx->width = mt->width; tx->height = mt->height; for (j = 0; j < MIPLEVELS; j++) @@ -208,7 +209,7 @@ Mod_LoadTextures (model_t *mod, bsp_t *bsp) memcpy (tx + 1, mt + 1, pixels); if (!strncmp (mt->name, "sky", 3)) - mod->skytexture = tx; + brush->skytexture = tx; } if (mod_funcs && mod_funcs->Mod_ProcessTexture) { size_t render_size = mod_funcs->texture_render_size; @@ -218,7 +219,7 @@ Mod_LoadTextures (model_t *mod, bsp_t *bsp) mod->name); } for (i = 0; i < m->nummiptex; i++) { - tx = mod->textures[i]; + tx = brush->textures[i]; tx->render = render_data; render_data += render_size; mod_funcs->Mod_ProcessTexture (mod, tx); @@ -229,7 +230,7 @@ Mod_LoadTextures (model_t *mod, bsp_t *bsp) // sequence the animations for (i = 0; i < m->nummiptex; i++) { - tx = mod->textures[i]; + tx = brush->textures[i]; if (!tx || tx->name[0] != '+') continue; if (tx->anim_next) @@ -256,7 +257,7 @@ Mod_LoadTextures (model_t *mod, bsp_t *bsp) Sys_Error ("Bad animating texture %s", tx->name); for (j = i + 1; j < m->nummiptex; j++) { - tx2 = mod->textures[j]; + tx2 = brush->textures[j]; if (!tx2 || tx2->name[0] != '+') continue; if (strcmp (tx2->name + 2, tx->name + 2)) @@ -310,22 +311,22 @@ static void Mod_LoadVisibility (model_t *mod, bsp_t *bsp) { if (!bsp->visdatasize) { - mod->visdata = NULL; + mod->brush.visdata = NULL; return; } - mod->visdata = Hunk_AllocName (bsp->visdatasize, mod->name); - memcpy (mod->visdata, bsp->visdata, bsp->visdatasize); + mod->brush.visdata = Hunk_AllocName (bsp->visdatasize, mod->name); + memcpy (mod->brush.visdata, bsp->visdata, bsp->visdatasize); } static void Mod_LoadEntities (model_t *mod, bsp_t *bsp) { if (!bsp->entdatasize) { - mod->entities = NULL; + mod->brush.entities = NULL; return; } - mod->entities = Hunk_AllocName (bsp->entdatasize, mod->name); - memcpy (mod->entities, bsp->entdata, bsp->entdatasize); + mod->brush.entities = Hunk_AllocName (bsp->entdatasize, mod->name); + memcpy (mod->brush.entities, bsp->entdata, bsp->entdatasize); } static void @@ -339,8 +340,8 @@ Mod_LoadVertexes (model_t *mod, bsp_t *bsp) count = bsp->numvertexes; out = Hunk_AllocName (count * sizeof (*out), mod->name); - mod->vertexes = out; - mod->numvertexes = count; + mod->brush.vertexes = out; + mod->brush.numvertexes = count; for (i = 0; i < count; i++, in++, out++) VectorCopy (in->point, out->position); @@ -351,13 +352,14 @@ Mod_LoadSubmodels (model_t *mod, bsp_t *bsp) { dmodel_t *in, *out; int count, i, j; + mod_brush_t *brush = &mod->brush; in = bsp->models; count = bsp->nummodels; out = Hunk_AllocName (count * sizeof (*out), mod->name); - mod->submodels = out; - mod->numsubmodels = count; + brush->submodels = out; + brush->numsubmodels = count; for (i = 0; i < count; i++, in++, out++) { static vec3_t offset = {1, 1, 1}; @@ -372,7 +374,7 @@ Mod_LoadSubmodels (model_t *mod, bsp_t *bsp) out->numfaces = in->numfaces; } - out = mod->submodels; + out = brush->submodels; if (out->visleafs > MAX_MAP_LEAFS) { Sys_Error ("Mod_LoadSubmodels: too many visleafs (%d, max = %d) in %s", @@ -396,8 +398,8 @@ Mod_LoadEdges (model_t *mod, bsp_t *bsp) count = bsp->numedges; out = Hunk_AllocName ((count + 1) * sizeof (*out), mod->name); - mod->edges = out; - mod->numedges = count; + mod->brush.edges = out; + mod->brush.numedges = count; for (i = 0; i < count; i++, in++, out++) { out->v[0] = in->v[0]; @@ -417,8 +419,8 @@ Mod_LoadTexinfo (model_t *mod, bsp_t *bsp) count = bsp->numtexinfo; out = Hunk_AllocName (count * sizeof (*out), mod->name); - mod->texinfo = out; - mod->numtexinfo = count; + mod->brush.texinfo = out; + mod->brush.numtexinfo = count; for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 4; j++) { @@ -441,13 +443,13 @@ Mod_LoadTexinfo (model_t *mod, bsp_t *bsp) miptex = in->miptex; out->flags = in->flags; - if (!mod->textures) { + if (!mod->brush.textures) { out->texture = r_notexture_mip; // checkerboard texture out->flags = 0; } else { - if (miptex >= mod->numtextures) - Sys_Error ("miptex >= mod->numtextures"); - out->texture = mod->textures[miptex]; + if (miptex >= mod->brush.numtextures) + Sys_Error ("miptex >= mod->brush.numtextures"); + out->texture = mod->brush.textures[miptex]; if (!out->texture) { out->texture = r_notexture_mip; // texture not found out->flags = 0; @@ -469,6 +471,7 @@ CalcSurfaceExtents (model_t *mod, msurface_t *s) int bmins[2], bmaxs[2]; mtexinfo_t *tex; mvertex_t *v; + mod_brush_t *brush = &mod->brush; mins[0] = mins[1] = 999999; maxs[0] = maxs[1] = -99999; @@ -476,11 +479,11 @@ CalcSurfaceExtents (model_t *mod, msurface_t *s) tex = s->texinfo; for (i = 0; i < s->numedges; i++) { - e = mod->surfedges[s->firstedge + i]; + e = brush->surfedges[s->firstedge + i]; if (e >= 0) - v = &mod->vertexes[mod->edges[e].v[0]]; + v = &brush->vertexes[brush->edges[e].v[0]]; else - v = &mod->vertexes[mod->edges[-e].v[1]]; + v = &brush->vertexes[brush->edges[-e].v[1]]; for (j = 0; j < 2; j++) { val = v->position[0] * tex->vecs[j][0] + @@ -512,6 +515,7 @@ Mod_LoadFaces (model_t *mod, bsp_t *bsp) dface_t *in; int count, planenum, side, surfnum, i; msurface_t *out; + mod_brush_t *brush = &mod->brush; in = bsp->faces; count = bsp->numfaces; @@ -522,8 +526,8 @@ Mod_LoadFaces (model_t *mod, bsp_t *bsp) "%i faces exceeds standard limit of 32767.\n", count); } - mod->surfaces = out; - mod->numsurfaces = count; + brush->surfaces = out; + brush->numsurfaces = count; for (surfnum = 0; surfnum < count; surfnum++, in++, out++) { out->firstedge = in->firstedge; @@ -535,9 +539,9 @@ Mod_LoadFaces (model_t *mod, bsp_t *bsp) if (side) out->flags |= SURF_PLANEBACK; - out->plane = mod->planes + planenum; + out->plane = brush->planes + planenum; - out->texinfo = mod->texinfo + in->texinfo; + out->texinfo = brush->texinfo + in->texinfo; CalcSurfaceExtents (mod, out); @@ -549,7 +553,7 @@ Mod_LoadFaces (model_t *mod, bsp_t *bsp) if (i == -1) out->samples = NULL; else - out->samples = mod->lightdata + (i * mod_lightmap_bytes); + out->samples = brush->lightdata + (i * mod_lightmap_bytes); // set the drawing flags flag if (!out->texinfo->texture || !out->texinfo->texture->name) @@ -596,6 +600,7 @@ Mod_LoadNodes (model_t *mod, bsp_t *bsp) dnode_t *in; int count, i, j, p; mnode_t *out; + mod_brush_t *brush = &mod->brush; in = bsp->nodes; count = bsp->numnodes; @@ -606,8 +611,8 @@ Mod_LoadNodes (model_t *mod, bsp_t *bsp) "%i nodes exceeds standard limit of 32767.\n", count); } - mod->nodes = out; - mod->numnodes = count; + brush->nodes = out; + brush->numnodes = count; for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 3; j++) { @@ -616,7 +621,7 @@ Mod_LoadNodes (model_t *mod, bsp_t *bsp) } p = in->planenum; - out->plane = mod->planes + p; + out->plane = brush->planes + p; out->firstsurface = in->firstface; out->numsurfaces = in->numfaces; @@ -625,23 +630,23 @@ Mod_LoadNodes (model_t *mod, bsp_t *bsp) p = in->children[j]; // this check is for extended bsp 29 files if (p >= 0) { - out->children[j] = mod->nodes + p; + out->children[j] = brush->nodes + p; } else { p = ~p; - if (p < mod->numleafs) { - out->children[j] = (mnode_t *) (mod->leafs + p); + if (p < brush->numleafs) { + out->children[j] = (mnode_t *) (brush->leafs + p); } else { Sys_Printf ("Mod_LoadNodes: invalid leaf index %i " "(file has only %i leafs)\n", p, - mod->numleafs); + brush->numleafs); //map it to the solid leaf - out->children[j] = (mnode_t *)(mod->leafs); + out->children[j] = (mnode_t *)(brush->leafs); } } } } - Mod_SetParent (mod->nodes, NULL); // sets nodes and leafs + Mod_SetParent (brush->nodes, NULL); // sets nodes and leafs } static void @@ -651,13 +656,14 @@ Mod_LoadLeafs (model_t *mod, bsp_t *bsp) int count, i, j, p; mleaf_t *out; qboolean isnotmap = true; + mod_brush_t *brush = &mod->brush; in = bsp->leafs; count = bsp->numleafs; out = Hunk_AllocName (count * sizeof (*out), mod->name); - mod->leafs = out; - mod->numleafs = count; + brush->leafs = out; + brush->numleafs = count; // snprintf(s, sizeof (s), "maps/%s.bsp", // Info_ValueForKey(cl.serverinfo,"map")); if (!strncmp ("maps/", mod->path, 5)) @@ -671,14 +677,14 @@ Mod_LoadLeafs (model_t *mod, bsp_t *bsp) p = in->contents; out->contents = p; - out->firstmarksurface = mod->marksurfaces + in->firstmarksurface; + out->firstmarksurface = brush->marksurfaces + in->firstmarksurface; out->nummarksurfaces = in->nummarksurfaces; p = in->visofs; if (p == -1) out->compressed_vis = NULL; else - out->compressed_vis = mod->visdata + p; + out->compressed_vis = brush->visdata + p; out->efrags = NULL; for (j = 0; j < 4; j++) @@ -703,6 +709,7 @@ Mod_LoadClipnodes (model_t *mod, bsp_t *bsp) mclipnode_t *out; hull_t *hull; int count, i; + mod_brush_t *brush = &mod->brush; in = bsp->clipnodes; count = bsp->numclipnodes; @@ -714,15 +721,15 @@ Mod_LoadClipnodes (model_t *mod, bsp_t *bsp) count); } - mod->clipnodes = out; - mod->numclipnodes = count; + brush->clipnodes = out; + brush->numclipnodes = count; - hull = &mod->hulls[1]; - mod->hull_list[1] = hull; + hull = &brush->hulls[1]; + brush->hull_list[1] = hull; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count - 1; - hull->planes = mod->planes; + hull->planes = brush->planes; hull->clip_mins[0] = -16; hull->clip_mins[1] = -16; hull->clip_mins[2] = -24; @@ -730,12 +737,12 @@ Mod_LoadClipnodes (model_t *mod, bsp_t *bsp) hull->clip_maxs[1] = 16; hull->clip_maxs[2] = 32; - hull = &mod->hulls[2]; - mod->hull_list[2] = hull; + hull = &brush->hulls[2]; + brush->hull_list[2] = hull; hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count - 1; - hull->planes = mod->planes; + hull->planes = brush->planes; hull->clip_mins[0] = -32; hull->clip_mins[1] = -32; hull->clip_mins[2] = -24; @@ -745,7 +752,7 @@ Mod_LoadClipnodes (model_t *mod, bsp_t *bsp) for (i = 0; i < count; i++, out++, in++) { out->planenum = in->planenum; - if (out->planenum < 0 || out->planenum >= mod->numplanes) + if (out->planenum < 0 || out->planenum >= brush->numplanes) Sys_Error ("Mod_LoadClipnodes: planenum out of bounds"); out->children[0] = in->children[0]; out->children[1] = in->children[1]; @@ -776,27 +783,28 @@ Mod_MakeHull0 (model_t *mod) hull_t *hull; int count, i, j; mnode_t *in, *child; + mod_brush_t *brush = &mod->brush; - hull = &mod->hulls[0]; - mod->hull_list[0] = hull; + hull = &brush->hulls[0]; + brush->hull_list[0] = hull; - in = mod->nodes; - count = mod->numnodes; + in = brush->nodes; + count = brush->numnodes; out = Hunk_AllocName (count * sizeof (*out), mod->name); hull->clipnodes = out; hull->firstclipnode = 0; hull->lastclipnode = count - 1; - hull->planes = mod->planes; + hull->planes = brush->planes; for (i = 0; i < count; i++, out++, in++) { - out->planenum = in->plane - mod->planes; + out->planenum = in->plane - brush->planes; for (j = 0; j < 2; j++) { child = in->children[j]; if (child->contents < 0) out->children[j] = child->contents; else - out->children[j] = child - mod->nodes; + out->children[j] = child - brush->nodes; } } } @@ -807,6 +815,7 @@ Mod_LoadMarksurfaces (model_t *mod, bsp_t *bsp) int count, i, j; msurface_t **out; uint32_t *in; + mod_brush_t *brush = &mod->brush; in = bsp->marksurfaces; count = bsp->nummarksurfaces; @@ -818,14 +827,14 @@ Mod_LoadMarksurfaces (model_t *mod, bsp_t *bsp) count); } - mod->marksurfaces = out; - mod->nummarksurfaces = count; + brush->marksurfaces = out; + brush->nummarksurfaces = count; for (i = 0; i < count; i++) { j = in[i]; - if (j >= mod->numsurfaces) + if (j >= brush->numsurfaces) Sys_Error ("Mod_ParseMarksurfaces: bad surface number"); - out[i] = mod->surfaces + j; + out[i] = brush->surfaces + j; } } @@ -835,13 +844,14 @@ Mod_LoadSurfedges (model_t *mod, bsp_t *bsp) int count, i; int32_t *in; int *out; + mod_brush_t *brush = &mod->brush; in = bsp->surfedges; count = bsp->numsurfedges; out = Hunk_AllocName (count * sizeof (*out), mod->name); - mod->surfedges = out; - mod->numsurfedges = count; + brush->surfedges = out; + brush->numsurfedges = count; for (i = 0; i < count; i++) out[i] = in[i]; @@ -853,13 +863,14 @@ Mod_LoadPlanes (model_t *mod, bsp_t *bsp) dplane_t *in; int bits, count, i, j; plane_t *out; + mod_brush_t *brush = &mod->brush; in = bsp->planes; count = bsp->numplanes; out = Hunk_AllocName (count * 2 * sizeof (*out), mod->name); - mod->planes = out; - mod->numplanes = count; + brush->planes = out; + brush->numplanes = count; for (i = 0; i < count; i++, in++, out++) { bits = 0; @@ -881,12 +892,13 @@ do_checksums (const bsp_t *bsp, void *_mod) int i; model_t *mod = (model_t *) _mod; byte *base; + mod_brush_t *brush = &mod->brush; base = (byte *) bsp->header; // checksum all of the map, except for entities - mod->checksum = 0; - mod->checksum2 = 0; + brush->checksum = 0; + brush->checksum2 = 0; for (i = 0; i < HEADER_LUMPS; i++) { lump_t *lump = bsp->header->lumps + i; int csum; @@ -894,30 +906,30 @@ do_checksums (const bsp_t *bsp, void *_mod) if (i == LUMP_ENTITIES) continue; csum = Com_BlockChecksum (base + lump->fileofs, lump->filelen); - mod->checksum ^= csum; + brush->checksum ^= csum; if (i != LUMP_VISIBILITY && i != LUMP_LEAFS && i != LUMP_NODES) - mod->checksum2 ^= csum; + brush->checksum2 ^= csum; } } static void -recurse_draw_tree (model_t *mod, mnode_t *node, int depth) +recurse_draw_tree (mod_brush_t *brush, mnode_t *node, int depth) { if (!node || node->contents < 0) { - if (depth > mod->depth) - mod->depth = depth; + if (depth > brush->depth) + brush->depth = depth; return; } - recurse_draw_tree (mod, node->children[0], depth + 1); - recurse_draw_tree (mod, node->children[1], depth + 1); + recurse_draw_tree (brush, node->children[0], depth + 1); + recurse_draw_tree (brush, node->children[1], depth + 1); } static void -Mod_FindDrawDepth (model_t *mod) +Mod_FindDrawDepth (mod_brush_t *brush) { - mod->depth = 0; - recurse_draw_tree (mod, mod->nodes, 1); + brush->depth = 0; + recurse_draw_tree (brush, brush->nodes, 1); } void @@ -954,35 +966,35 @@ Mod_LoadBrushModel (model_t *mod, void *buffer) Mod_MakeHull0 (mod); - Mod_FindDrawDepth (mod); + Mod_FindDrawDepth (&mod->brush); for (i = 0; i < MAX_MAP_HULLS; i++) - Mod_FindClipDepth (&mod->hulls[i]); + Mod_FindClipDepth (&mod->brush.hulls[i]); mod->numframes = 2; // regular and alternate animation // set up the submodels (FIXME: this is confusing) - for (i = 0; i < mod->numsubmodels; i++) { - bm = &mod->submodels[i]; + for (i = 0; i < mod->brush.numsubmodels; i++) { + bm = &mod->brush.submodels[i]; - mod->hulls[0].firstclipnode = bm->headnode[0]; - mod->hull_list[0] = &mod->hulls[0]; + mod->brush.hulls[0].firstclipnode = bm->headnode[0]; + mod->brush.hull_list[0] = &mod->brush.hulls[0]; for (j = 1; j < MAX_MAP_HULLS; j++) { - mod->hulls[j].firstclipnode = bm->headnode[j]; - mod->hulls[j].lastclipnode = mod->numclipnodes - 1; - mod->hull_list[j] = &mod->hulls[j]; + mod->brush.hulls[j].firstclipnode = bm->headnode[j]; + mod->brush.hulls[j].lastclipnode = mod->brush.numclipnodes - 1; + mod->brush.hull_list[j] = &mod->brush.hulls[j]; } - mod->firstmodelsurface = bm->firstface; - mod->nummodelsurfaces = bm->numfaces; + mod->brush.firstmodelsurface = bm->firstface; + mod->brush.nummodelsurfaces = bm->numfaces; VectorCopy (bm->maxs, mod->maxs); VectorCopy (bm->mins, mod->mins); mod->radius = RadiusFromBounds (mod->mins, mod->maxs); - mod->numleafs = bm->visleafs; + mod->brush.numleafs = bm->visleafs; - if (i < mod->numsubmodels - 1) { + if (i < mod->brush.numsubmodels - 1) { // duplicate the basic information char name[12]; diff --git a/libs/models/brush/sw_model_brush.c b/libs/models/brush/sw_model_brush.c index 65a0e4e48..84080d49d 100644 --- a/libs/models/brush/sw_model_brush.c +++ b/libs/models/brush/sw_model_brush.c @@ -45,9 +45,9 @@ sw_Mod_LoadLighting (model_t *mod, bsp_t *bsp) { mod_lightmap_bytes = 1; if (!bsp->lightdatasize) { - mod->lightdata = NULL; + mod->brush.lightdata = NULL; return; } - mod->lightdata = Hunk_AllocName (bsp->lightdatasize, mod->name); - memcpy (mod->lightdata, bsp->lightdata, bsp->lightdatasize); + mod->brush.lightdata = Hunk_AllocName (bsp->lightdatasize, mod->name); + memcpy (mod->brush.lightdata, bsp->lightdata, bsp->lightdatasize); } diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index ce9fd1e7e..55eacb90b 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -69,9 +69,10 @@ static void vulkan_brush_clear (model_t *mod, void *data) vulkan_ctx_t *ctx = mctx->ctx; qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + mod_brush_t *brush = &mod->brush; - for (int i = 0; i < mod->numtextures; i++) { - texture_t *tx = mod->textures[i]; + for (int i = 0; i < brush->numtextures; i++) { + texture_t *tx = brush->textures[i]; if (!tx) { continue; } @@ -180,12 +181,13 @@ load_textures (model_t *mod, vulkan_ctx_t *ctx) modelctx_t *mctx = mod->data; VkImage image = 0; byte *buffer; + mod_brush_t *brush = &mod->brush; size_t image_count = 0; size_t copy_count = 0; size_t memsize = 0; - for (int i = 0; i < mod->numtextures; i++) { - texture_t *tx = mod->textures[i]; + for (int i = 0; i < brush->numtextures; i++) { + texture_t *tx = brush->textures[i]; if (!tx) { continue; } @@ -221,8 +223,8 @@ load_textures (model_t *mod, vulkan_ctx_t *ctx) qfv_packet_t *packet = QFV_PacketAcquire (stage); buffer = QFV_PacketExtend (packet, memsize); - for (int i = 0; i < mod->numtextures; i++) { - texture_t *tx = mod->textures[i]; + for (int i = 0; i < brush->numtextures; i++) { + texture_t *tx = brush->textures[i]; byte *palette = vid.palette32; if (!tx) { continue; @@ -275,8 +277,8 @@ load_textures (model_t *mod, vulkan_ctx_t *ctx) __auto_type barriers = QFV_AllocImageBarrierSet (image_count, malloc); barriers->size = 0; - for (int i = 0; i < mod->numtextures; i++) { - texture_t *tx = mod->textures[i]; + for (int i = 0; i < brush->numtextures; i++) { + texture_t *tx = brush->textures[i]; if (!tx) { continue; } @@ -296,8 +298,8 @@ load_textures (model_t *mod, vulkan_ctx_t *ctx) dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, barriers->size, barriers->a); - for (int i = 0, j = 0; i < mod->numtextures; i++) { - texture_t *tx = mod->textures[i]; + for (int i = 0, j = 0; i < brush->numtextures; i++) { + texture_t *tx = brush->textures[i]; if (!tx) { continue; } @@ -401,9 +403,11 @@ Vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx, vulkan_ctx_t *ctx) void Vulkan_Mod_LoadLighting (model_t *mod, bsp_t *bsp, vulkan_ctx_t *ctx) { + mod_brush_t *brush = &mod->brush; + mod_lightmap_bytes = 3; if (!bsp->lightdatasize) { - mod->lightdata = NULL; + brush->lightdata = NULL; return; } @@ -413,7 +417,7 @@ Vulkan_Mod_LoadLighting (model_t *mod, bsp_t *bsp, vulkan_ctx_t *ctx) int ver; QFile *lit_file; - mod->lightdata = 0; + brush->lightdata = 0; if (mod_lightmap_bytes > 1) { // LordHavoc: check for a .lit file to load dstring_t *litfilename = dstring_new (); @@ -428,7 +432,7 @@ Vulkan_Mod_LoadLighting (model_t *mod, bsp_t *bsp, vulkan_ctx_t *ctx) ver = LittleLong (((int32_t *) data)[1]); if (ver == 1) { Sys_MaskPrintf (SYS_DEV, "%s loaded", litfilename->str); - mod->lightdata = data + 8; + brush->lightdata = data + 8; } else { Sys_MaskPrintf (SYS_DEV, "Unknown .lit file version (%d)\n", ver); @@ -439,13 +443,13 @@ Vulkan_Mod_LoadLighting (model_t *mod, bsp_t *bsp, vulkan_ctx_t *ctx) } dstring_delete (litfilename); } - if (mod->lightdata || !bsp->lightdatasize) { + if (brush->lightdata || !bsp->lightdatasize) { return; } // LordHavoc: oh well, expand the white lighting data - mod->lightdata = Hunk_AllocName (bsp->lightdatasize * 3, mod->name); + brush->lightdata = Hunk_AllocName (bsp->lightdatasize * 3, mod->name); in = bsp->lightdata; - out = mod->lightdata; + out = brush->lightdata; for (i = 0; i < bsp->lightdatasize ; i++) { d = *in++; diff --git a/libs/video/renderer/gl/gl_lightmap.c b/libs/video/renderer/gl/gl_lightmap.c index 6eed72124..c6270f5d4 100644 --- a/libs/video/renderer/gl/gl_lightmap.c +++ b/libs/video/renderer/gl/gl_lightmap.c @@ -74,7 +74,7 @@ glRect_t gl_lightmap_rectchange[MAX_LIGHTMAPS]; static int lmshift = 7; -void (*gl_R_BuildLightMap) (msurface_t *surf); +void (*gl_R_BuildLightMap) (mod_brush_t *brush, msurface_t *surf); extern void gl_multitexture_f (cvar_t *var); @@ -240,7 +240,7 @@ R_AddDynamicLights_3 (msurface_t *surf) } static void -R_BuildLightMap_1 (msurface_t *surf) +R_BuildLightMap_1 (mod_brush_t *brush, msurface_t *surf) { byte *dest; int maps, size, stride, smax, tmax, i, j; @@ -254,7 +254,7 @@ R_BuildLightMap_1 (msurface_t *surf) size = smax * tmax * gl_internalformat; // set to full bright if no light data - if (!r_worldentity.model->lightdata) { + if (!brush->lightdata) { memset (&blocklights[0], 0xff, size * sizeof(int)); goto store; } @@ -300,7 +300,7 @@ R_BuildLightMap_1 (msurface_t *surf) } static void -R_BuildLightMap_3 (msurface_t *surf) +R_BuildLightMap_3 (mod_brush_t *brush, msurface_t *surf) { byte *dest; int maps, size, stride, smax, tmax, i, j; @@ -314,7 +314,7 @@ R_BuildLightMap_3 (msurface_t *surf) size = smax * tmax * gl_internalformat; // set to full bright if no light data - if (!r_worldentity.model->lightdata) { + if (!brush->lightdata) { memset (&blocklights[0], 0xff, size * sizeof(int)); goto store; } @@ -365,7 +365,7 @@ R_BuildLightMap_3 (msurface_t *surf) } static void -R_BuildLightMap_4 (msurface_t *surf) +R_BuildLightMap_4 (mod_brush_t *brush, msurface_t *surf) { byte *dest; int maps, size, smax, tmax, i, j, stride; @@ -379,7 +379,7 @@ R_BuildLightMap_4 (msurface_t *surf) size = smax * tmax * gl_internalformat; // set to full bright if no light data - if (!r_worldentity.model->lightdata) { + if (!brush->lightdata) { memset (&blocklights[0], 0xff, size * sizeof(int)); goto store; } @@ -535,6 +535,7 @@ gl_overbright_f (cvar_t *var) model_t *m; msurface_t *fa; entity_t *ent; + mod_brush_t *brush; if (!var) return; @@ -588,7 +589,8 @@ gl_overbright_f (cvar_t *var) if (m->path[0] == '*') continue; - for (j = 0, fa = m->surfaces; j < m->numsurfaces; j++, fa++) { + brush = &m->brush; + for (j = 0, fa = brush->surfaces; j < brush->numsurfaces; j++, fa++) { if (fa->flags & (SURF_DRAWTURB | SURF_DRAWSKY)) continue; @@ -599,13 +601,13 @@ gl_overbright_f (cvar_t *var) gl_lightmap_rectchange[num].w = BLOCK_WIDTH; gl_lightmap_rectchange[num].h = BLOCK_HEIGHT; - gl_R_BuildLightMap (fa); + gl_R_BuildLightMap (brush, fa); } } - m = r_worldentity.model; + brush = &r_worldentity.model->brush; - for (i = 0, fa = m->surfaces; i < m->numsurfaces; i++, fa++) { + for (i = 0, fa = brush->surfaces; i < brush->numsurfaces; i++, fa++) { if (fa->flags & (SURF_DRAWTURB | SURF_DRAWSKY)) continue; @@ -616,7 +618,7 @@ gl_overbright_f (cvar_t *var) gl_lightmap_rectchange[num].w = BLOCK_WIDTH; gl_lightmap_rectchange[num].h = BLOCK_HEIGHT; - gl_R_BuildLightMap (fa); + gl_R_BuildLightMap (brush, fa); } } @@ -665,7 +667,7 @@ AllocBlock (int w, int h, int *x, int *y) } static void -GL_CreateSurfaceLightmap (msurface_t *surf) +GL_CreateSurfaceLightmap (mod_brush_t *brush, msurface_t *surf) { int smax, tmax; @@ -677,7 +679,7 @@ GL_CreateSurfaceLightmap (msurface_t *surf) surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t); - gl_R_BuildLightMap (surf); + gl_R_BuildLightMap (brush, surf); } /* @@ -690,6 +692,7 @@ GL_BuildLightmaps (model_t **models, int num_models) { int i, j; model_t *m; + mod_brush_t *brush; memset (allocated, 0, sizeof (allocated)); @@ -732,21 +735,22 @@ GL_BuildLightmaps (model_t **models, int num_models) m = models[j]; if (!m) break; - if (m->path[0] == '*') { + if (m->path[0] == '*' || m->type != mod_brush) { // sub model surfaces are processed as part of the main model continue; } - r_pcurrentvertbase = m->vertexes; + brush = &m->brush; + r_pcurrentvertbase = brush->vertexes; gl_currentmodel = m; // non-bsp models don't have surfaces. - for (i = 0; i < m->numsurfaces; i++) { - if (m->surfaces[i].flags & SURF_DRAWTURB) + for (i = 0; i < brush->numsurfaces; i++) { + if (brush->surfaces[i].flags & SURF_DRAWTURB) continue; - if (gl_sky_divide->int_val && (m->surfaces[i].flags & + if (gl_sky_divide->int_val && (brush->surfaces[i].flags & SURF_DRAWSKY)) continue; - GL_CreateSurfaceLightmap (m->surfaces + i); - GL_BuildSurfaceDisplayList (m->surfaces + i); + GL_CreateSurfaceLightmap (brush, brush->surfaces + i); + GL_BuildSurfaceDisplayList (brush->surfaces + i); } } diff --git a/libs/video/renderer/gl/gl_mod_alias.c b/libs/video/renderer/gl/gl_mod_alias.c index 44a114ff5..d47a1504f 100644 --- a/libs/video/renderer/gl/gl_mod_alias.c +++ b/libs/video/renderer/gl/gl_mod_alias.c @@ -436,7 +436,7 @@ gl_R_DrawAliasModel (entity_t *e) float lightadj; // get lighting information - R_LightPoint (e->origin); + R_LightPoint (&r_worldentity.model->brush, e->origin); lightadj = (ambientcolor[0] + ambientcolor[1] + ambientcolor[2]) / 765.0; diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index 5946c98bd..5c61fd70d 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -167,13 +167,13 @@ gl_R_Init (void) } static void -register_textures (model_t *model) +register_textures (mod_brush_t *brush) { int i; texture_t *tex; - for (i = 0; i < model->numtextures; i++) { - tex = model->textures[i]; + for (i = 0; i < brush->numtextures; i++) { + tex = brush->textures[i]; if (!tex) continue; gl_R_AddTexture (tex); @@ -185,18 +185,20 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) { int i; texture_t *tex; + mod_brush_t *brush; for (i = 0; i < 256; i++) d_lightstylevalue[i] = 264; // normal light value memset (&r_worldentity, 0, sizeof (r_worldentity)); r_worldentity.model = worldmodel; + brush = &worldmodel->brush; R_FreeAllEntities (); // clear out efrags in case the level hasn't been reloaded - for (i = 0; i < r_worldentity.model->numleafs; i++) - r_worldentity.model->leafs[i].efrags = NULL; + for (i = 0; i < brush->numleafs; i++) + brush->leafs[i].efrags = NULL; // Force a vis update r_viewleaf = NULL; @@ -209,8 +211,8 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) // identify sky texture gl_mirrortexturenum = -1; gl_R_ClearTextures (); - for (i = 0; i < r_worldentity.model->numtextures; i++) { - tex = r_worldentity.model->textures[i]; + for (i = 0; i < brush->numtextures; i++) { + tex = brush->textures[i]; if (!tex) continue; if (!strncmp (tex->name, "sky", 3)) { @@ -220,16 +222,16 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) gl_mirrortexturenum = i; } - gl_R_InitSurfaceChains (r_worldentity.model); + gl_R_InitSurfaceChains (brush); gl_R_AddTexture (r_notexture_mip); - register_textures (r_worldentity.model); + register_textures (brush); for (i = 0; i < num_models; i++) { if (!models[i]) continue; if (*models[i]->path == '*') continue; if (models[i] != r_worldentity.model && models[i]->type == mod_brush) - register_textures (models[i]); + register_textures (&models[i]->brush); } } diff --git a/libs/video/renderer/gl/gl_rsurf.c b/libs/video/renderer/gl/gl_rsurf.c index f673e4cc4..acd9f4ad3 100644 --- a/libs/video/renderer/gl/gl_rsurf.c +++ b/libs/video/renderer/gl/gl_rsurf.c @@ -146,15 +146,15 @@ gl_R_AddTexture (texture_t *tx) } void -gl_R_InitSurfaceChains (model_t *model) +gl_R_InitSurfaceChains (mod_brush_t *brush) { int i; if (static_chains) free (static_chains); - static_chains = calloc (model->nummodelsurfaces, sizeof (instsurf_t)); - for (i = 0; i < model->nummodelsurfaces; i++) - model->surfaces[i].instsurf = static_chains + i; + static_chains = calloc (brush->nummodelsurfaces, sizeof (instsurf_t)); + for (i = 0; i < brush->nummodelsurfaces; i++) + brush->surfaces[i].instsurf = static_chains + i; release_instsurfs (); } @@ -267,7 +267,7 @@ R_RenderBrushPoly_1 (msurface_t *fa) } static inline void -R_AddToLightmapChain (msurface_t *fa) +R_AddToLightmapChain (mod_brush_t *brush, msurface_t *fa) { int maps, smax, tmax; glRect_t *theRect; @@ -306,7 +306,7 @@ R_AddToLightmapChain (msurface_t *fa) theRect->w = (fa->light_s - theRect->l) + smax; if ((theRect->h + theRect->t) < (fa->light_t + tmax)) theRect->h = (fa->light_t - theRect->t) + tmax; - gl_R_BuildLightMap (fa); + gl_R_BuildLightMap (brush, fa); } } } @@ -490,7 +490,8 @@ clear_texture_chains (void) } static inline void -chain_surface (msurface_t *surf, vec_t *transform, float *color) +chain_surface (mod_brush_t *brush, msurface_t *surf, vec_t *transform, + float *color) { instsurf_t *sc; @@ -509,7 +510,7 @@ chain_surface (msurface_t *surf, vec_t *transform, float *color) tex = tx->render; CHAIN_SURF_F2B (surf, tex->tex_chain); - R_AddToLightmapChain (surf); + R_AddToLightmapChain (brush, surf); } if (!(sc = surf->instsurf)) sc = surf->tinst; @@ -528,8 +529,10 @@ gl_R_DrawBrushModel (entity_t *e) msurface_t *psurf; qboolean rotated; vec3_t mins, maxs; + mod_brush_t *brush; model = e->model; + brush = &model->brush; if (e->transform[0] != 1 || e->transform[5] != 1 || e->transform[10] != 1) { rotated = true; @@ -565,7 +568,7 @@ gl_R_DrawBrushModel (entity_t *e) } // calculate dynamic lighting for bmodel if it's not an instanced model - if (model->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { + if (brush->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { vec3_t lightorigin; for (k = 0; k < r_maxdlights; k++) { @@ -574,8 +577,8 @@ gl_R_DrawBrushModel (entity_t *e) continue; VectorSubtract (r_dlights[k].origin, e->origin, lightorigin); - R_RecursiveMarkLights (lightorigin, &r_dlights[k], k, - model->nodes + model->hulls[0].firstclipnode); + R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, + brush->nodes + brush->hulls[0].firstclipnode); } } @@ -584,10 +587,10 @@ gl_R_DrawBrushModel (entity_t *e) qfglGetFloatv (GL_MODELVIEW_MATRIX, e->full_transform); qfglPopMatrix (); - psurf = &model->surfaces[model->firstmodelsurface]; + psurf = &brush->surfaces[brush->firstmodelsurface]; // draw texture - for (i = 0; i < model->nummodelsurfaces; i++, psurf++) { + for (i = 0; i < brush->nummodelsurfaces; i++, psurf++) { // find which side of the node we are on pplane = psurf->plane; @@ -596,7 +599,7 @@ gl_R_DrawBrushModel (entity_t *e) // draw the polygon if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - chain_surface (psurf, e->full_transform, e->colormod); + chain_surface (brush, psurf, e->full_transform, e->colormod); } } } @@ -623,7 +626,7 @@ get_side (mnode_t *node) } static inline void -visit_node (mnode_t *node, int side) +visit_node (mod_brush_t *brush, mnode_t *node, int side) { int c; msurface_t *surf; @@ -632,7 +635,7 @@ visit_node (mnode_t *node, int side) side = (~side + 1) & SURF_PLANEBACK; // draw stuff if ((c = node->numsurfaces)) { - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (; c; c--, surf++) { if (surf->visframe != r_visframecount) continue; @@ -641,7 +644,7 @@ visit_node (mnode_t *node, int side) if (side ^ (surf->flags & SURF_PLANEBACK)) continue; // wrong side - chain_surface (surf, 0, 0); + chain_surface (brush, surf, 0, 0); } } } @@ -659,7 +662,7 @@ test_node (mnode_t *node) } static void -R_VisitWorldNodes (model_t *model) +R_VisitWorldNodes (mod_brush_t *brush) { typedef struct { mnode_t *node; @@ -671,9 +674,9 @@ R_VisitWorldNodes (model_t *model) mnode_t *front; int side; - node = model->nodes; + node = brush->nodes; // +2 for paranoia - node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); + node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; while (1) { @@ -689,7 +692,7 @@ R_VisitWorldNodes (model_t *model) } if (front->contents < 0 && front->contents != CONTENTS_SOLID) visit_leaf ((mleaf_t *) front); - visit_node (node, side); + visit_node (brush, node, side); node = node->children[!side]; } if (node->contents < 0 && node->contents != CONTENTS_SOLID) @@ -698,7 +701,7 @@ R_VisitWorldNodes (model_t *model) node_ptr--; node = node_ptr->node; side = node_ptr->side; - visit_node (node, side); + visit_node (brush, node, side); node = node->children[!side]; continue; } @@ -726,7 +729,7 @@ gl_R_DrawWorld (void) gl_R_DrawSky (); } - R_VisitWorldNodes (r_worldentity.model); + R_VisitWorldNodes (&r_worldentity.model->brush); if (r_drawentities->int_val) { entity_t *ent; for (ent = r_ent_queue; ent; ent = ent->next) { @@ -821,7 +824,7 @@ GL_BuildSurfaceDisplayList (msurface_t *fa) medge_t *pedges, *r_pedge; // reconstruct the polygon - pedges = gl_currentmodel->edges; + pedges = gl_currentmodel->brush.edges; lnumverts = fa->numedges; // draw texture @@ -833,7 +836,7 @@ GL_BuildSurfaceDisplayList (msurface_t *fa) poly->numverts = lnumverts; for (i = 0; i < lnumverts; i++) { - lindex = gl_currentmodel->surfedges[fa->firstedge + i]; + lindex = gl_currentmodel->brush.surfedges[fa->firstedge + i]; if (lindex > 0) { r_pedge = &pedges[lindex]; diff --git a/libs/video/renderer/glsl/glsl_alias.c b/libs/video/renderer/glsl/glsl_alias.c index 155845450..3cbf4f89d 100644 --- a/libs/video/renderer/glsl/glsl_alias.c +++ b/libs/video/renderer/glsl/glsl_alias.c @@ -159,7 +159,7 @@ calc_lighting (entity_t *ent, float *ambient, float *shadelight, int light; VectorSet ( -1, 0, 0, lightvec); //FIXME - light = R_LightPoint (ent->origin); + light = R_LightPoint (&r_worldentity.model->brush, ent->origin); *ambient = max (light, max (ent->model->min_light, ent->min_light) * 128); *shadelight = *ambient; diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index 8a6ee73f5..3b5ed0cd4 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -311,17 +311,17 @@ glsl_R_AddTexture (texture_t *tx) tex->elechain_tail = &tex->elechain; } -void -glsl_R_InitSurfaceChains (model_t *model) +static void +glsl_R_InitSurfaceChains (mod_brush_t *brush) { int i; release_static_instsurfs (); release_instsurfs (); - for (i = 0; i < model->nummodelsurfaces; i++) { - model->surfaces[i].instsurf = get_static_instsurf (); - model->surfaces[i].instsurf->surface = &model->surfaces[i]; + for (i = 0; i < brush->nummodelsurfaces; i++) { + brush->surfaces[i].instsurf = get_static_instsurf (); + brush->surfaces[i].instsurf->surface = &brush->surfaces[i]; } } @@ -358,7 +358,7 @@ glsl_R_ClearElements (void) } static void -update_lightmap (msurface_t *surf) +update_lightmap (mod_brush_t *brush, msurface_t *surf) { int maps; @@ -369,12 +369,13 @@ update_lightmap (msurface_t *surf) if ((surf->dlightframe == r_framecount) || surf->cached_dlight) { dynamic: if (r_dynamic->int_val) - glsl_R_BuildLightMap (surf); + glsl_R_BuildLightMap (brush, surf); } } static inline void -chain_surface (msurface_t *surf, vec_t *transform, float *color) +chain_surface (mod_brush_t *brush, msurface_t *surf, vec_t *transform, + float *color) { instsurf_t *is; @@ -393,7 +394,7 @@ chain_surface (msurface_t *surf, vec_t *transform, float *color) tex = tx->render; CHAIN_SURF_F2B (surf, tex->tex_chain); - update_lightmap (surf); + update_lightmap (brush, surf); } if (!(is = surf->instsurf)) is = surf->tinst; @@ -402,13 +403,13 @@ chain_surface (msurface_t *surf, vec_t *transform, float *color) } static void -register_textures (model_t *model) +register_textures (mod_brush_t *brush) { int i; texture_t *tex; - for (i = 0; i < model->numtextures; i++) { - tex = model->textures[i]; + for (i = 0; i < brush->numtextures; i++) { + tex = brush->textures[i]; if (!tex) continue; glsl_R_AddTexture (tex); @@ -426,11 +427,12 @@ glsl_R_RegisterTextures (model_t **models, int num_models) { int i; model_t *m; + mod_brush_t *brush; glsl_R_ClearTextures (); - glsl_R_InitSurfaceChains (r_worldentity.model); + glsl_R_InitSurfaceChains (&r_worldentity.model->brush); glsl_R_AddTexture (r_notexture_mip); - register_textures (r_worldentity.model); + register_textures (&r_worldentity.model->brush); for (i = 0; i < num_models; i++) { m = models[i]; if (!m) @@ -441,8 +443,9 @@ glsl_R_RegisterTextures (model_t **models, int num_models) // world has already been done, not interested in non-brush models if (m == r_worldentity.model || m->type != mod_brush) continue; - m->numsubmodels = 1; // no support for submodels in non-world model - register_textures (m); + brush = &m->brush; + brush->numsubmodels = 1; // no support for submodels in non-world model + register_textures (brush); } } @@ -478,16 +481,17 @@ build_surf_displist (model_t **models, msurface_t *fa, int base, glslpoly_t *poly; GLushort *ind; float s, t; + mod_brush_t *brush; if (fa->ec_index < 0) { - vertices = models[-fa->ec_index - 1]->vertexes; - edges = models[-fa->ec_index - 1]->edges; - surfedges = models[-fa->ec_index - 1]->surfedges; + brush = &models[-fa->ec_index - 1]->brush; } else { - vertices = r_worldentity.model->vertexes; - edges = r_worldentity.model->edges; - surfedges = r_worldentity.model->surfedges; + brush = &r_worldentity.model->brush; } + vertices = brush->vertexes; + edges = brush->edges; + surfedges = brush->surfedges; + numverts = fa->numedges; numtris = numverts - 2; numindices = numtris * 3; @@ -545,6 +549,7 @@ glsl_R_BuildDisplayLists (model_t **models, int num_models) dmodel_t *dm; msurface_t *surf; dstring_t *vertices; + mod_brush_t *brush; QuatSet (0, 0, sqrt(0.5), sqrt(0.5), sky_fix); // proper skies QuatSet (0, 0, 0, 1, sky_rotation[0]); @@ -561,24 +566,25 @@ glsl_R_BuildDisplayLists (model_t **models, int num_models) if (!m) continue; // sub-models are done as part of the main model - if (*m->path == '*') + if (*m->path == '*' || m->type != mod_brush) continue; + brush = &m->brush; // non-bsp models don't have surfaces. - dm = m->submodels; - for (j = 0; j < m->numsurfaces; j++) { + dm = brush->submodels; + for (j = 0; j < brush->numsurfaces; j++) { glsltex_t *tex; if (j == dm->firstface + dm->numfaces) { dm++; - if (dm - m->submodels == m->numsubmodels) { + if (dm - brush->submodels == brush->numsubmodels) { // limit the surfaces // probably never hit Sys_Printf ("R_BuildDisplayLists: too many surfaces\n"); - m->numsurfaces = j; + brush->numsurfaces = j; break; } } - surf = m->surfaces + j; - surf->ec_index = dm - m->submodels; + surf = brush->surfaces + j; + surf->ec_index = dm - brush->submodels; if (!surf->ec_index && m != r_worldentity.model) surf->ec_index = -1 - i; // instanced model tex = surf->texinfo->texture->render; @@ -654,8 +660,10 @@ R_DrawBrushModel (entity_t *e) msurface_t *surf; qboolean rotated; vec3_t mins, maxs, org; + mod_brush_t *brush; model = e->model; + brush = &model->brush; if (e->transform[0] != 1 || e->transform[5] != 1 || e->transform[10] != 1) { rotated = true; radius = model->radius; @@ -680,7 +688,7 @@ R_DrawBrushModel (entity_t *e) } // calculate dynamic lighting for bmodel if it's not an instanced model - if (model->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { + if (brush->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { vec3_t lightorigin; for (k = 0; k < r_maxdlights; k++) { @@ -689,14 +697,14 @@ R_DrawBrushModel (entity_t *e) continue; VectorSubtract (r_dlights[k].origin, e->origin, lightorigin); - R_RecursiveMarkLights (lightorigin, &r_dlights[k], k, - model->nodes + model->hulls[0].firstclipnode); + R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, + brush->nodes + brush->hulls[0].firstclipnode); } } - surf = &model->surfaces[model->firstmodelsurface]; + surf = &brush->surfaces[brush->firstmodelsurface]; - for (i = 0; i < model->nummodelsurfaces; i++, surf++) { + for (i = 0; i < brush->nummodelsurfaces; i++, surf++) { // find the node side on which we are plane = surf->plane; @@ -705,7 +713,7 @@ R_DrawBrushModel (entity_t *e) // enqueue the polygon if (((surf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(surf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - chain_surface (surf, e->transform, e->colormod); + chain_surface (brush, surf, e->transform, e->colormod); } } } @@ -730,7 +738,7 @@ get_side (mnode_t *node) } static inline void -visit_node (mnode_t *node, int side) +visit_node (mod_brush_t *brush, mnode_t *node, int side) { int c; msurface_t *surf; @@ -739,7 +747,7 @@ visit_node (mnode_t *node, int side) side = (~side + 1) & SURF_PLANEBACK; // draw stuff if ((c = node->numsurfaces)) { - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (; c; c--, surf++) { if (surf->visframe != r_visframecount) continue; @@ -748,7 +756,7 @@ visit_node (mnode_t *node, int side) if (side ^ (surf->flags & SURF_PLANEBACK)) continue; // wrong side - chain_surface (surf, 0, 0); + chain_surface (brush, surf, 0, 0); } } } @@ -766,7 +774,7 @@ test_node (mnode_t *node) } static void -R_VisitWorldNodes (model_t *model) +R_VisitWorldNodes (mod_brush_t *brush) { typedef struct { mnode_t *node; @@ -778,9 +786,9 @@ R_VisitWorldNodes (model_t *model) mnode_t *front; int side; - node = model->nodes; + node = brush->nodes; // +2 for paranoia - node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); + node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; while (1) { @@ -796,7 +804,7 @@ R_VisitWorldNodes (model_t *model) } if (front->contents < 0 && front->contents != CONTENTS_SOLID) visit_leaf ((mleaf_t *) front); - visit_node (node, side); + visit_node (brush, node, side); node = node->children[!side]; } if (node->contents < 0 && node->contents != CONTENTS_SOLID) @@ -805,7 +813,7 @@ R_VisitWorldNodes (model_t *model) node_ptr--; node = node_ptr->node; side = node_ptr->side; - visit_node (node, side); + visit_node (brush, node, side); node = node->children[!side]; continue; } @@ -1123,7 +1131,7 @@ glsl_R_DrawWorld (void) currententity = &worldent; - R_VisitWorldNodes (worldent.model); + R_VisitWorldNodes (&worldent.model->brush); if (r_drawentities->int_val) { entity_t *ent; for (ent = r_ent_queue; ent; ent = ent->next) { diff --git a/libs/video/renderer/glsl/glsl_iqm.c b/libs/video/renderer/glsl/glsl_iqm.c index e757cf087..ce2c2f31d 100644 --- a/libs/video/renderer/glsl/glsl_iqm.c +++ b/libs/video/renderer/glsl/glsl_iqm.c @@ -217,7 +217,7 @@ glsl_R_DrawIQM (void) float blend; iqmframe_t *frame; - R_LightPoint (ent->origin); //FIXME min_light? + R_LightPoint (&r_worldentity.model->brush, ent->origin);//FIXME min_light? VectorScale (ambientcolor, 1/255.0, ambientcolor); R_FindNearLights (ent->origin, MAX_IQM_LIGHTS, lights); diff --git a/libs/video/renderer/glsl/glsl_lightmap.c b/libs/video/renderer/glsl/glsl_lightmap.c index 0776e015e..65af9d238 100644 --- a/libs/video/renderer/glsl/glsl_lightmap.c +++ b/libs/video/renderer/glsl/glsl_lightmap.c @@ -61,7 +61,7 @@ static scrap_t *light_scrap; static unsigned *blocklights; static int bl_extents[2]; -void (*glsl_R_BuildLightMap) (msurface_t *surf); +void (*glsl_R_BuildLightMap) (mod_brush_t *brush, msurface_t *surf); static void R_AddDynamicLights_1 (msurface_t *surf) @@ -121,7 +121,7 @@ R_AddDynamicLights_1 (msurface_t *surf) } static void -R_BuildLightMap_1 (msurface_t *surf) +R_BuildLightMap_1 (mod_brush_t *brush, msurface_t *surf) { int smax, tmax, size; unsigned scale; @@ -138,7 +138,7 @@ R_BuildLightMap_1 (msurface_t *surf) // clear to no light memset (blocklights, 0, size * sizeof (blocklights[0])); - if (!r_worldentity.model->lightdata) { + if (!brush->lightdata) { // because we by-pass the inversion, "no light" = "full bright" GLSL_SubpicUpdate (surf->lightpic, (byte *) blocklights, 1); return; @@ -196,6 +196,7 @@ glsl_R_BuildLightmaps (model_t **models, int num_models) { int i, j, size; model_t *m; + mod_brush_t *brush; //FIXME RGB support if (!light_scrap) { @@ -210,13 +211,14 @@ glsl_R_BuildLightmaps (model_t **models, int num_models) m = models[j]; if (!m) break; - if (m->path[0] == '*') { + if (m->path[0] == '*' || m->type != mod_brush) { // sub model surfaces are processed as part of the main model continue; } + brush = &m->brush; // non-bsp models don't have surfaces. - for (i = 0; i < m->numsurfaces; i++) { - msurface_t *surf = m->surfaces + i; + for (i = 0; i < brush->numsurfaces; i++) { + msurface_t *surf = brush->surfaces + i; surf->lightpic = 0; // paranoia if (surf->flags & SURF_DRAWTURB) continue; @@ -231,15 +233,16 @@ glsl_R_BuildLightmaps (model_t **models, int num_models) m = models[j]; if (!m) break; - if (m->path[0] == '*') { + if (m->path[0] == '*' || m->type != mod_brush) { // sub model surfaces are processed as part of the main model continue; } + brush = &m->brush; // non-bsp models don't have surfaces. - for (i = 0; i < m->numsurfaces; i++) { - msurface_t *surf = m->surfaces + i; + for (i = 0; i < brush->numsurfaces; i++) { + msurface_t *surf = brush->surfaces + i; if (surf->lightpic) - glsl_R_BuildLightMap (surf); + glsl_R_BuildLightMap (brush, surf); } } } diff --git a/libs/video/renderer/glsl/namehack.h b/libs/video/renderer/glsl/namehack.h index aed6d2e21..a6f62e701 100644 --- a/libs/video/renderer/glsl/namehack.h +++ b/libs/video/renderer/glsl/namehack.h @@ -52,7 +52,6 @@ #define R_InitParticles glsl_R_InitParticles #define R_InitSky glsl_R_InitSky #define R_InitSprites glsl_R_InitSprites -#define R_InitSurfaceChains glsl_R_InitSurfaceChains #define R_LineGraph glsl_R_LineGraph #define R_LoadSky_f glsl_R_LoadSky_f #define R_LoadSkys glsl_R_LoadSkys diff --git a/libs/video/renderer/r_bsp.c b/libs/video/renderer/r_bsp.c index a6fdc961d..2475873a5 100644 --- a/libs/video/renderer/r_bsp.c +++ b/libs/video/renderer/r_bsp.c @@ -67,13 +67,13 @@ R_MarkLeaves (void) r_oldviewleaf = 0; // so vis will be recalcualted when novis gets // turned off vis = solid; - memset (solid, 0xff, (r_worldentity.model->numleafs + 7) >> 3); + memset (solid, 0xff, (r_worldentity.model->brush.numleafs + 7) >> 3); } else vis = Mod_LeafPVS (r_viewleaf, r_worldentity.model); - for (i = 0; (int) i < r_worldentity.model->numleafs; i++) { + for (i = 0; (int) i < r_worldentity.model->brush.numleafs; i++) { if (vis[i >> 3] & (1 << (i & 7))) { - leaf = &r_worldentity.model->leafs[i + 1]; + leaf = &r_worldentity.model->brush.leafs[i + 1]; if ((c = leaf->nummarksurfaces)) { mark = leaf->firstmarksurface; do { diff --git a/libs/video/renderer/r_efrag.c b/libs/video/renderer/r_efrag.c index ae5e1fd8a..8785d3d7d 100644 --- a/libs/video/renderer/r_efrag.c +++ b/libs/video/renderer/r_efrag.c @@ -195,7 +195,7 @@ R_SplitEntityOnNode (mnode_t *node) } void -R_AddEfrags (entity_t *ent) +R_AddEfrags (mod_brush_t *brush, entity_t *ent) { model_t *entmodel; @@ -215,7 +215,7 @@ R_AddEfrags (entity_t *ent) VectorAdd (ent->origin, entmodel->mins, r_emins); VectorAdd (ent->origin, entmodel->maxs, r_emaxs); - R_SplitEntityOnNode (r_worldentity.model->nodes); + R_SplitEntityOnNode (brush->nodes); ent->topnode = r_pefragtopnode; } diff --git a/libs/video/renderer/r_light.c b/libs/video/renderer/r_light.c index bd242e7bc..8d3294c37 100644 --- a/libs/video/renderer/r_light.c +++ b/libs/video/renderer/r_light.c @@ -203,8 +203,8 @@ mark_surfaces (msurface_t *surf, const vec3_t lightorigin, dlight_t *light, // LordHavoc: heavily modified, to eliminate unnecessary texture uploads, // and support bmodel lighting better void -R_RecursiveMarkLights (const vec3_t lightorigin, dlight_t *light, int lightnum, - mnode_t *node) +R_RecursiveMarkLights (mod_brush_t *brush, const vec3_t lightorigin, + dlight_t *light, int lightnum, mnode_t *node) { unsigned i; float ndist, maxdist; @@ -240,14 +240,14 @@ loc0: } // mark the polygons - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (i = 0; i < node->numsurfaces; i++, surf++) { mark_surfaces (surf, lightorigin, light, lightnum); } if (node->children[0]->contents >= 0) { if (node->children[1]->contents >= 0) - R_RecursiveMarkLights (lightorigin, light, lightnum, + R_RecursiveMarkLights (brush, lightorigin, light, lightnum, node->children[1]); node = node->children[0]; goto loc0; @@ -262,11 +262,12 @@ void R_MarkLights (const vec3_t lightorigin, dlight_t *light, int lightnum, model_t *model) { + mod_brush_t *brush = &model->brush; mleaf_t *pvsleaf = Mod_PointInLeaf (lightorigin, model); if (!pvsleaf->compressed_vis) { - mnode_t *node = model->nodes + model->hulls[0].firstclipnode; - R_RecursiveMarkLights (lightorigin, light, lightnum, node); + mnode_t *node = brush->nodes + brush->hulls[0].firstclipnode; + R_RecursiveMarkLights (brush, lightorigin, light, lightnum, node); } else { float radius = light->radius; vec3_t mins, maxs; @@ -280,16 +281,16 @@ R_MarkLights (const vec3_t lightorigin, dlight_t *light, int lightnum, maxs[0] = lightorigin[0] + radius; maxs[1] = lightorigin[1] + radius; maxs[2] = lightorigin[2] + radius; - while (leafnum < model->numleafs) { + while (leafnum < brush->numleafs) { int b; if (!(vis_bits = *in++)) { leafnum += (*in++) * 8; continue; } - for (b = 1; b < 256 && leafnum < model->numleafs; + for (b = 1; b < 256 && leafnum < brush->numleafs; b <<= 1, leafnum++) { int m; - mleaf_t *leaf = &model->leafs[leafnum + 1]; + mleaf_t *leaf = &brush->leafs[leafnum + 1]; if (!(vis_bits & b)) continue; if (leaf->visframe != r_visframecount) @@ -400,7 +401,8 @@ calc_lighting_3 (msurface_t *surf, int ds, int dt) } static int -RecursiveLightPoint (mnode_t *node, const vec3_t start, const vec3_t end) +RecursiveLightPoint (mod_brush_t *brush, mnode_t *node, const vec3_t start, + const vec3_t end) { unsigned i; int r, s, t, ds, dt, side; @@ -430,7 +432,7 @@ loop: mid[2] = start[2] + (end[2] - start[2]) * frac; // go down front side - r = RecursiveLightPoint (node->children[side], start, mid); + r = RecursiveLightPoint (brush, node->children[side], start, mid); if (r >= 0) return r; // hit something @@ -441,7 +443,7 @@ loop: VectorCopy (mid, lightspot); lightplane = plane; - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (i = 0; i < node->numsurfaces; i++, surf++) { if (surf->flags & SURF_DRAWTILED) continue; // no lightmaps @@ -472,16 +474,16 @@ loop: } // go down back side - return RecursiveLightPoint (node->children[!side], mid, end); + return RecursiveLightPoint (brush, node->children[!side], mid, end); } int -R_LightPoint (const vec3_t p) +R_LightPoint (mod_brush_t *brush, const vec3_t p) { vec3_t end; int r; - if (!r_worldentity.model->lightdata) { + if (!brush->lightdata) { // allow dlights to have some effect, so don't go /quite/ fullbright ambientcolor[2] = ambientcolor[1] = ambientcolor[0] = 200; return 200; @@ -491,7 +493,7 @@ R_LightPoint (const vec3_t p) end[1] = p[1]; end[2] = p[2] - 2048; - r = RecursiveLightPoint (r_worldentity.model->nodes, p, end); + r = RecursiveLightPoint (brush, brush->nodes, p, end); if (r == -1) r = 0; diff --git a/libs/video/renderer/sw/sw_rbsp.c b/libs/video/renderer/sw/sw_rbsp.c index 17fcbf5bb..7cf001b87 100644 --- a/libs/video/renderer/sw/sw_rbsp.c +++ b/libs/video/renderer/sw/sw_rbsp.c @@ -237,7 +237,7 @@ R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) void -R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) +R_DrawSolidClippedSubmodelPolygons (model_t *model) { int i, j, lindex; vec_t dot; @@ -247,12 +247,13 @@ R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) mvertex_t bverts[MAX_BMODEL_VERTS]; bedge_t bedges[MAX_BMODEL_EDGES], *pbedge; medge_t *pedge, *pedges; + mod_brush_t *brush = &model->brush; // FIXME: use bounding-box-based frustum clipping info? - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; - pedges = pmodel->edges; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; + pedges = brush->edges; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on @@ -278,7 +279,7 @@ R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) numbedges += psurf->numedges; for (j = 0; j < psurf->numedges; j++) { - lindex = pmodel->surfedges[psurf->firstedge + j]; + lindex = brush->surfedges[psurf->firstedge + j]; if (lindex > 0) { pedge = &pedges[lindex]; @@ -306,18 +307,19 @@ R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) void -R_DrawSubmodelPolygons (model_t *pmodel, int clipflags) +R_DrawSubmodelPolygons (model_t *model, int clipflags) { int i; vec_t dot; msurface_t *psurf; int numsurfaces; plane_t *pplane; + mod_brush_t *brush = &model->brush; // FIXME: use bounding-box-based frustum clipping info? - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on @@ -358,7 +360,7 @@ get_side (mnode_t *node) } static void -visit_node (mnode_t *node, int side, int clipflags) +visit_node (mod_brush_t *brush, mnode_t *node, int side, int clipflags) { int c; msurface_t *surf; @@ -367,7 +369,7 @@ visit_node (mnode_t *node, int side, int clipflags) side = (~side + 1) & SURF_PLANEBACK; // draw stuff if ((c = node->numsurfaces)) { - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (; c; c--, surf++) { if (surf->visframe != r_visframecount) continue; @@ -444,7 +446,7 @@ test_node (mnode_t *node, int *clipflags) } static void -R_VisitWorldNodes (model_t *model, int clipflags) +R_VisitWorldNodes (mod_brush_t *brush, int clipflags) { typedef struct { mnode_t *node; @@ -456,9 +458,9 @@ R_VisitWorldNodes (model_t *model, int clipflags) mnode_t *front; int side, cf; - node = model->nodes; + node = brush->nodes; // +2 for paranoia - node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); + node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; cf = clipflags; @@ -478,7 +480,7 @@ R_VisitWorldNodes (model_t *model, int clipflags) } if (front->contents < 0 && front->contents != CONTENTS_SOLID) visit_leaf ((mleaf_t *) front); - visit_node (node, side, clipflags); + visit_node (brush, node, side, clipflags); node = node->children[!side]; } if (node->contents < 0 && node->contents != CONTENTS_SOLID) @@ -488,7 +490,7 @@ R_VisitWorldNodes (model_t *model, int clipflags) node = node_ptr->node; side = node_ptr->side; clipflags = node_ptr->clipflags; - visit_node (node, side, clipflags); + visit_node (brush, node, side, clipflags); node = node->children[!side]; continue; } @@ -502,17 +504,17 @@ void R_RenderWorld (void) { int i; - model_t *clmodel; btofpoly_t btofpolys[MAX_BTOFPOLYS]; + mod_brush_t *brush; pbtofpolys = btofpolys; currententity = &r_worldentity; VectorCopy (r_origin, modelorg); - clmodel = currententity->model; - r_pcurrentvertbase = clmodel->vertexes; + brush = ¤tentity->model->brush; + r_pcurrentvertbase = brush->vertexes; - R_VisitWorldNodes (clmodel, 15); + R_VisitWorldNodes (brush, 15); // if the driver wants the polygons back to front, play the visible ones // back in that order diff --git a/libs/video/renderer/sw/sw_rdraw.c b/libs/video/renderer/sw/sw_rdraw.c index c5c943fd5..3f460643d 100644 --- a/libs/video/renderer/sw/sw_rdraw.c +++ b/libs/video/renderer/sw/sw_rdraw.c @@ -353,6 +353,7 @@ R_RenderFace (msurface_t *fa, int clipflags) vec3_t p_normal; medge_t *pedges, tedge; clipplane_t *pclip; + mod_brush_t *brush = ¤tentity->model->brush; // skip out if no more surfs if ((surface_p) >= surf_max) { @@ -382,11 +383,11 @@ R_RenderFace (msurface_t *fa, int clipflags) r_nearzi = 0; r_nearzionly = false; makeleftedge = makerightedge = false; - pedges = currententity->model->edges; + pedges = brush->edges; r_lastvertvalid = false; for (i = 0; i < fa->numedges; i++) { - lindex = currententity->model->surfedges[fa->firstedge + i]; + lindex = brush->surfedges[fa->firstedge + i]; if (lindex > 0) { r_pedge = &pedges[lindex]; @@ -623,6 +624,7 @@ R_RenderPoly (msurface_t *fa, int clipflags) polyvert_t pverts[100]; // FIXME: do real number, safely int vertpage, newverts, newpage, lastvert; qboolean visible; + mod_brush_t *brush = ¤tentity->model->brush; // FIXME: clean this up and make it faster // FIXME: guard against running out of vertices @@ -641,12 +643,12 @@ R_RenderPoly (msurface_t *fa, int clipflags) // reconstruct the polygon // FIXME: these should be precalculated and loaded off disk - pedges = currententity->model->edges; + pedges = brush->edges; lnumverts = fa->numedges; vertpage = 0; for (i = 0; i < lnumverts; i++) { - lindex = currententity->model->surfedges[fa->firstedge + i]; + lindex = brush->surfedges[fa->firstedge + i]; if (lindex > 0) { r_pedge = &pedges[lindex]; @@ -777,15 +779,16 @@ R_RenderPoly (msurface_t *fa, int clipflags) void -R_ZDrawSubmodelPolys (model_t *pmodel) +R_ZDrawSubmodelPolys (model_t *model) { int i, numsurfaces; msurface_t *psurf; float dot; plane_t *pplane; + mod_brush_t *brush = &model->brush; - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 5d38ae04d..573827bda 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -164,6 +164,7 @@ void R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) { int i; + mod_brush_t *brush = &worldmodel->brush; memset (&r_worldentity, 0, sizeof (r_worldentity)); r_worldentity.model = worldmodel; @@ -172,11 +173,11 @@ R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) // clear out efrags in case the level hasn't been reloaded // FIXME: is this one short? - for (i = 0; i < r_worldentity.model->numleafs; i++) - r_worldentity.model->leafs[i].efrags = NULL; + for (i = 0; i < brush->numleafs; i++) + brush->leafs[i].efrags = NULL; - if (worldmodel->skytexture) - R_InitSky (worldmodel->skytexture); + if (brush->skytexture) + R_InitSky (brush->skytexture); // Force a vis update r_viewleaf = NULL; @@ -381,7 +382,8 @@ R_DrawEntitiesOnList (void) if (currententity->model->type == mod_iqm//FIXME || R_AliasCheckBBox ()) { // 128 instead of 255 due to clamping below - j = max (R_LightPoint (currententity->origin), minlight * 128); + j = max (R_LightPoint (&r_worldentity.model->brush, + currententity->origin), minlight * 128); lighting.ambientlight = j; lighting.shadelight = j; @@ -448,7 +450,8 @@ R_DrawViewModel (void) minlight = max (currententity->min_light, currententity->model->min_light); - j = max (R_LightPoint (currententity->origin), minlight * 128); + j = max (R_LightPoint (&r_worldentity.model->brush, + currententity->origin), minlight * 128); r_viewlighting.ambientlight = j; r_viewlighting.shadelight = j; @@ -568,19 +571,20 @@ R_DrawBEntitiesOnList (void) clipflags = R_BmodelCheckBBox (clmodel, minmaxs); if (clipflags != BMODEL_FULLY_CLIPPED) { + mod_brush_t *brush = &clmodel->brush; VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // FIXME: is this needed? VectorCopy (modelorg, r_worldmodelorg); - r_pcurrentvertbase = clmodel->vertexes; + r_pcurrentvertbase = brush->vertexes; // FIXME: stop transforming twice R_RotateBmodel (); // calculate dynamic lighting for bmodel if it's not an // instanced model - if (clmodel->firstmodelsurface != 0) { + if (brush->firstmodelsurface != 0) { vec3_t lightorigin; for (k = 0; k < r_maxdlights; k++) { @@ -590,9 +594,10 @@ R_DrawBEntitiesOnList (void) VectorSubtract (r_dlights[k].origin, currententity->origin, lightorigin); - R_RecursiveMarkLights (lightorigin, &r_dlights[k], - k, clmodel->nodes + - clmodel->hulls[0].firstclipnode); + R_RecursiveMarkLights (brush, lightorigin, + &r_dlights[k], k, + brush->nodes + + brush->hulls[0].firstclipnode); } } // if the driver wants polygons, deliver those. diff --git a/libs/video/renderer/sw/sw_rsurf.c b/libs/video/renderer/sw/sw_rsurf.c index e4d3fa853..5133118cb 100644 --- a/libs/video/renderer/sw/sw_rsurf.c +++ b/libs/video/renderer/sw/sw_rsurf.c @@ -154,7 +154,7 @@ R_BuildLightMap (void) size = smax * tmax; lightmap = surf->samples; - if (!r_worldentity.model->lightdata) { + if (!r_worldentity.model->brush.lightdata) { for (i = 0; i < size; i++) blocklights[i] = 0; return; diff --git a/libs/video/renderer/sw32/sw32_rbsp.c b/libs/video/renderer/sw32/sw32_rbsp.c index 017268dbb..521e70cd5 100644 --- a/libs/video/renderer/sw32/sw32_rbsp.c +++ b/libs/video/renderer/sw32/sw32_rbsp.c @@ -240,7 +240,7 @@ R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) void -sw32_R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) +sw32_R_DrawSolidClippedSubmodelPolygons (model_t *model) { int i, j, lindex; vec_t dot; @@ -250,12 +250,13 @@ sw32_R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) mvertex_t bverts[MAX_BMODEL_VERTS]; bedge_t bedges[MAX_BMODEL_EDGES], *pbedge; medge_t *pedge, *pedges; + mod_brush_t *brush = &model->brush; // FIXME: use bounding-box-based frustum clipping info? - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; - pedges = pmodel->edges; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; + pedges = brush->edges; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on @@ -281,7 +282,7 @@ sw32_R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) numbedges += psurf->numedges; for (j = 0; j < psurf->numedges; j++) { - lindex = pmodel->surfedges[psurf->firstedge + j]; + lindex = brush->surfedges[psurf->firstedge + j]; if (lindex > 0) { pedge = &pedges[lindex]; @@ -309,18 +310,19 @@ sw32_R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) void -sw32_R_DrawSubmodelPolygons (model_t *pmodel, int clipflags) +sw32_R_DrawSubmodelPolygons (model_t *model, int clipflags) { int i; vec_t dot; msurface_t *psurf; int numsurfaces; plane_t *pplane; + mod_brush_t *brush = &model->brush; // FIXME: use bounding-box-based frustum clipping info? - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on @@ -361,7 +363,7 @@ get_side (mnode_t *node) } static void -visit_node (mnode_t *node, int side, int clipflags) +visit_node (mod_brush_t *brush, mnode_t *node, int side, int clipflags) { int c; msurface_t *surf; @@ -370,7 +372,7 @@ visit_node (mnode_t *node, int side, int clipflags) side = (~side + 1) & SURF_PLANEBACK; // draw stuff if ((c = node->numsurfaces)) { - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (; c; c--, surf++) { if (surf->visframe != r_visframecount) continue; @@ -447,7 +449,7 @@ test_node (mnode_t *node, int *clipflags) } static void -R_VisitWorldNodes (model_t *model, int clipflags) +R_VisitWorldNodes (mod_brush_t *brush, int clipflags) { typedef struct { mnode_t *node; @@ -459,9 +461,9 @@ R_VisitWorldNodes (model_t *model, int clipflags) mnode_t *front; int side, cf; - node = model->nodes; + node = brush->nodes; // +2 for paranoia - node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); + node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; cf = clipflags; @@ -481,7 +483,7 @@ R_VisitWorldNodes (model_t *model, int clipflags) } if (front->contents < 0 && front->contents != CONTENTS_SOLID) visit_leaf ((mleaf_t *) front); - visit_node (node, side, clipflags); + visit_node (brush, node, side, clipflags); node = node->children[!side]; } if (node->contents < 0 && node->contents != CONTENTS_SOLID) @@ -491,7 +493,7 @@ R_VisitWorldNodes (model_t *model, int clipflags) node = node_ptr->node; side = node_ptr->side; clipflags = node_ptr->clipflags; - visit_node (node, side, clipflags); + visit_node (brush, node, side, clipflags); node = node->children[!side]; continue; } @@ -505,17 +507,17 @@ void sw32_R_RenderWorld (void) { int i; - model_t *clmodel; btofpoly_t btofpolys[MAX_BTOFPOLYS]; + mod_brush_t *brush; pbtofpolys = btofpolys; currententity = &r_worldentity; VectorCopy (r_origin, modelorg); - clmodel = currententity->model; - r_pcurrentvertbase = clmodel->vertexes; + brush = ¤tentity->model->brush; + r_pcurrentvertbase = brush->vertexes; - R_VisitWorldNodes (clmodel, 15); + R_VisitWorldNodes (brush, 15); // if the driver wants the polygons back to front, play the visible ones // back in that order diff --git a/libs/video/renderer/sw32/sw32_rdraw.c b/libs/video/renderer/sw32/sw32_rdraw.c index 6624917a7..b106ab63a 100644 --- a/libs/video/renderer/sw32/sw32_rdraw.c +++ b/libs/video/renderer/sw32/sw32_rdraw.c @@ -349,6 +349,7 @@ sw32_R_RenderFace (msurface_t *fa, int clipflags) vec3_t p_normal; medge_t *pedges, tedge; clipplane_t *pclip; + mod_brush_t *brush = ¤tentity->model->brush; // skip out if no more surfs if ((sw32_surface_p) >= sw32_surf_max) { @@ -378,11 +379,11 @@ sw32_R_RenderFace (msurface_t *fa, int clipflags) sw32_r_nearzi = 0; sw32_r_nearzionly = false; makeleftedge = makerightedge = false; - pedges = currententity->model->edges; + pedges = brush->edges; sw32_r_lastvertvalid = false; for (i = 0; i < fa->numedges; i++) { - lindex = currententity->model->surfedges[fa->firstedge + i]; + lindex = brush->surfedges[fa->firstedge + i]; if (lindex > 0) { sw32_r_pedge = &pedges[lindex]; @@ -621,6 +622,7 @@ sw32_R_RenderPoly (msurface_t *fa, int clipflags) polyvert_t pverts[100]; // FIXME: do real number, safely int vertpage, newverts, newpage, lastvert; qboolean visible; + mod_brush_t *brush = ¤tentity->model->brush; // FIXME: clean this up and make it faster // FIXME: guard against running out of vertices @@ -639,12 +641,12 @@ sw32_R_RenderPoly (msurface_t *fa, int clipflags) // reconstruct the polygon // FIXME: these should be precalculated and loaded off disk - pedges = currententity->model->edges; + pedges = brush->edges; lnumverts = fa->numedges; vertpage = 0; for (i = 0; i < lnumverts; i++) { - lindex = currententity->model->surfedges[fa->firstedge + i]; + lindex = brush->surfedges[fa->firstedge + i]; if (lindex > 0) { sw32_r_pedge = &pedges[lindex]; @@ -775,15 +777,16 @@ sw32_R_RenderPoly (msurface_t *fa, int clipflags) void -sw32_R_ZDrawSubmodelPolys (model_t *pmodel) +sw32_R_ZDrawSubmodelPolys (model_t *model) { int i, numsurfaces; msurface_t *psurf; float dot; plane_t *pplane; + mod_brush_t *brush = &model->brush; - psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; - numsurfaces = pmodel->nummodelsurfaces; + psurf = &brush->surfaces[brush->firstmodelsurface]; + numsurfaces = brush->nummodelsurfaces; for (i = 0; i < numsurfaces; i++, psurf++) { // find which side of the node we are on diff --git a/libs/video/renderer/sw32/sw32_rmain.c b/libs/video/renderer/sw32/sw32_rmain.c index fd204e587..67c59e2f9 100644 --- a/libs/video/renderer/sw32/sw32_rmain.c +++ b/libs/video/renderer/sw32/sw32_rmain.c @@ -180,6 +180,7 @@ void sw32_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) { int i; + mod_brush_t *brush = &worldmodel->brush; memset (&r_worldentity, 0, sizeof (r_worldentity)); r_worldentity.model = worldmodel; @@ -188,11 +189,11 @@ sw32_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) // clear out efrags in case the level hasn't been reloaded // FIXME: is this one short? - for (i = 0; i < r_worldentity.model->numleafs; i++) - r_worldentity.model->leafs[i].efrags = NULL; + for (i = 0; i < brush->numleafs; i++) + brush->leafs[i].efrags = NULL; - if (worldmodel->skytexture) - sw32_R_InitSky (worldmodel->skytexture); + if (brush->skytexture) + sw32_R_InitSky (brush->skytexture); // Force a vis update r_viewleaf = NULL; @@ -388,7 +389,9 @@ R_DrawEntitiesOnList (void) if (currententity->model->type == mod_iqm//FIXME || sw32_R_AliasCheckBBox ()) { // 128 instead of 255 due to clamping below - j = max (R_LightPoint (currententity->origin), minlight * 128); + j = max (R_LightPoint (&r_worldentity.model->brush, + currententity->origin), + minlight * 128); lighting.ambientlight = j; lighting.shadelight = j; @@ -454,7 +457,8 @@ R_DrawViewModel (void) minlight = max (currententity->min_light, currententity->model->min_light); - j = max (R_LightPoint (currententity->origin), minlight * 128); + j = max (R_LightPoint (&r_worldentity.model->brush, + currententity->origin), minlight * 128); r_viewlighting.ambientlight = j; r_viewlighting.shadelight = j; @@ -574,19 +578,20 @@ R_DrawBEntitiesOnList (void) clipflags = R_BmodelCheckBBox (clmodel, minmaxs); if (clipflags != BMODEL_FULLY_CLIPPED) { + mod_brush_t *brush = &clmodel->brush; VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // FIXME: is this needed? VectorCopy (modelorg, sw32_r_worldmodelorg); - r_pcurrentvertbase = clmodel->vertexes; + r_pcurrentvertbase = brush->vertexes; // FIXME: stop transforming twice sw32_R_RotateBmodel (); // calculate dynamic lighting for bmodel if it's not an // instanced model - if (clmodel->firstmodelsurface != 0) { + if (brush->firstmodelsurface != 0) { vec3_t lightorigin; for (k = 0; k < r_maxdlights; k++) { @@ -596,9 +601,10 @@ R_DrawBEntitiesOnList (void) VectorSubtract (r_dlights[k].origin, currententity->origin, lightorigin); - R_RecursiveMarkLights (lightorigin, &r_dlights[k], - k, clmodel->nodes + - clmodel->hulls[0].firstclipnode); + R_RecursiveMarkLights (brush, lightorigin, + &r_dlights[k], k, + brush->nodes + + brush->hulls[0].firstclipnode); } } // if the driver wants polygons, deliver those. diff --git a/libs/video/renderer/sw32/sw32_rsurf.c b/libs/video/renderer/sw32/sw32_rsurf.c index 9badf0c96..decd8c3a7 100644 --- a/libs/video/renderer/sw32/sw32_rsurf.c +++ b/libs/video/renderer/sw32/sw32_rsurf.c @@ -172,7 +172,7 @@ R_BuildLightMap (void) size = smax * tmax; lightmap = surf->samples; - if (!r_worldentity.model->lightdata) { + if (!r_worldentity.model->brush.lightdata) { for (i = 0; i < size; i++) blocklights[i] = 0; return; diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 65fa232cc..fec2d2cd6 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -144,7 +144,7 @@ calc_lighting (qfv_light_t *light, entity_t *ent) { vec3_t ambient_color; //FIXME should be ent->position - float l = R_LightPoint (r_origin) / 128.0; + float l = R_LightPoint (&r_worldentity.model->brush, r_origin) / 128.0; //XXX l = max (light, max (ent->model->min_light, ent->min_light)); light->type = 2; diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index ff64990ee..a0dcd9134 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -153,7 +153,7 @@ add_texture (texture_t *tx, vulkan_ctx_t *ctx) } static void -init_surface_chains (model_t *model, vulkan_ctx_t *ctx) +init_surface_chains (mod_brush_t *brush, vulkan_ctx_t *ctx) { bspctx_t *bctx = ctx->bsp_context; int i; @@ -161,9 +161,9 @@ init_surface_chains (model_t *model, vulkan_ctx_t *ctx) release_static_instsurfs (bctx); release_instsurfs (bctx); - for (i = 0; i < model->nummodelsurfaces; i++) { - model->surfaces[i].instsurf = get_static_instsurf (bctx); - model->surfaces[i].instsurf->surface = &model->surfaces[i]; + for (i = 0; i < brush->nummodelsurfaces; i++) { + brush->surfaces[i].instsurf = get_static_instsurf (bctx); + brush->surfaces[i].instsurf->surface = &brush->surfaces[i]; } } @@ -199,7 +199,7 @@ Vulkan_ClearElements (vulkan_ctx_t *ctx) } static void -update_lightmap (msurface_t *surf, vulkan_ctx_t *ctx) +update_lightmap (mod_brush_t *brush, msurface_t *surf, vulkan_ctx_t *ctx) { int maps; @@ -210,13 +210,13 @@ update_lightmap (msurface_t *surf, vulkan_ctx_t *ctx) if ((surf->dlightframe == r_framecount) || surf->cached_dlight) { dynamic: if (r_dynamic->int_val) - Vulkan_BuildLightMap (surf, ctx); + Vulkan_BuildLightMap (brush, surf, ctx); } } static inline void -chain_surface (msurface_t *surf, vec_t *transform, float *color, - vulkan_ctx_t *ctx) +chain_surface (mod_brush_t *brush, msurface_t *surf, vec_t *transform, + float *color, vulkan_ctx_t *ctx) { bspctx_t *bctx = ctx->bsp_context; instsurf_t *is; @@ -236,7 +236,7 @@ chain_surface (msurface_t *surf, vec_t *transform, float *color, tex = tx->render; CHAIN_SURF_F2B (surf, tex->tex_chain); - update_lightmap (surf, ctx); + update_lightmap (brush, surf, ctx); } if (!(is = surf->instsurf)) is = surf->tinst; @@ -245,13 +245,13 @@ chain_surface (msurface_t *surf, vec_t *transform, float *color, } static void -register_textures (model_t *model, vulkan_ctx_t *ctx) +register_textures (mod_brush_t *brush, vulkan_ctx_t *ctx) { int i; texture_t *tex; - for (i = 0; i < model->numtextures; i++) { - tex = model->textures[i]; + for (i = 0; i < brush->numtextures; i++) { + tex = brush->textures[i]; if (!tex) continue; add_texture (tex, ctx); @@ -270,11 +270,12 @@ Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx) { int i; model_t *m; + mod_brush_t *brush = &r_worldentity.model->brush; clear_textures (ctx); - init_surface_chains (r_worldentity.model, ctx); + init_surface_chains (brush, ctx); add_texture (r_notexture_mip, ctx); - register_textures (r_worldentity.model, ctx); + register_textures (brush, ctx); for (i = 0; i < num_models; i++) { m = models[i]; if (!m) @@ -285,8 +286,9 @@ Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx) // world has already been done, not interested in non-brush models if (m == r_worldentity.model || m->type != mod_brush) continue; - m->numsubmodels = 1; // no support for submodels in non-world model - register_textures (m, ctx); + brush = &m->brush; + brush->numsubmodels = 1; // no support for submodels in non-world model + register_textures (brush, ctx); } } @@ -329,18 +331,18 @@ build_surf_displist (model_t **models, msurface_t *fa, int base, bsppoly_t *poly; uint32_t *ind; float s, t; + mod_brush_t *brush; if (fa->ec_index < 0) { // instance model - vertices = models[~fa->ec_index]->vertexes; - edges = models[~fa->ec_index]->edges; - surfedges = models[~fa->ec_index]->surfedges; + brush = &models[~fa->ec_index]->brush; } else { // main or sub model - vertices = r_worldentity.model->vertexes; - edges = r_worldentity.model->edges; - surfedges = r_worldentity.model->surfedges; + brush = &r_worldentity.model->brush; } + vertices = brush->vertexes; + edges = brush->edges; + surfedges = brush->surfedges; // create a triangle fan numverts = fa->numedges; numindices = numverts + 1; @@ -405,6 +407,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) qfv_stagebuf_t *stage; bspvert_t *vertices; bsppoly_t *poly; + mod_brush_t *brush; QuatSet (0, 0, sqrt(0.5), sqrt(0.5), bctx->sky_fix); // proper skies QuatSet (0, 0, 0, 1, bctx->sky_rotation[0]); @@ -421,24 +424,25 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) if (!m) continue; // sub-models are done as part of the main model - if (*m->path == '*') + if (*m->path == '*' || m->type != mod_brush) continue; + brush = &m->brush; // non-bsp models don't have surfaces. - dm = m->submodels; - for (j = 0; j < m->numsurfaces; j++) { + dm = brush->submodels; + for (j = 0; j < brush->numsurfaces; j++) { vulktex_t *tex; if (j == dm->firstface + dm->numfaces) { dm++; - if (dm - m->submodels == m->numsubmodels) { + if (dm - brush->submodels == brush->numsubmodels) { // limit the surfaces // probably never hit Sys_Printf ("R_BuildDisplayLists: too many surfaces\n"); - m->numsurfaces = j; + brush->numsurfaces = j; break; } } - surf = m->surfaces + j; - surf->ec_index = dm - m->submodels; + surf = brush->surfaces + j; + surf->ec_index = dm - brush->submodels; if (!surf->ec_index && m != r_worldentity.model) surf->ec_index = -1 - i; // instanced model tex = surf->texinfo->texture->render; @@ -602,8 +606,10 @@ R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) msurface_t *surf; qboolean rotated; vec3_t mins, maxs, org; + mod_brush_t *brush; model = e->model; + brush = &model->brush; if (e->transform[0] != 1 || e->transform[5] != 1 || e->transform[10] != 1) { rotated = true; radius = model->radius; @@ -628,7 +634,7 @@ R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) } // calculate dynamic lighting for bmodel if it's not an instanced model - if (model->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { + if (brush->firstmodelsurface != 0 && r_dlight_lightmap->int_val) { vec3_t lightorigin; for (k = 0; k < r_maxdlights; k++) { @@ -637,14 +643,14 @@ R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) continue; VectorSubtract (r_dlights[k].origin, e->origin, lightorigin); - R_RecursiveMarkLights (lightorigin, &r_dlights[k], k, - model->nodes + model->hulls[0].firstclipnode); + R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, + brush->nodes + brush->hulls[0].firstclipnode); } } - surf = &model->surfaces[model->firstmodelsurface]; + surf = &brush->surfaces[brush->firstmodelsurface]; - for (i = 0; i < model->nummodelsurfaces; i++, surf++) { + for (i = 0; i < brush->nummodelsurfaces; i++, surf++) { // find the node side on which we are plane = surf->plane; @@ -653,7 +659,7 @@ R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) // enqueue the polygon if (((surf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(surf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - chain_surface (surf, e->transform, e->colormod, ctx); + chain_surface (brush, surf, e->transform, e->colormod, ctx); } } } @@ -678,7 +684,7 @@ get_side (mnode_t *node) } static inline void -visit_node (mnode_t *node, int side, vulkan_ctx_t *ctx) +visit_node (mod_brush_t *brush, mnode_t *node, int side, vulkan_ctx_t *ctx) { int c; msurface_t *surf; @@ -687,7 +693,7 @@ visit_node (mnode_t *node, int side, vulkan_ctx_t *ctx) side = (~side + 1) & SURF_PLANEBACK; // draw stuff if ((c = node->numsurfaces)) { - surf = r_worldentity.model->surfaces + node->firstsurface; + surf = brush->surfaces + node->firstsurface; for (; c; c--, surf++) { if (surf->visframe != r_visframecount) continue; @@ -696,7 +702,7 @@ visit_node (mnode_t *node, int side, vulkan_ctx_t *ctx) if (side ^ (surf->flags & SURF_PLANEBACK)) continue; // wrong side - chain_surface (surf, 0, 0, ctx); + chain_surface (brush, surf, 0, 0, ctx); } } } @@ -714,7 +720,7 @@ test_node (mnode_t *node) } static void -R_VisitWorldNodes (model_t *model, vulkan_ctx_t *ctx) +R_VisitWorldNodes (mod_brush_t *brush, vulkan_ctx_t *ctx) { typedef struct { mnode_t *node; @@ -726,9 +732,9 @@ R_VisitWorldNodes (model_t *model, vulkan_ctx_t *ctx) mnode_t *front; int side; - node = model->nodes; + node = brush->nodes; // +2 for paranoia - node_stack = alloca ((model->depth + 2) * sizeof (rstack_t)); + node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; while (1) { @@ -744,7 +750,7 @@ R_VisitWorldNodes (model_t *model, vulkan_ctx_t *ctx) } if (front->contents < 0 && front->contents != CONTENTS_SOLID) visit_leaf ((mleaf_t *) front); - visit_node (node, side, ctx); + visit_node (brush, node, side, ctx); node = node->children[!side]; } if (node->contents < 0 && node->contents != CONTENTS_SOLID) @@ -753,7 +759,7 @@ R_VisitWorldNodes (model_t *model, vulkan_ctx_t *ctx) node_ptr--; node = node_ptr->node; side = node_ptr->side; - visit_node (node, side, ctx); + visit_node (brush, node, side, ctx); node = node->children[!side]; continue; } @@ -1099,19 +1105,21 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) bspctx_t *bctx = ctx->bsp_context; bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; entity_t worldent; + mod_brush_t *brush; clear_texture_chains (bctx); // do this first for water and skys bframe->index_count = 0; memset (&worldent, 0, sizeof (worldent)); worldent.model = r_worldentity.model; + brush = &r_worldentity.model->brush; //vulktex_t *tex = r_worldentity.model->skytexture->render; //bctx->skysheet_tex = tex->tex; currententity = &worldent; - R_VisitWorldNodes (worldent.model, ctx); + R_VisitWorldNodes (brush, ctx); if (r_drawentities->int_val) { entity_t *ent; for (ent = r_ent_queue; ent; ent = ent->next) { diff --git a/libs/video/renderer/vulkan/vulkan_lightmap.c b/libs/video/renderer/vulkan/vulkan_lightmap.c index 623bd9d94..ca5d433e8 100644 --- a/libs/video/renderer/vulkan/vulkan_lightmap.c +++ b/libs/video/renderer/vulkan/vulkan_lightmap.c @@ -125,7 +125,7 @@ add_dynamic_lights (msurface_t *surf, float *block) } void -Vulkan_BuildLightMap (msurface_t *surf, vulkan_ctx_t *ctx) +Vulkan_BuildLightMap (mod_brush_t *brush, msurface_t *surf, vulkan_ctx_t *ctx) { bspctx_t *bctx = ctx->bsp_context; int smax, tmax, size; @@ -142,7 +142,7 @@ Vulkan_BuildLightMap (msurface_t *surf, vulkan_ctx_t *ctx) block = QFV_SubpicBatch (surf->lightpic, bctx->light_stage); // set to full bright if no light data - if (!r_worldentity.model->lightdata) { + if (!brush->lightdata) { out = block; while (size-- > 0) { *out++ = 1; @@ -219,6 +219,7 @@ Vulkan_BuildLightmaps (model_t **models, int num_models, vulkan_ctx_t *ctx) bspctx_t *bctx = ctx->bsp_context; int i, j; model_t *m; + mod_brush_t *brush; QFV_ScrapClear (bctx->light_scrap); @@ -228,13 +229,14 @@ Vulkan_BuildLightmaps (model_t **models, int num_models, vulkan_ctx_t *ctx) m = models[j]; if (!m) break; - if (m->path[0] == '*') { + if (m->path[0] == '*' || m->type != mod_brush) { // sub model surfaces are processed as part of the main model continue; } + brush = &m->brush; // non-bsp models don't have surfaces. - for (i = 0; i < m->numsurfaces; i++) { - msurface_t *surf = m->surfaces + i; + for (i = 0; i < brush->numsurfaces; i++) { + msurface_t *surf = brush->surfaces + i; surf->lightpic = 0; // paranoia if (surf->flags & SURF_DRAWTURB) { continue; @@ -251,15 +253,16 @@ Vulkan_BuildLightmaps (model_t **models, int num_models, vulkan_ctx_t *ctx) if (!m) { break; } - if (m->path[0] == '*') { + if (m->path[0] == '*' || m->type != mod_brush) { // sub model surfaces are processed as part of the main model continue; } + brush = &m->brush; // non-bsp models don't have surfaces. - for (i = 0; i < m->numsurfaces; i++) { - msurface_t *surf = m->surfaces + i; + for (i = 0; i < brush->numsurfaces; i++) { + msurface_t *surf = brush->surfaces + i; if (surf->lightpic) { - Vulkan_BuildLightMap (surf, ctx); + Vulkan_BuildLightMap (brush, surf, ctx); } } } diff --git a/nq/source/cl_chase.c b/nq/source/cl_chase.c index 92903bbfc..5d23817cd 100644 --- a/nq/source/cl_chase.c +++ b/nq/source/cl_chase.c @@ -86,7 +86,7 @@ TraceLine (vec3_t start, vec3_t end, vec3_t impact) memset (&trace, 0, sizeof (trace)); trace.fraction = 1; - MOD_TraceLine (cl.worldmodel->hulls, 0, start, end, &trace); + MOD_TraceLine (cl.worldmodel->brush.hulls, 0, start, end, &trace); VectorCopy (trace.endpos, impact); } diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index 6f6e90e29..ce76ebf71 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -381,7 +381,7 @@ CL_RelinkEntities (void) if (i != cl.viewentity || chase_active->int_val) { if (ent->efrag) r_funcs->R_RemoveEfrags (ent); - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } VectorCopy (ent->origin, ent->old_origin); } else { @@ -416,10 +416,10 @@ CL_RelinkEntities (void) if (ent->efrag) { if (!VectorCompare (ent->origin, ent->old_origin)) { r_funcs->R_RemoveEfrags (ent); - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } } else { - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } } } diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index 981f72714..3b076b43f 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -301,7 +301,7 @@ map_ent (const char *mapname) edicts = ED_Parse (&edpr, buf); free (buf); } else { - edicts = ED_Parse (&edpr, cl.model_precache[1]->entities); + edicts = ED_Parse (&edpr, cl.model_precache[1]->brush.entities); } free (name); return edicts; @@ -315,7 +315,7 @@ CL_NewMap (const char *mapname) Hunk_Check (); // make sure nothing is hurt Sbar_CenterPrint (0); - if (cl.model_precache[1] && cl.model_precache[1]->entities) { + if (cl.model_precache[1] && cl.model_precache[1]->brush.entities) { cl.edicts = map_ent (mapname); if (cl.edicts) { cl.worldspawn = PL_ObjectAtIndex (cl.edicts, 0); @@ -795,7 +795,7 @@ CL_ParseStatic (int version) VectorCopy (baseline.origin, ent->origin); CL_TransformEntity (ent, baseline.angles, true); - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } static void diff --git a/nq/source/cl_tent.c b/nq/source/cl_tent.c index 89f05ee74..2286d829a 100644 --- a/nq/source/cl_tent.c +++ b/nq/source/cl_tent.c @@ -294,7 +294,7 @@ beam_setup (beam_t *b, qboolean transform) CL_TransformEntity (&tent->ent, ang, true); } VectorCopy (ang, tent->ent.angles); - r_funcs->R_AddEfrags (&tent->ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, &tent->ent); } } @@ -588,7 +588,7 @@ CL_UpdateExplosions (void) ent->frame = f; if (!ent->efrag) - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } } diff --git a/nq/source/sv_main.c b/nq/source/sv_main.c index 9ee006e3b..38604e66c 100644 --- a/nq/source/sv_main.c +++ b/nq/source/sv_main.c @@ -432,9 +432,9 @@ SV_AddToFatPVS (vec3_t org, mnode_t *node) static byte * SV_FatPVS (vec3_t org) { - fatbytes = (sv.worldmodel->numleafs + 31) >> 3; + fatbytes = (sv.worldmodel->brush.numleafs + 31) >> 3; memset (fatpvs, 0, fatbytes); - SV_AddToFatPVS (org, sv.worldmodel->nodes); + SV_AddToFatPVS (org, sv.worldmodel->brush.nodes); return fatpvs; } @@ -1189,7 +1189,7 @@ SV_SpawnServer (const char *server) sv.model_precache[0] = sv_pr_state.pr_strings; sv.model_precache[1] = sv.modelname; - for (i = 1; i < sv.worldmodel->numsubmodels; i++) { + for (i = 1; i < sv.worldmodel->brush.numsubmodels; i++) { sv.model_precache[1 + i] = localmodels[i]; sv.models[i + 1] = Mod_ForName (localmodels[i], false); } @@ -1220,7 +1220,7 @@ SV_SpawnServer (const char *server) ED_LoadFromFile (&sv_pr_state, (char *) buf); free (buf); } else { - ED_LoadFromFile (&sv_pr_state, sv.worldmodel->entities); + ED_LoadFromFile (&sv_pr_state, sv.worldmodel->brush.entities); } sv.active = true; diff --git a/nq/source/sv_pr_cmds.c b/nq/source/sv_pr_cmds.c index 0084b3b99..096010f77 100644 --- a/nq/source/sv_pr_cmds.c +++ b/nq/source/sv_pr_cmds.c @@ -585,7 +585,7 @@ PF_newcheckclient (progs_t *pr, int check) VectorAdd (SVvector (ent, origin), SVvector (ent, view_ofs), org); leaf = Mod_PointInLeaf (org, sv.worldmodel); pvs = Mod_LeafPVS (leaf, sv.worldmodel); - memcpy (checkpvs, pvs, (sv.worldmodel->numleafs + 7) >> 3); + memcpy (checkpvs, pvs, (sv.worldmodel->brush.numleafs + 7) >> 3); return i; } @@ -630,7 +630,7 @@ PF_checkclient (progs_t *pr) self = PROG_TO_EDICT (pr, *sv_globals.self); VectorAdd (SVvector (self, origin), SVvector (self, view_ofs), view); leaf = Mod_PointInLeaf (view, sv.worldmodel); - l = (leaf - sv.worldmodel->leafs) - 1; + l = (leaf - sv.worldmodel->brush.leafs) - 1; if ((l < 0) || !(checkpvs[l >> 3] & (1 << (l & 7)))) { c_notvis++; RETURN_EDICT (pr, sv.edicts); diff --git a/nq/source/world.c b/nq/source/world.c index f7d379a2d..5f8bce898 100644 --- a/nq/source/world.c +++ b/nq/source/world.c @@ -245,7 +245,7 @@ SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs, PR_GetString (&sv_pr_state, SVstring (ent, classname))); - hull_list = model->hull_list; + hull_list = model->brush.hull_list; } if (hull_list) { // decide which clipping hull to use, based on the size @@ -425,7 +425,7 @@ SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) leaf = (mleaf_t *) node; edict_leaf = alloc_edict_leaf (); - edict_leaf->leafnum = leaf - sv.worldmodel->leafs - 1; + edict_leaf->leafnum = leaf - sv.worldmodel->brush.leafs - 1; edict_leaf->next = SVdata (ent)->leafs; SVdata (ent)->leafs = edict_leaf; return; @@ -497,7 +497,7 @@ SV_LinkEdict (edict_t *ent, qboolean touch_triggers) // link to PVS leafs free_edict_leafs (&SVdata (ent)->leafs); if (SVfloat (ent, modelindex)) - SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); + SV_FindTouchedLeafs (ent, sv.worldmodel->brush.nodes); if (SVfloat (ent, solid) == SOLID_NOT) return; @@ -560,7 +560,7 @@ SV_PointContents (const vec3_t p) { int cont; - cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); + cont = SV_HullPointContents (&sv.worldmodel->brush.hulls[0], 0, p); if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) cont = CONTENTS_WATER; return cont; @@ -569,7 +569,7 @@ SV_PointContents (const vec3_t p) int SV_TruePointContents (const vec3_t p) { - return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); + return SV_HullPointContents (&sv.worldmodel->brush.hulls[0], 0, p); } /* @@ -903,7 +903,7 @@ SV_TestPlayerPosition (edict_t *ent, const vec3_t origin) vec3_t boxmins, boxmaxs, offset; // check world first - hull = &sv.worldmodel->hulls[1]; + hull = &sv.worldmodel->brush.hulls[1]; if (SV_HullPointContents (hull, hull->firstclipnode, origin) != CONTENTS_EMPTY) return sv.edicts; diff --git a/qw/source/cl_chase.c b/qw/source/cl_chase.c index 2e5583429..8a3d6419d 100644 --- a/qw/source/cl_chase.c +++ b/qw/source/cl_chase.c @@ -86,7 +86,7 @@ TraceLine (vec3_t start, vec3_t end, vec3_t impact) memset (&trace, 0, sizeof (trace)); trace.fraction = 1; - MOD_TraceLine (cl.worldmodel->hulls, 0, start, end, &trace); + MOD_TraceLine (cl.worldmodel->brush.hulls, 0, start, end, &trace); VectorCopy (trace.endpos, impact); } diff --git a/qw/source/cl_entparse.c b/qw/source/cl_entparse.c index 3fdeda901..6fc04a4c4 100644 --- a/qw/source/cl_entparse.c +++ b/qw/source/cl_entparse.c @@ -542,7 +542,7 @@ CL_SetSolidEntities (void) continue; if (!cl.model_precache[state->modelindex]) continue; - if (cl.model_precache[state->modelindex]->hulls[1].firstclipnode + if (cl.model_precache[state->modelindex]->brush.hulls[1].firstclipnode || cl.model_precache[state->modelindex]->clipbox) { if (pmove.numphysent == MAX_PHYSENTS) { Sys_Printf ("WARNING: entity physent overflow, email " diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 24f14933b..7c95040ed 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -335,7 +335,7 @@ CL_LinkPacketEntities (void) if (i != cl.viewentity || chase_active->int_val) { if (ent->efrag) r_funcs->R_RemoveEfrags (ent); - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } VectorCopy (ent->origin, ent->old_origin); } else { @@ -370,15 +370,15 @@ CL_LinkPacketEntities (void) if (ent->efrag) { if (!VectorCompare (ent->origin, ent->old_origin)) { r_funcs->R_RemoveEfrags (ent); - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } } else { - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } } } if (!ent->efrag) - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); // rotate binary objects locally if (ent->model->flags & EF_ROTATE) { @@ -567,7 +567,7 @@ CL_LinkPlayers (void) } // stuff entity in map - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); if (state->pls.effects & EF_FLAG1) CL_AddFlagModels (ent, 0, j); diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 21c7dabd2..f38b30537 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -288,7 +288,7 @@ map_ent (const char *mapname) edicts = ED_Parse (&edpr, buf); free (buf); } else { - edicts = ED_Parse (&edpr, cl.model_precache[1]->entities); + edicts = ED_Parse (&edpr, cl.model_precache[1]->brush.entities); } free (name); return edicts; @@ -305,7 +305,7 @@ CL_NewMap (const char *mapname) Hunk_Check (); // make sure nothing is hurt Sbar_CenterPrint (0); - if (cl.model_precache[1] && cl.model_precache[1]->entities) { + if (cl.model_precache[1] && cl.model_precache[1]->brush.entities) { cl.edicts = map_ent (mapname); if (cl.edicts) { cl.worldspawn = PL_ObjectAtIndex (cl.edicts, 0); @@ -404,7 +404,7 @@ Model_NextDownload (void) MSG_WriteByte (&cls.netchan.message, clc_stringcmd); MSG_WriteString (&cls.netchan.message, va (0, prespawn_name, cl.servercount, - cl.worldmodel->checksum2)); + cl.worldmodel->brush.checksum2)); } } @@ -986,7 +986,7 @@ CL_ParseStatic (void) VectorCopy (es.origin, ent->origin); CL_TransformEntity (ent, es.angles, true); - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } static void diff --git a/qw/source/cl_tent.c b/qw/source/cl_tent.c index 950734bea..c24f1f0bc 100644 --- a/qw/source/cl_tent.c +++ b/qw/source/cl_tent.c @@ -298,7 +298,7 @@ beam_setup (beam_t *b, qboolean transform) CL_TransformEntity (&tent->ent, ang, true); } VectorCopy (ang, tent->ent.angles); - r_funcs->R_AddEfrags (&tent->ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, &tent->ent); } } @@ -595,7 +595,7 @@ CL_UpdateExplosions (void) ent->frame = f; if (!ent->efrag) - r_funcs->R_AddEfrags (ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } } @@ -658,7 +658,7 @@ CL_ParseProjectiles (qboolean nail2) pr->angles[2] = 0; CL_TransformEntity (&tent->ent, tent->ent.angles, true); - r_funcs->R_AddEfrags (&tent->ent); + r_funcs->R_AddEfrags (&cl.worldmodel->brush, &tent->ent); } *tail = cl_projectiles; diff --git a/qw/source/pmovetst.c b/qw/source/pmovetst.c index 6b3857feb..b79e860e0 100644 --- a/qw/source/pmovetst.c +++ b/qw/source/pmovetst.c @@ -136,7 +136,7 @@ PM_PointContents (const vec3_t p) hull_t *hull; plane_t *plane; - hull = &pmove.physents[0].model->hulls[0]; + hull = &pmove.physents[0].model->brush.hulls[0]; num = hull->firstclipnode; @@ -174,7 +174,7 @@ PM_TestPlayerPosition (const vec3_t pos) pe = &pmove.physents[i]; // get the clipping hull if (pe->model) - hull = &pmove.physents[i].model->hulls[1]; + hull = &pmove.physents[i].model->brush.hulls[1]; else { VectorSubtract (pe->mins, player_maxs, mins); VectorSubtract (pe->maxs, player_mins, maxs); @@ -235,7 +235,7 @@ PM_PlayerMove (const vec3_t start, const vec3_t end) } else { check_box = 1; if (pe->model) { - hull = &pe->model->hulls[1]; + hull = &pe->model->brush.hulls[1]; VectorSubtract (pe->model->mins, player_maxs, mins); VectorSubtract (pe->model->maxs, player_mins, maxs); } else { diff --git a/qw/source/sv_ents.c b/qw/source/sv_ents.c index 09e19ba83..a5d6b4db9 100644 --- a/qw/source/sv_ents.c +++ b/qw/source/sv_ents.c @@ -99,9 +99,9 @@ SV_AddToFatPVS (vec3_t org, mnode_t *node) static byte * SV_FatPVS (vec3_t org) { - fatbytes = (sv.worldmodel->numleafs + 31) >> 3; + fatbytes = (sv.worldmodel->brush.numleafs + 31) >> 3; memset (fatpvs, 0, fatbytes); - SV_AddToFatPVS (org, sv.worldmodel->nodes); + SV_AddToFatPVS (org, sv.worldmodel->brush.nodes); return fatpvs; } @@ -738,7 +738,7 @@ calc_pvs (delta_t *delta) if (pvs == NULL) { pvs = SV_FatPVS (org); } else { - SV_AddToFatPVS (org, sv.worldmodel->nodes); + SV_AddToFatPVS (org, sv.worldmodel->brush.nodes); } } } diff --git a/qw/source/sv_init.c b/qw/source/sv_init.c index 8535dacb6..e0a370f92 100644 --- a/qw/source/sv_init.c +++ b/qw/source/sv_init.c @@ -229,7 +229,7 @@ SV_CalcPHS (void) SV_Printf ("Building PHS...\n"); - num = sv.worldmodel->numleafs; + num = sv.worldmodel->brush.numleafs; rowwords = (num + 31) >> 5; rowbytes = rowwords * 4; @@ -237,7 +237,8 @@ SV_CalcPHS (void) scan = sv.pvs; vcount = 0; for (i = 0; i < num; i++, scan += rowbytes) { - memcpy (scan, Mod_LeafPVS (sv.worldmodel->leafs + i, sv.worldmodel), + memcpy (scan, Mod_LeafPVS (sv.worldmodel->brush.leafs + i, + sv.worldmodel), rowbytes); if (i == 0) continue; @@ -402,7 +403,7 @@ SV_SpawnServer (const char *server) sv.model_precache[0] = sv_pr_state.pr_strings; sv.model_precache[1] = sv.modelname; sv.models[1] = sv.worldmodel; - for (i = 1; i < sv.worldmodel->numsubmodels; i++) { + for (i = 1; i < sv.worldmodel->brush.numsubmodels; i++) { sv.model_precache[1 + i] = localmodels[i]; sv.models[i + 1] = Mod_ForName (localmodels[i], false); } @@ -443,7 +444,7 @@ SV_SpawnServer (const char *server) ED_LoadFromFile (&sv_pr_state, (char *) buf); free (buf); } else { - ED_LoadFromFile (&sv_pr_state, sv.worldmodel->entities); + ED_LoadFromFile (&sv_pr_state, sv.worldmodel->brush.entities); } // look up some model indexes for specialized message compression diff --git a/qw/source/sv_pr_cmds.c b/qw/source/sv_pr_cmds.c index 7298dc74a..b8dc58de0 100644 --- a/qw/source/sv_pr_cmds.c +++ b/qw/source/sv_pr_cmds.c @@ -506,7 +506,7 @@ PF_newcheckclient (progs_t *pr, int check) VectorAdd (SVvector (ent, origin), SVvector (ent, view_ofs), org); leaf = Mod_PointInLeaf (org, sv.worldmodel); pvs = Mod_LeafPVS (leaf, sv.worldmodel); - memcpy (checkpvs, pvs, (sv.worldmodel->numleafs + 7) >> 3); + memcpy (checkpvs, pvs, (sv.worldmodel->brush.numleafs + 7) >> 3); return i; } @@ -551,7 +551,7 @@ PF_checkclient (progs_t *pr) self = PROG_TO_EDICT (pr, *sv_globals.self); VectorAdd (SVvector (self, origin), SVvector (self, view_ofs), view); leaf = Mod_PointInLeaf (view, sv.worldmodel); - l = (leaf - sv.worldmodel->leafs) - 1; + l = (leaf - sv.worldmodel->brush.leafs) - 1; if ((l < 0) || !(checkpvs[l >> 3] & (1 << (l & 7)))) { c_notvis++; RETURN_EDICT (pr, sv.edicts); diff --git a/qw/source/sv_send.c b/qw/source/sv_send.c index 400b9484e..0948e6f18 100644 --- a/qw/source/sv_send.c +++ b/qw/source/sv_send.c @@ -297,12 +297,13 @@ SV_Multicast (const vec3_t origin, int to) int leafnum, j; mleaf_t *leaf; qboolean reliable; + mod_brush_t *brush = &sv.worldmodel->brush; leaf = Mod_PointInLeaf (origin, sv.worldmodel); if (!leaf) leafnum = 0; else - leafnum = leaf - sv.worldmodel->leafs; + leafnum = leaf - sv.worldmodel->brush.leafs; reliable = false; @@ -316,13 +317,13 @@ SV_Multicast (const vec3_t origin, int to) case MULTICAST_PHS_R: reliable = true; // intentional fallthrough case MULTICAST_PHS: - mask = sv.phs + leafnum * 4 * ((sv.worldmodel->numleafs + 31) >> 5); + mask = sv.phs + leafnum * 4 * ((brush->numleafs + 31) >> 5); break; case MULTICAST_PVS_R: reliable = true; // intentional fallthrough case MULTICAST_PVS: - mask = sv.pvs + leafnum * 4 * ((sv.worldmodel->numleafs + 31) >> 5); + mask = sv.pvs + leafnum * 4 * ((brush->numleafs + 31) >> 5); break; default: @@ -347,7 +348,7 @@ SV_Multicast (const vec3_t origin, int to) sv.worldmodel); if (leaf) { // -1 is because pvs rows are 1 based, not 0 based like leafs - leafnum = leaf - sv.worldmodel->leafs - 1; + leafnum = leaf - brush->leafs - 1; if (!(mask[leafnum >> 3] & (1 << (leafnum & 7)))) { // SV_Printf ("supressed multicast\n"); continue; diff --git a/qw/source/sv_user.c b/qw/source/sv_user.c index 3fba2c17f..12c3de010 100644 --- a/qw/source/sv_user.c +++ b/qw/source/sv_user.c @@ -335,14 +335,15 @@ SV_PreSpawn_f (void *unused) // Sys_MaskPrintf (SYS_DEV, , "Client check = %d\n", check); - if (sv_mapcheck->int_val && check != sv.worldmodel->checksum && - check != sv.worldmodel->checksum2) { + if (sv_mapcheck->int_val && check != sv.worldmodel->brush.checksum && + check != sv.worldmodel->brush.checksum2) { SV_ClientPrintf (1, host_client, PRINT_HIGH, "Map model file does " "not match (%s), %i != %i/%i.\n" "You may need a new version of the map, or the " "proper install files.\n", - sv.modelname, check, sv.worldmodel->checksum, - sv.worldmodel->checksum2); + sv.modelname, check, + sv.worldmodel->brush.checksum, + sv.worldmodel->brush.checksum2); SV_DropClient (host_client); return; } diff --git a/qw/source/world.c b/qw/source/world.c index bbf4d930e..393daaf6f 100644 --- a/qw/source/world.c +++ b/qw/source/world.c @@ -245,7 +245,7 @@ SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs, PR_GetString (&sv_pr_state, SVstring (ent, classname))); - hull_list = model->hull_list; + hull_list = model->brush.hull_list; } if (hull_list) { // decide which clipping hull to use, based on the size @@ -425,7 +425,7 @@ SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) leaf = (mleaf_t *) node; edict_leaf = alloc_edict_leaf (); - edict_leaf->leafnum = leaf - sv.worldmodel->leafs - 1; + edict_leaf->leafnum = leaf - sv.worldmodel->brush.leafs - 1; edict_leaf->next = SVdata (ent)->leafs; SVdata (ent)->leafs = edict_leaf; return; @@ -497,7 +497,7 @@ SV_LinkEdict (edict_t *ent, qboolean touch_triggers) // link to PVS leafs free_edict_leafs (&SVdata (ent)->leafs); if (SVfloat (ent, modelindex)) - SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); + SV_FindTouchedLeafs (ent, sv.worldmodel->brush.nodes); if (SVfloat (ent, solid) == SOLID_NOT) return; @@ -560,7 +560,7 @@ SV_PointContents (const vec3_t p) { int cont; - cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); + cont = SV_HullPointContents (&sv.worldmodel->brush.hulls[0], 0, p); if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) cont = CONTENTS_WATER; return cont; @@ -569,7 +569,7 @@ SV_PointContents (const vec3_t p) int SV_TruePointContents (const vec3_t p) { - return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); + return SV_HullPointContents (&sv.worldmodel->brush.hulls[0], 0, p); } /* @@ -991,7 +991,7 @@ SV_TestPlayerPosition (edict_t *ent, const vec3_t origin) vec3_t boxmins, boxmaxs, offset; // check world first - hull = &sv.worldmodel->hulls[1]; + hull = &sv.worldmodel->brush.hulls[1]; if (SV_HullPointContents (hull, hull->firstclipnode, origin) != CONTENTS_EMPTY) return sv.edicts; From ea72d0c60e9e2ead63fbfdaa96a62d16c52cde86 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 1 Feb 2021 21:11:45 +0900 Subject: [PATCH 320/435] [model] Clean up the globals for alias models --- include/QF/Vulkan/qf_alias.h | 12 +- include/QF/model.h | 11 -- include/QF/plugin/vid_render.h | 12 +- include/mod_internal.h | 47 ++++--- libs/models/alias/gl_mesh.c | 118 ++++++++--------- libs/models/alias/gl_model_alias.c | 51 ++++---- libs/models/alias/glsl_model_alias.c | 75 +++++------ libs/models/alias/model_alias.c | 161 +++++++++++++----------- libs/models/alias/sw_model_alias.c | 75 ++++++----- libs/models/alias/vulkan_model_alias.c | 82 ++++++------ libs/video/renderer/vid_render_sw.c | 4 +- libs/video/renderer/vid_render_sw32.c | 4 +- libs/video/renderer/vid_render_vulkan.c | 18 +-- 13 files changed, 350 insertions(+), 320 deletions(-) diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index dac8f4ca7..ebf4f6996 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -102,14 +102,16 @@ typedef struct aliasctx_s { struct vulkan_ctx_s; struct entity_s; -void *Vulkan_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, - int gnum, qboolean group, +struct mod_alias_ctx_s; +void *Vulkan_Mod_LoadSkin (struct mod_alias_ctx_s *alias_ctx, byte *skin, + int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc, struct vulkan_ctx_s *ctx); -void Vulkan_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr, +void Vulkan_Mod_FinalizeAliasModel (struct mod_alias_ctx_s *alias_ctx, struct vulkan_ctx_s *ctx); -void Vulkan_Mod_LoadExternalSkins (model_t *mod, struct vulkan_ctx_s *ctx); -void Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, +void Vulkan_Mod_LoadExternalSkins (struct mod_alias_ctx_s *alias_ctx, + struct vulkan_ctx_s *ctx); +void Vulkan_Mod_MakeAliasModelDisplayLists (struct mod_alias_ctx_s *alias_ctx, void *_m, int _s, int extra, struct vulkan_ctx_s *ctx); diff --git a/include/QF/model.h b/include/QF/model.h index 6d7dfe61d..a05d489a4 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -28,7 +28,6 @@ #ifndef __QF_model_h #define __QF_model_h -#include "QF/darray.h" #include "QF/qtypes.h" #include "QF/bspfile.h" #include "QF/spritegn.h" @@ -372,16 +371,6 @@ typedef struct { maliasframedesc_t frames[1]; } aliashdr_t; -typedef struct stvertset_s DARRAY_TYPE (stvert_t) stvertset_t; -typedef struct mtriangleset_s DARRAY_TYPE (mtriangle_t) mtriangleset_t; -typedef struct trivertxset_s DARRAY_TYPE (trivertx_t *) trivertxset_t; -extern aliashdr_t *pheader; -extern stvertset_t stverts; -extern mtriangleset_t triangles; -extern trivertxset_t poseverts; -extern int aliasbboxmins[3]; -extern int aliasbboxmaxs[3]; - // Whole model ================================================================ typedef enum {mod_brush, mod_sprite, mod_alias, mod_iqm} modtype_t; diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index bc80780e4..5d2ed3d18 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -37,6 +37,8 @@ struct plitem_s; struct cvar_s; struct skin_s; +struct mod_alias_ctx_s; + /* All video plugins must export these functions */ @@ -88,13 +90,13 @@ typedef struct vid_model_funcs_s { void (*Mod_LoadAliasModel) (model_t *mod, void *buffer, cache_allocator_t allocator); void (*Mod_LoadSpriteModel) (model_t *mod, void *buffer); - void (*Mod_MakeAliasModelDisplayLists) (model_t *m, aliashdr_t *hdr, + void (*Mod_MakeAliasModelDisplayLists) (struct mod_alias_ctx_s *alias_ctx, void *_m, int _s, int extra); - void *(*Mod_LoadSkin) (model_t *mod, byte *skin, int skinsize, int snum, - int gnum, + void *(*Mod_LoadSkin) (struct mod_alias_ctx_s *alias_ctx, byte *skin, + int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc); - void (*Mod_FinalizeAliasModel) (model_t *m, aliashdr_t *hdr); - void (*Mod_LoadExternalSkins) (model_t *mod); + void (*Mod_FinalizeAliasModel) (struct mod_alias_ctx_s *alias_ctx); + void (*Mod_LoadExternalSkins) (struct mod_alias_ctx_s *alias_ctx); void (*Mod_IQMFinish) (model_t *mod); int alias_cache; void (*Mod_SpriteLoadTexture) (model_t *mod, mspriteframe_t *pspriteframe, diff --git a/include/mod_internal.h b/include/mod_internal.h index f459bbeaa..d498ee9ce 100644 --- a/include/mod_internal.h +++ b/include/mod_internal.h @@ -1,11 +1,27 @@ #ifndef __mod_internal_h #define __mod_internal_h +#include "QF/darray.h" #include "QF/iqm.h" #include "QF/model.h" #include "QF/skin.h" #include "QF/plugin/vid_render.h" +typedef struct stvertset_s DARRAY_TYPE (stvert_t) stvertset_t; +typedef struct mtriangleset_s DARRAY_TYPE (mtriangle_t) mtriangleset_t; +typedef struct trivertxset_s DARRAY_TYPE (trivertx_t *) trivertxset_t; + +typedef struct mod_alias_ctx_s { + aliashdr_t *header; + model_t *mod; + stvertset_t stverts; + mtriangleset_t triangles; + trivertxset_t poseverts; + int aliasbboxmins[3]; + int aliasbboxmaxs[3]; + +} mod_alias_ctx_t; + int Mod_CalcFullbright (const byte *in, byte *out, int pixels); void Mod_ClearFullbright (const byte *in, byte *out, int pixels); void Mod_FloodFillSkin (byte *skin, int skinwidth, int skinheight); @@ -22,28 +38,29 @@ struct vulkan_ctx_s; extern vid_model_funcs_t *m_funcs; -void gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, +void gl_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra); -void *gl_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, - int gnum, qboolean group, maliasskindesc_t *skindesc); -void gl_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr); -void gl_Mod_LoadExternalSkins (model_t *mod); +void *gl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc); +void gl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx); +void gl_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx); void gl_Mod_IQMFinish (model_t *mod); -void glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, +void glsl_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra); -void *glsl_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, - int gnum, qboolean group, maliasskindesc_t *skindesc); -void glsl_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr); -void glsl_Mod_LoadExternalSkins (model_t *mod); +void *glsl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc); +void glsl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx); +void glsl_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx); void glsl_Mod_IQMFinish (model_t *mod); -void sw_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, +void sw_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra); -void *sw_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, - int gnum, qboolean group, maliasskindesc_t *skindesc); -void sw_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr); -void sw_Mod_LoadExternalSkins (model_t *mod); +void *sw_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc); void sw_Mod_IQMFinish (model_t *mod); void gl_Mod_LoadLighting (model_t *mod, bsp_t *bsp); diff --git a/libs/models/alias/gl_mesh.c b/libs/models/alias/gl_mesh.c index 6820000cf..73c65b56d 100644 --- a/libs/models/alias/gl_mesh.c +++ b/libs/models/alias/gl_mesh.c @@ -49,9 +49,6 @@ // ALIAS MODEL DISPLAY LIST GENERATION ======================================== -static model_t *aliasmodel; -static aliashdr_t *paliashdr; - static qboolean *used; static int used_size; @@ -126,14 +123,15 @@ add_strip (int vert, int tri) } static int -StripLength (int starttri, int startv) +StripLength (mod_alias_ctx_t *alias_ctx, int starttri, int startv) { + aliashdr_t *header = alias_ctx->header; int m1, m2, j, k; mtriangle_t *last, *check; used[starttri] = 2; - last = &triangles.a[starttri]; + last = &alias_ctx->triangles.a[starttri]; stripcount = 0; add_strip (last->vertindex[(startv) % 3], starttri); @@ -145,8 +143,8 @@ StripLength (int starttri, int startv) // look for a matching triangle nexttri: - for (j = starttri + 1, check = &triangles.a[starttri + 1]; - j < pheader->mdl.numtris; j++, check++) { + for (j = starttri + 1, check = &alias_ctx->triangles.a[starttri + 1]; + j < header->mdl.numtris; j++, check++) { if (check->facesfront != last->facesfront) continue; for (k = 0; k < 3; k++) { @@ -176,7 +174,7 @@ nexttri: done: // clear the temp used flags - for (j = starttri + 1; j < pheader->mdl.numtris; j++) + for (j = starttri + 1; j < header->mdl.numtris; j++) if (used[j] == 2) used[j] = 0; @@ -184,14 +182,15 @@ done: } static int -FanLength (int starttri, int startv) +FanLength (mod_alias_ctx_t *alias_ctx, int starttri, int startv) { + aliashdr_t *header = alias_ctx->header; int m1, m2, j, k; mtriangle_t *last, *check; used[starttri] = 2; - last = &triangles.a[starttri]; + last = &alias_ctx->triangles.a[starttri]; stripcount = 0; add_strip (last->vertindex[(startv) % 3], starttri); @@ -204,8 +203,8 @@ FanLength (int starttri, int startv) // look for a matching triangle nexttri: - for (j = starttri + 1, check = &triangles.a[starttri + 1]; - j < pheader->mdl.numtris; j++, check++) { + for (j = starttri + 1, check = &alias_ctx->triangles.a[starttri + 1]; + j < header->mdl.numtris; j++, check++) { if (check->facesfront != last->facesfront) continue; for (k = 0; k < 3; k++) { @@ -232,7 +231,7 @@ FanLength (int starttri, int startv) done: // clear the temp used flags - for (j = starttri + 1; j < pheader->mdl.numtris; j++) + for (j = starttri + 1; j < header->mdl.numtris; j++) if (used[j] == 2) used[j] = 0; @@ -246,8 +245,9 @@ FanLength (int starttri, int startv) for the model, which holds for all frames */ static void -BuildTris (void) +BuildTris (mod_alias_ctx_t *alias_ctx) { + aliashdr_t *header = alias_ctx->header; float s, t; int bestlen, len, startv, type, i, j, k; int besttype = 0; @@ -257,10 +257,10 @@ BuildTris (void) numorder = 0; numcommands = 0; stripcount = 0; - alloc_used (pheader->mdl.numtris); + alloc_used (header->mdl.numtris); memset (used, 0, used_size * sizeof (used[0])); - for (i = 0; i < pheader->mdl.numtris; i++) { + for (i = 0; i < header->mdl.numtris; i++) { // pick an unused triangle and start the trifan if (used[i]) continue; @@ -270,9 +270,9 @@ BuildTris (void) // type = 1; for (startv = 0; startv < 3; startv++) { if (type == 1) - len = StripLength (i, startv); + len = StripLength (alias_ctx, i, startv); else - len = FanLength (i, startv); + len = FanLength (alias_ctx, i, startv); if (len > bestlen) { besttype = type; bestlen = len; @@ -304,12 +304,13 @@ BuildTris (void) add_vertex (k); // emit s/t coords into the commands stream - s = stverts.a[k].s; - t = stverts.a[k].t; - if (!triangles.a[besttris[0]].facesfront && stverts.a[k].onseam) - s += pheader->mdl.skinwidth / 2; // on back side - s = (s + 0.5) / pheader->mdl.skinwidth; - t = (t + 0.5) / pheader->mdl.skinheight; + s = alias_ctx->stverts.a[k].s; + t = alias_ctx->stverts.a[k].t; + if (!alias_ctx->triangles.a[besttris[0]].facesfront + && alias_ctx->stverts.a[k].onseam) + s += header->mdl.skinwidth / 2; // on back side + s = (s + 0.5) / header->mdl.skinwidth; + t = (t + 0.5) / header->mdl.skinheight; memcpy (&tmp, &s, 4); add_command (tmp); @@ -321,10 +322,10 @@ BuildTris (void) add_command (0); // end of list marker Sys_MaskPrintf (SYS_DEV, "%3i tri %3i vert %3i cmd\n", - pheader->mdl.numtris, numorder, numcommands); + header->mdl.numtris, numorder, numcommands); allverts += numorder; - alltris += pheader->mdl.numtris; + alltris += header->mdl.numtris; if (bestverts) free (bestverts); @@ -333,9 +334,10 @@ BuildTris (void) } void -gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, +gl_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra) { + aliashdr_t *header = alias_ctx->header; dstring_t *cache, *fullpath; unsigned char model_digest[MDFOUR_DIGEST_BYTES]; unsigned char mesh_digest[MDFOUR_DIGEST_BYTES]; @@ -345,24 +347,21 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, qboolean remesh = true; qboolean do_cache = false; - aliasmodel = m; - paliashdr = hdr; - cache = dstring_new (); fullpath = dstring_new (); if (!gl_alias_render_tri->int_val) { if (gl_mesh_cache->int_val - && gl_mesh_cache->int_val <= paliashdr->mdl.numtris) { + && gl_mesh_cache->int_val <= header->mdl.numtris) { do_cache = true; mdfour (model_digest, (unsigned char *) _m, _s); // look for a cached version dstring_copystr (cache, "glquake/"); - dstring_appendstr (cache, m->path); - QFS_StripExtension (m->path + strlen ("progs/"), + dstring_appendstr (cache, alias_ctx->mod->path); + QFS_StripExtension (alias_ctx->mod->path + strlen ("progs/"), cache->str + strlen ("glquake/")); dstring_appendstr (cache, ".qfms"); @@ -433,9 +432,9 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, } if (remesh) { // build it from scratch - Sys_MaskPrintf (SYS_DEV, "meshing %s...\n", m->path); + Sys_MaskPrintf (SYS_DEV, "meshing %s...\n", alias_ctx->mod->path); - BuildTris (); // trifans or lists + BuildTris (alias_ctx); // trifans or lists if (do_cache) { // save out the cached version @@ -474,35 +473,36 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, } // save the data out - paliashdr->poseverts = numorder; + header->poseverts = numorder; cmds = Hunk_Alloc (numcommands * sizeof (int)); - paliashdr->commands = (byte *) cmds - (byte *) paliashdr; + header->commands = (byte *) cmds - (byte *) header; memcpy (cmds, commands, numcommands * sizeof (int)); } else { tex_coord_t *tex_coord; numorder = 0; - for (i=0; i < pheader->mdl.numtris; i++) { - add_vertex(triangles.a[i].vertindex[0]); - add_vertex(triangles.a[i].vertindex[1]); - add_vertex(triangles.a[i].vertindex[2]); + for (i=0; i < header->mdl.numtris; i++) { + add_vertex(alias_ctx->triangles.a[i].vertindex[0]); + add_vertex(alias_ctx->triangles.a[i].vertindex[1]); + add_vertex(alias_ctx->triangles.a[i].vertindex[2]); } - paliashdr->poseverts = numorder; + header->poseverts = numorder; tex_coord = Hunk_Alloc (numorder * sizeof(tex_coord_t)); - paliashdr->tex_coord = (byte *) tex_coord - (byte *) paliashdr; + header->tex_coord = (byte *) tex_coord - (byte *) header; for (i=0; i < numorder; i++) { float s, t; int k; k = vertexorder[i]; - s = stverts.a[k].s; - t = stverts.a[k].t; - if (!triangles.a[i/3].facesfront && stverts.a[k].onseam) - s += pheader->mdl.skinwidth / 2; // on back side - s = (s + 0.5) / pheader->mdl.skinwidth; - t = (t + 0.5) / pheader->mdl.skinheight; + s = alias_ctx->stverts.a[k].s; + t = alias_ctx->stverts.a[k].t; + if (!alias_ctx->triangles.a[i/3].facesfront + && alias_ctx->stverts.a[k].onseam) + s += header->mdl.skinwidth / 2; // on back side + s = (s + 0.5) / header->mdl.skinwidth; + t = (t + 0.5) / header->mdl.skinheight; tex_coord[i].st[0] = s; tex_coord[i].st[1] = t; } @@ -510,11 +510,11 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, if (extra) { trivertx16_t *verts; - verts = Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts + verts = Hunk_Alloc (header->numposes * header->poseverts * sizeof (trivertx16_t)); - paliashdr->posedata = (byte *) verts - (byte *) paliashdr; - for (i = 0; i < paliashdr->numposes; i++) { - trivertx_t *pv = poseverts.a[i]; + header->posedata = (byte *) verts - (byte *) header; + for (i = 0; i < header->numposes; i++) { + trivertx_t *pv = alias_ctx->poseverts.a[i]; for (j = 0; j < numorder; j++) { trivertx16_t v; // convert MD16's split coordinates into something a little @@ -523,21 +523,21 @@ gl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // fractional bits of the vertex, giving 8.8. However, it's // easier for us to multiply everything by 256 and adjust the // model scale appropriately - VectorMultAdd (pv[vertexorder[j] + hdr->mdl.numverts].v, + VectorMultAdd (pv[vertexorder[j] + header->mdl.numverts].v, 256, pv[vertexorder[j]].v, v.v); v.lightnormalindex = - poseverts.a[i][vertexorder[j]].lightnormalindex; + alias_ctx->poseverts.a[i][vertexorder[j]].lightnormalindex; *verts++ = v; } } } else { trivertx_t *verts; - verts = Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts + verts = Hunk_Alloc (header->numposes * header->poseverts * sizeof (trivertx_t)); - paliashdr->posedata = (byte *) verts - (byte *) paliashdr; - for (i = 0; i < paliashdr->numposes; i++) { + header->posedata = (byte *) verts - (byte *) header; + for (i = 0; i < header->numposes; i++) { for (j = 0; j < numorder; j++) - *verts++ = poseverts.a[i][vertexorder[j]]; + *verts++ = alias_ctx->poseverts.a[i][vertexorder[j]]; } } dstring_delete (cache); diff --git a/libs/models/alias/gl_model_alias.c b/libs/models/alias/gl_model_alias.c index dec3a6e98..4b8d6ccb7 100644 --- a/libs/models/alias/gl_model_alias.c +++ b/libs/models/alias/gl_model_alias.c @@ -53,36 +53,38 @@ #include "compat.h" void * -gl_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc) +gl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc) { + aliashdr_t *header = alias_ctx->header; byte *pskin; char modname[MAX_QPATH + 4]; int fb_texnum = 0, texnum = 0; dstring_t *name = dstring_new (); - pskin = Hunk_AllocName (skinsize, mod->name); - skindesc->skin = (byte *) pskin - (byte *) pheader; + pskin = Hunk_AllocName (skinsize, alias_ctx->mod->name); + skindesc->skin = (byte *) pskin - (byte *) header; memcpy (pskin, skin, skinsize); - Mod_FloodFillSkin (pskin, pheader->mdl.skinwidth, pheader->mdl.skinheight); + Mod_FloodFillSkin (pskin, header->mdl.skinwidth, header->mdl.skinheight); // save 8 bit texels for the player model to remap // FIXME remove model restriction - if (strequal (mod->path, "progs/player.mdl")) - gl_Skin_SetPlayerSkin (pheader->mdl.skinwidth, pheader->mdl.skinheight, + if (strequal (alias_ctx->mod->path, "progs/player.mdl")) + gl_Skin_SetPlayerSkin (header->mdl.skinwidth, header->mdl.skinheight, pskin); - QFS_StripExtension (mod->path, modname); + QFS_StripExtension (alias_ctx->mod->path, modname); - if (!mod->fullbright) { + if (!alias_ctx->mod->fullbright) { if (group) { dsprintf (name, "fb_%s_%i_%i", modname, snum, gnum); } else { dsprintf (name, "fb_%s_%i", modname, snum); } - fb_texnum = Mod_Fullbright (pskin, pheader->mdl.skinwidth, - pheader->mdl.skinheight, name->str); + fb_texnum = Mod_Fullbright (pskin, header->mdl.skinwidth, + header->mdl.skinheight, name->str); Sys_MaskPrintf (SYS_GLT, "%s %d\n", name->str, fb_texnum); } if (group) { @@ -90,23 +92,25 @@ gl_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, int gnum, } else { dsprintf (name, "%s_%i", modname, snum); } - texnum = GL_LoadTexture (name->str, pheader->mdl.skinwidth, - pheader->mdl.skinheight, pskin, true, false, 1); + texnum = GL_LoadTexture (name->str, header->mdl.skinwidth, + header->mdl.skinheight, pskin, true, false, 1); Sys_MaskPrintf (SYS_GLT, "%s %d\n", name->str, texnum); skindesc->texnum = texnum; skindesc->fb_texnum = fb_texnum; - mod->hasfullbrights = fb_texnum; + alias_ctx->mod->hasfullbrights = fb_texnum; dstring_delete (name); // alpha param was true for non group skins return skin + skinsize; } void -gl_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr) +gl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx) { - if (strequal (m->path, "progs/eyes.mdl")) { - hdr->mdl.scale_origin[2] -= (22 + 8); - VectorScale (hdr->mdl.scale, 2, hdr->mdl.scale); + aliashdr_t *header = alias_ctx->header; + + if (strequal (alias_ctx->mod->path, "progs/eyes.mdl")) { + header->mdl.scale_origin[2] -= (22 + 8); + VectorScale (header->mdl.scale, 2, header->mdl.scale); } } @@ -150,25 +154,26 @@ Mod_LoadExternalSkin (maliasskindesc_t *pskindesc, char *filename) } void -gl_Mod_LoadExternalSkins (model_t *mod) +gl_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx) { + aliashdr_t *header = alias_ctx->header; char modname[MAX_QPATH + 4]; int i, j; maliasskindesc_t *pskindesc; maliasskingroup_t *pskingroup; dstring_t *filename = dstring_new (); - QFS_StripExtension (mod->path, modname); + QFS_StripExtension (alias_ctx->mod->path, modname); - for (i = 0; i < pheader->mdl.numskins; i++) { + for (i = 0; i < header->mdl.numskins; i++) { pskindesc = ((maliasskindesc_t *) - ((byte *) pheader + pheader->skindesc)) + i; + ((byte *) header + header->skindesc)) + i; if (pskindesc->type == ALIAS_SKIN_SINGLE) { dsprintf (filename, "%s_%i", modname, i); Mod_LoadExternalSkin (pskindesc, filename->str); } else { pskingroup = (maliasskingroup_t *) - ((byte *) pheader + pskindesc->skin); + ((byte *) header + pskindesc->skin); for (j = 0; j < pskingroup->numskins; j++) { dsprintf (filename, "%s_%i_%i", modname, i, j); diff --git a/libs/models/alias/glsl_model_alias.c b/libs/models/alias/glsl_model_alias.c index 609fa01b7..c48500ad7 100644 --- a/libs/models/alias/glsl_model_alias.c +++ b/libs/models/alias/glsl_model_alias.c @@ -58,24 +58,24 @@ static void glsl_alias_clear (model_t *m, void *data) { int i, j; - aliashdr_t *hdr; + aliashdr_t *header; GLuint bufs[2]; maliasskindesc_t *skins; maliasskingroup_t *group; m->needload = true; - if (!(hdr = m->aliashdr)) - hdr = Cache_Get (&m->cache); + if (!(header = m->aliashdr)) + header = Cache_Get (&m->cache); - bufs[0] = hdr->posedata; - bufs[1] = hdr->commands; + bufs[0] = header->posedata; + bufs[1] = header->commands; qfeglDeleteBuffers (2, bufs); - skins = ((maliasskindesc_t *) ((byte *) hdr + hdr->skindesc)); - for (i = 0; i < hdr->mdl.numskins; i++) { + skins = ((maliasskindesc_t *) ((byte *) header + header->skindesc)); + for (i = 0; i < header->mdl.numskins; i++) { if (skins[i].type == ALIAS_SKIN_GROUP) { - group = (maliasskingroup_t *) ((byte *) hdr + skins[i].skin); + group = (maliasskingroup_t *) ((byte *) header + skins[i].skin); for (j = 0; j < group->numskins; j++) { GLSL_ReleaseTexture (group->skindescs[j].texnum); } @@ -91,44 +91,49 @@ glsl_alias_clear (model_t *m, void *data) } void * -glsl_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, int gnum, - qboolean group, maliasskindesc_t *skindesc) +glsl_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc) { + aliashdr_t *header = alias_ctx->header; byte *tskin; const char *name; int w, h; - w = pheader->mdl.skinwidth; - h = pheader->mdl.skinheight; + w = header->mdl.skinwidth; + h = header->mdl.skinheight; tskin = malloc (skinsize); memcpy (tskin, skin, skinsize); Mod_FloodFillSkin (tskin, w, h); if (group) - name = va (0, "%s_%i_%i", mod->path, snum, gnum); + name = va (0, "%s_%i_%i", alias_ctx->mod->path, snum, gnum); else - name = va (0, "%s_%i", mod->path, snum); + name = va (0, "%s_%i", alias_ctx->mod->path, snum); skindesc->texnum = GLSL_LoadQuakeTexture (name, w, h, tskin); free (tskin); return skin + skinsize; } void -glsl_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr) +glsl_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx) { - if (hdr->mdl.ident == HEADER_MDL16) - VectorScale (hdr->mdl.scale, 1/256.0, hdr->mdl.scale); - m->clear = glsl_alias_clear; + aliashdr_t *header = alias_ctx->header; + + if (header->mdl.ident == HEADER_MDL16) + VectorScale (header->mdl.scale, 1/256.0, header->mdl.scale); + alias_ctx->mod->clear = glsl_alias_clear; } void -glsl_Mod_LoadExternalSkins (model_t *mod) +glsl_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx) { } void -glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, +glsl_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra) { + aliashdr_t *header = alias_ctx->header; mtriangle_t *tris; stvert_t *st; aliasvrt_t *verts; @@ -142,12 +147,12 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, int i, j; int pose; - numverts = hdr->mdl.numverts; - numtris = hdr->mdl.numtris; + numverts = header->mdl.numverts; + numtris = header->mdl.numtris; // copy triangles before editing them tris = malloc (numtris * sizeof (mtriangle_t)); - memcpy (tris, triangles.a, numtris * sizeof (mtriangle_t)); + memcpy (tris, alias_ctx->triangles.a, numtris * sizeof (mtriangle_t)); // initialize indexmap to -1 (unduplicated). any other value indicates // both that the vertex has been duplicated and the index of the @@ -157,7 +162,7 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // copy stverts. need space for duplicates st = malloc (2 * numverts * sizeof (stvert_t)); - memcpy (st, stverts.a, numverts * sizeof (stvert_t)); + memcpy (st, alias_ctx->stverts.a, numverts * sizeof (stvert_t)); // check for onseam verts, and duplicate any that are associated with // back-facing triangles. the s coordinate is shifted right by half @@ -168,7 +173,7 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, if (st[vind].onseam && !tris[i].facesfront) { if (indexmap[vind] == -1) { st[numverts] = st[vind]; - st[numverts].s += hdr->mdl.skinwidth / 2; + st[numverts].s += header->mdl.skinwidth / 2; indexmap[vind] = numverts++; } tris[i].vertindex[j] = indexmap[vind]; @@ -178,13 +183,13 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // we now know exactly how many vertices we need, so built the vertex // array - vertexsize = hdr->numposes * numverts * sizeof (aliasvrt_t); + vertexsize = header->numposes * numverts * sizeof (aliasvrt_t); verts = malloc (vertexsize); - for (i = 0, pose = 0; i < hdr->numposes; i++, pose += numverts) { - for (j = 0; j < hdr->mdl.numverts; j++) { - pv = &poseverts.a[i][j]; + for (i = 0, pose = 0; i < header->numposes; i++, pose += numverts) { + for (j = 0; j < header->mdl.numverts; j++) { + pv = &alias_ctx->poseverts.a[i][j]; if (extra) { - VectorMultAdd (pv[hdr->mdl.numverts].v, 256, pv->v, + VectorMultAdd (pv[header->mdl.numverts].v, 256, pv->v, verts[pose + j].vertex); } else { VectorCopy (pv->v, verts[pose + j].vertex); @@ -218,14 +223,14 @@ glsl_Mod_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr, void *_m, // finished with tris free (tris); - hdr->poseverts = numverts; + header->poseverts = numverts; // load the vertex data and indices into GL qfeglGenBuffers (2, bnum); - hdr->posedata = bnum[0]; - hdr->commands = bnum[1]; - qfeglBindBuffer (GL_ARRAY_BUFFER, hdr->posedata); - qfeglBindBuffer (GL_ELEMENT_ARRAY_BUFFER, hdr->commands); + header->posedata = bnum[0]; + header->commands = bnum[1]; + qfeglBindBuffer (GL_ARRAY_BUFFER, header->posedata); + qfeglBindBuffer (GL_ELEMENT_ARRAY_BUFFER, header->commands); qfeglBufferData (GL_ARRAY_BUFFER, vertexsize, verts, GL_STATIC_DRAW); qfeglBufferData (GL_ELEMENT_ARRAY_BUFFER, indexsize, indices, GL_STATIC_DRAW); diff --git a/libs/models/alias/model_alias.c b/libs/models/alias/model_alias.c index e4225daea..727957fe5 100644 --- a/libs/models/alias/model_alias.c +++ b/libs/models/alias/model_alias.c @@ -49,22 +49,11 @@ #include "mod_internal.h" #include "r_local.h" -aliashdr_t *pheader; - -stvertset_t stverts = { 0, 0, 256 }; -mtriangleset_t triangles = { 0, 0, 256 }; - -// a pose is a single set of vertexes. a frame may be an animating -// sequence of poses -trivertxset_t poseverts = { 0, 0, 256 };; -int posenum = 0; -int aliasbboxmins[3], aliasbboxmaxs[3]; - - static void * -Mod_LoadAllSkins (model_t *mod, int numskins, daliasskintype_t *pskintype, - int *pskinindex) +Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx, int numskins, + daliasskintype_t *pskintype, int *pskinindex) { + aliashdr_t *header = alias_ctx->header; byte *skin; float *poutskinintervals; int groupskins, skinsize, gnum, snum, t; @@ -76,34 +65,34 @@ Mod_LoadAllSkins (model_t *mod, int numskins, daliasskintype_t *pskintype, if (numskins < 1 || numskins > MAX_SKINS) Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d", numskins); - skinsize = pheader->mdl.skinwidth * pheader->mdl.skinheight; + skinsize = header->mdl.skinwidth * header->mdl.skinheight; pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t), - mod->name); + alias_ctx->mod->name); - *pskinindex = (byte *) pskindesc - (byte *) pheader; + *pskinindex = (byte *) pskindesc - (byte *) header; for (snum = 0; snum < numskins; snum++) { pskindesc[snum].type = pskintype->type; if (pskintype->type == ALIAS_SKIN_SINGLE) { skin = (byte *) (pskintype + 1); - skin = m_funcs->Mod_LoadSkin (mod, skin, skinsize, snum, 0, false, - &pskindesc[snum]); + skin = m_funcs->Mod_LoadSkin (alias_ctx, skin, skinsize, snum, 0, + false, &pskindesc[snum]); } else { pskintype++; pinskingroup = (daliasskingroup_t *) pskintype; groupskins = LittleLong (pinskingroup->numskins); t = field_offset (maliasskingroup_t, skindescs[groupskins]); - paliasskingroup = Hunk_AllocName (t, mod->name); + paliasskingroup = Hunk_AllocName (t, alias_ctx->mod->name); paliasskingroup->numskins = groupskins; - pskindesc[snum].skin = (byte *) paliasskingroup - (byte *) pheader; + pskindesc[snum].skin = (byte *) paliasskingroup - (byte *) header; pinskinintervals = (daliasskininterval_t *) (pinskingroup + 1); poutskinintervals = Hunk_AllocName (groupskins * sizeof (float), - mod->name); + alias_ctx->mod->name); paliasskingroup->intervals = - (byte *) poutskinintervals - (byte *) pheader; + (byte *) poutskinintervals - (byte *) header; for (gnum = 0; gnum < groupskins; gnum++) { *poutskinintervals = LittleFloat (pinskinintervals->interval); if (*poutskinintervals <= 0) @@ -118,8 +107,8 @@ Mod_LoadAllSkins (model_t *mod, int numskins, daliasskintype_t *pskintype, for (gnum = 0; gnum < groupskins; gnum++) { paliasskingroup->skindescs[gnum].type = ALIAS_SKIN_SINGLE; - skin = mod_funcs->Mod_LoadSkin (mod, skin, skinsize, snum, - gnum, true, + skin = mod_funcs->Mod_LoadSkin (alias_ctx, skin, skinsize, + snum, gnum, true, &paliasskingroup->skindescs[gnum]); } } @@ -130,9 +119,10 @@ Mod_LoadAllSkins (model_t *mod, int numskins, daliasskintype_t *pskintype, } static void * -Mod_LoadAliasFrame (model_t *mod, void *pin, int *posenum, +Mod_LoadAliasFrame (mod_alias_ctx_t *alias_ctx, void *pin, int *posenum, maliasframedesc_t *frame, int extra) { + aliashdr_t *header = alias_ctx->header; daliasframe_t *pdaliasframe; trivertx_t *pinframe; @@ -146,25 +136,29 @@ Mod_LoadAliasFrame (model_t *mod, void *pin, int *posenum, // byte values, don't worry about endianness VectorCopy (pdaliasframe->bboxmin.v, frame->bboxmin.v); VectorCopy (pdaliasframe->bboxmax.v, frame->bboxmax.v); - VectorCompMin (frame->bboxmin.v, aliasbboxmins, aliasbboxmins); - VectorCompMax (frame->bboxmax.v, aliasbboxmaxs, aliasbboxmaxs); + VectorCompMin (frame->bboxmin.v, alias_ctx->aliasbboxmins, + alias_ctx->aliasbboxmins); + VectorCompMax (frame->bboxmax.v, alias_ctx->aliasbboxmaxs, + alias_ctx->aliasbboxmaxs); pinframe = (trivertx_t *) (pdaliasframe + 1); - DARRAY_APPEND (&poseverts, pinframe); + DARRAY_APPEND (&alias_ctx->poseverts, pinframe); (*posenum)++; - pinframe += pheader->mdl.numverts; + pinframe += header->mdl.numverts; if (extra) - pinframe += pheader->mdl.numverts; + pinframe += header->mdl.numverts; return pinframe; } static void * -Mod_LoadAliasGroup (model_t *mod, void *pin, int *posenum, +Mod_LoadAliasGroup (mod_alias_ctx_t *alias_ctx, void *pin, int *posenum, maliasframedesc_t *frame, int extra) { + aliashdr_t *header = alias_ctx->header; + model_t *mod = alias_ctx->mod; daliasgroup_t *pingroup; daliasinterval_t *pin_intervals; float *poutintervals; @@ -182,17 +176,19 @@ Mod_LoadAliasGroup (model_t *mod, void *pin, int *posenum, paliasgroup = Hunk_AllocName (field_offset (maliasgroup_t, frames[numframes]), mod->name); paliasgroup->numframes = numframes; - frame->frame = (byte *) paliasgroup - (byte *) pheader; + frame->frame = (byte *) paliasgroup - (byte *) header; // these are byte values, so we don't have to worry about endianness VectorCopy (pingroup->bboxmin.v, frame->bboxmin.v); VectorCopy (pingroup->bboxmax.v, frame->bboxmax.v); - VectorCompMin (frame->bboxmin.v, aliasbboxmins, aliasbboxmins); - VectorCompMax (frame->bboxmax.v, aliasbboxmaxs, aliasbboxmaxs); + VectorCompMin (frame->bboxmin.v, alias_ctx->aliasbboxmins, + alias_ctx->aliasbboxmins); + VectorCompMax (frame->bboxmax.v, alias_ctx->aliasbboxmaxs, + alias_ctx->aliasbboxmaxs); pin_intervals = (daliasinterval_t *) (pingroup + 1); poutintervals = Hunk_AllocName (numframes * sizeof (float), mod->name); - paliasgroup->intervals = (byte *) poutintervals - (byte *) pheader; + paliasgroup->intervals = (byte *) poutintervals - (byte *) header; frame->interval = LittleFloat (pin_intervals->interval); for (i = 0; i < numframes; i++) { *poutintervals = LittleFloat (pin_intervals->interval); @@ -205,7 +201,8 @@ Mod_LoadAliasGroup (model_t *mod, void *pin, int *posenum, ptemp = (void *) pin_intervals; for (i = 0; i < numframes; i++) { maliasframedesc_t temp_frame; - ptemp = Mod_LoadAliasFrame (mod, ptemp, posenum, &temp_frame, extra); + ptemp = Mod_LoadAliasFrame (alias_ctx, ptemp, posenum, &temp_frame, + extra); memcpy (&paliasgroup->frames[i], &temp_frame, sizeof (paliasgroup->frames[i])); } @@ -225,6 +222,14 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) mdl_t *pinmodel, *pmodel; unsigned short crc; stvert_t *pinstverts; + mod_alias_ctx_t alias_ctx = {}; + aliashdr_t *header; + + alias_ctx.mod = mod; + //FIXME should be per batch rather than per model + DARRAY_INIT (&alias_ctx.poseverts, 256); + DARRAY_INIT (&alias_ctx.stverts, 256); + DARRAY_INIT (&alias_ctx.triangles, 256); if (LittleLong (* (unsigned int *) buffer) == HEADER_MDL16) extra = 1; // extra precision bytes @@ -244,12 +249,13 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) // allocate space for a working header, plus all the data except the // frames, skin and group info size = field_offset (aliashdr_t, frames[LittleLong (pinmodel->numframes)]); - pheader = Hunk_AllocName (size, mod->name); - memset (pheader, 0, size); - pmodel = &pheader->mdl; - pheader->model = (byte *) pmodel - (byte *) pheader; + header = Hunk_AllocName (size, mod->name); + memset (header, 0, size); + alias_ctx.header = header; + pmodel = &header->mdl; + header->model = (byte *) pmodel - (byte *) header; - pheader->crc = crc; + header->crc = crc; mod->flags = LittleLong (pinmodel->flags); @@ -264,20 +270,20 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) Sys_Error ("model %s has a skin taller than %d", mod->name, MAX_LBM_HEIGHT); - DARRAY_RESIZE (&poseverts, 0); + DARRAY_RESIZE (&alias_ctx.poseverts, 0); pmodel->numverts = LittleLong (pinmodel->numverts); if (pmodel->numverts <= 0) Sys_Error ("model %s has no vertices", mod->name); - DARRAY_RESIZE (&stverts, pmodel->numverts); + DARRAY_RESIZE (&alias_ctx.stverts, pmodel->numverts); pmodel->numtris = LittleLong (pinmodel->numtris); if (pmodel->numtris <= 0) Sys_Error ("model %s has no triangles", mod->name); - DARRAY_RESIZE (&triangles, pmodel->numtris); + DARRAY_RESIZE (&alias_ctx.triangles, pmodel->numtris); pmodel->numframes = LittleLong (pinmodel->numframes); numframes = pmodel->numframes; @@ -296,73 +302,76 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) // load the skins pskintype = (daliasskintype_t *) &pinmodel[1]; - pskintype = Mod_LoadAllSkins (mod, pheader->mdl.numskins, pskintype, - &pheader->skindesc); + pskintype = Mod_LoadAllSkins (&alias_ctx, header->mdl.numskins, pskintype, + &header->skindesc); // load base s and t vertices pinstverts = (stvert_t *) pskintype; - for (i = 0; i < pheader->mdl.numverts; i++) { - stverts.a[i].onseam = LittleLong (pinstverts[i].onseam); - stverts.a[i].s = LittleLong (pinstverts[i].s); - stverts.a[i].t = LittleLong (pinstverts[i].t); + for (i = 0; i < header->mdl.numverts; i++) { + alias_ctx.stverts.a[i].onseam = LittleLong (pinstverts[i].onseam); + alias_ctx.stverts.a[i].s = LittleLong (pinstverts[i].s); + alias_ctx.stverts.a[i].t = LittleLong (pinstverts[i].t); } // load triangle lists - pintriangles = (dtriangle_t *) &pinstverts[pheader->mdl.numverts]; + pintriangles = (dtriangle_t *) &pinstverts[header->mdl.numverts]; - for (i = 0; i < pheader->mdl.numtris; i++) { - triangles.a[i].facesfront = LittleLong (pintriangles[i].facesfront); + for (i = 0; i < header->mdl.numtris; i++) { + alias_ctx.triangles.a[i].facesfront = + LittleLong (pintriangles[i].facesfront); for (j = 0; j < 3; j++) { - triangles.a[i].vertindex[j] = + alias_ctx.triangles.a[i].vertindex[j] = LittleLong (pintriangles[i].vertindex[j]); } } // load the frames - posenum = 0; - pframetype = (daliasframetype_t *) &pintriangles[pheader->mdl.numtris]; - aliasbboxmins[0] = aliasbboxmins[1] = aliasbboxmins[2] = 99999; - aliasbboxmaxs[0] = aliasbboxmaxs[1] = aliasbboxmaxs[2] = -99999; + int posenum = 0; + pframetype = (daliasframetype_t *) &pintriangles[header->mdl.numtris]; + VectorSet (99999, 99999, 99999, alias_ctx.aliasbboxmins); + VectorSet (-99999, -99999, -99999, alias_ctx.aliasbboxmaxs); for (i = 0; i < numframes; i++) { aliasframetype_t frametype; frametype = LittleLong (pframetype->type); - pheader->frames[i].type = frametype; + header->frames[i].type = frametype; if (frametype == ALIAS_SINGLE) { pframetype = (daliasframetype_t *) - Mod_LoadAliasFrame (mod, pframetype + 1, &posenum, - &pheader->frames[i], extra); + Mod_LoadAliasFrame (&alias_ctx, pframetype + 1, &posenum, + &header->frames[i], extra); } else { pframetype = (daliasframetype_t *) - Mod_LoadAliasGroup (mod, pframetype + 1, &posenum, - &pheader->frames[i], extra); + Mod_LoadAliasGroup (&alias_ctx, pframetype + 1, &posenum, + &header->frames[i], extra); } } - pheader->numposes = posenum; + header->numposes = posenum; mod->type = mod_alias; - for (i = 0; i < 3; i++) { - mod->mins[i] = aliasbboxmins[i] * pheader->mdl.scale[i] + - pheader->mdl.scale_origin[i]; - mod->maxs[i] = aliasbboxmaxs[i] * pheader->mdl.scale[i] + - pheader->mdl.scale_origin[i]; - } + VectorCompMultAdd (header->mdl.scale_origin, header->mdl.scale, + alias_ctx.aliasbboxmins, mod->mins); + VectorCompMultAdd (header->mdl.scale_origin, header->mdl.scale, + alias_ctx.aliasbboxmaxs, mod->maxs); mod->radius = RadiusFromBounds (mod->mins, mod->maxs); // build the draw lists - m_funcs->Mod_MakeAliasModelDisplayLists (mod, pheader, buffer, + m_funcs->Mod_MakeAliasModelDisplayLists (&alias_ctx, buffer, qfs_filesize, extra); - m_funcs->Mod_FinalizeAliasModel (mod, pheader); + if (m_funcs->Mod_FinalizeAliasModel) { + m_funcs->Mod_FinalizeAliasModel (&alias_ctx); + } - m_funcs->Mod_LoadExternalSkins (mod); + if (m_funcs->Mod_LoadExternalSkins) { + m_funcs->Mod_LoadExternalSkins (&alias_ctx); + } // move the complete, relocatable alias model to the cache if (m_funcs->alias_cache) { @@ -371,11 +380,11 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) mem = allocator (&mod->cache, total, mod->name); if (mem) - memcpy (mem, pheader, total); + memcpy (mem, header, total); Hunk_FreeToLowMark (start); mod->aliashdr = 0; } else { - mod->aliashdr = pheader; + mod->aliashdr = header; } } diff --git a/libs/models/alias/sw_model_alias.c b/libs/models/alias/sw_model_alias.c index 61122298b..0bd57d5ce 100644 --- a/libs/models/alias/sw_model_alias.c +++ b/libs/models/alias/sw_model_alias.c @@ -50,13 +50,14 @@ void * -sw_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, int gnum, +sw_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, + int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc) { byte *pskin; - pskin = Hunk_AllocName (skinsize, mod->name); - skindesc->skin = (byte *) pskin - (byte *) pheader; + pskin = Hunk_AllocName (skinsize, alias_ctx->mod->name); + skindesc->skin = (byte *) pskin - (byte *) alias_ctx->header; memcpy (pskin, skin, skinsize); @@ -64,73 +65,67 @@ sw_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, int gnum, } static void -process_frame (model_t *mod, maliasframedesc_t *frame, int posenum, int extra) +process_frame (mod_alias_ctx_t *alias_ctx, maliasframedesc_t *frame, + int posenum, int extra) { - int size = pheader->mdl.numverts * sizeof (trivertx_t); + aliashdr_t *header = alias_ctx->header; + int size = header->mdl.numverts * sizeof (trivertx_t); trivertx_t *frame_verts; if (extra) size *= 2; - frame_verts = Hunk_AllocName (size, mod->name); - frame->frame = (byte *) frame_verts - (byte *) pheader; + frame_verts = Hunk_AllocName (size, alias_ctx->mod->name); + frame->frame = (byte *) frame_verts - (byte *) header; // The low-order 8 bits (actually, fractional) are completely separate // from the high-order bits (see R_AliasTransformFinalVert16 in // sw_ralias.c), but in adjacant arrays. This means we can get away with // just one memcpy as there are no endian issues. - memcpy (frame_verts, poseverts.a[posenum], size); + memcpy (frame_verts, alias_ctx->poseverts.a[posenum], size); } void -sw_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, +sw_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra) { + aliashdr_t *header = alias_ctx->header; int i, j; int posenum = 0; - int numv = hdr->mdl.numverts, numt = hdr->mdl.numtris; - stvert_t *pstverts; - mtriangle_t *ptri; + int numv = header->mdl.numverts, numt = header->mdl.numtris; + stvert_t *stverts; + mtriangle_t *tris; - pstverts = (stvert_t *) Hunk_AllocName (numv * sizeof (stvert_t), - mod->name); - ptri = (mtriangle_t *) Hunk_AllocName (numt * sizeof (mtriangle_t), - mod->name); + stverts = (stvert_t *) Hunk_AllocName (numv * sizeof (stvert_t), + alias_ctx->mod->name); + tris = (mtriangle_t *) Hunk_AllocName (numt * sizeof (mtriangle_t), + alias_ctx->mod->name); - hdr->stverts = (byte *) pstverts - (byte *) hdr; - hdr->triangles = (byte *) ptri - (byte *) hdr; + header->stverts = (byte *) stverts - (byte *) header; + header->triangles = (byte *) tris - (byte *) header; for (i = 0; i < numv; i++) { - pstverts[i].onseam = stverts.a[i].onseam; - pstverts[i].s = stverts.a[i].s << 16; - pstverts[i].t = stverts.a[i].t << 16; + stverts[i].onseam = alias_ctx->stverts.a[i].onseam; + stverts[i].s = alias_ctx->stverts.a[i].s << 16; + stverts[i].t = alias_ctx->stverts.a[i].t << 16; } for (i = 0; i < numt; i++) { - ptri[i].facesfront = triangles.a[i].facesfront; - VectorCopy (triangles.a[i].vertindex, ptri[i].vertindex); + tris[i].facesfront = alias_ctx->triangles.a[i].facesfront; + VectorCopy (alias_ctx->triangles.a[i].vertindex, tris[i].vertindex); } - for (i = 0; i < pheader->mdl.numframes; i++) { - maliasframedesc_t *frame = pheader->frames + i; + for (i = 0; i < header->mdl.numframes; i++) { + maliasframedesc_t *frame = header->frames + i; if (frame->type) { maliasgroup_t *group; - group = (maliasgroup_t *) ((byte *) pheader + frame->frame); - for (j = 0; j < group->numframes; j++) - process_frame (mod, (maliasframedesc_t *) &group->frames[j], - posenum++, extra); + group = (maliasgroup_t *) ((byte *) header + frame->frame); + for (j = 0; j < group->numframes; j++) { + __auto_type frame = (maliasframedesc_t *) &group->frames[j]; + process_frame (alias_ctx, frame, posenum++, extra); + } } else { - process_frame (mod, frame, posenum++, extra); + process_frame (alias_ctx, frame, posenum++, extra); } } } - -void -sw_Mod_FinalizeAliasModel (model_t *mod, aliashdr_t *hdr) -{ -} - -void -sw_Mod_LoadExternalSkins (model_t *mod) -{ -} diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index 97e8a63d0..c6493c750 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -110,19 +110,20 @@ vulkan_alias_clear (model_t *m, void *data) } void * -Vulkan_Mod_LoadSkin (model_t *mod, byte *skinpix, int skinsize, int snum, - int gnum, qboolean group, maliasskindesc_t *skindesc, - vulkan_ctx_t *ctx) +Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc, vulkan_ctx_t *ctx) { + aliashdr_t *header = alias_ctx->header; aliasskin_t *skin; byte *tskin; int w, h; skin = Hunk_Alloc (sizeof (aliasskin_t)); - skindesc->skin = (byte *) skin - (byte *) pheader;//FIXME pheader global + skindesc->skin = (byte *) skin - (byte *) header; //FIXME move all skins into arrays(?) - w = pheader->mdl.skinwidth; - h = pheader->mdl.skinheight; + w = header->mdl.skinwidth; + h = header->mdl.skinheight; tskin = malloc (2 * skinsize); memcpy (tskin, skinpix, skinsize); Mod_FloodFillSkin (tskin, w, h); @@ -131,25 +132,25 @@ Vulkan_Mod_LoadSkin (model_t *mod, byte *skinpix, int skinsize, int snum, if (Mod_CalcFullbright (tskin, tskin + skinsize, skinsize)) { skin->glow = Vulkan_LoadTex (ctx, &skin_tex, 1, va (ctx->va_ctx, "%s:%d:%d:glow", - mod->name, snum, gnum)); + alias_ctx->mod->name, snum, gnum)); Mod_ClearFullbright (tskin, tskin, skinsize); } if (Skin_CalcTopColors (tskin, tskin + skinsize, skinsize)) { skin->colora = Vulkan_LoadTex (ctx, &skin_tex, 1, va (ctx->va_ctx, "%s:%d:%d:colora", - mod->name, snum, gnum)); + alias_ctx->mod->name, snum, gnum)); Skin_ClearTopColors (tskin, tskin, skinsize); } if (Skin_CalcBottomColors (tskin, tskin + skinsize, skinsize)) { skin->colorb = Vulkan_LoadTex (ctx, &skin_tex, 1, va (ctx->va_ctx, "%s:%d:%d:colorb", - mod->name, snum, gnum)); + alias_ctx->mod->name, snum, gnum)); Skin_ClearBottomColors (tskin, tskin, skinsize); } skin_tex.data = tskin; skin->tex = Vulkan_LoadTex (ctx, &skin_tex, 1, va (ctx->va_ctx, "%s:%d:%d:tex", - mod->name, + alias_ctx->mod->name, snum, gnum)); free (tskin); @@ -158,14 +159,14 @@ Vulkan_Mod_LoadSkin (model_t *mod, byte *skinpix, int skinsize, int snum, } void -Vulkan_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr, vulkan_ctx_t *ctx) +Vulkan_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx) { - m->clear = vulkan_alias_clear; - m->data = ctx; + alias_ctx->mod->clear = vulkan_alias_clear; + alias_ctx->mod->data = ctx; } void -Vulkan_Mod_LoadExternalSkins (model_t *mod, vulkan_ctx_t *ctx) +Vulkan_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx) { } @@ -185,9 +186,10 @@ get_buffer_size (qfv_device_t *device, VkBuffer buffer) } void -Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, +Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra, vulkan_ctx_t *ctx) { + aliashdr_t *header = alias_ctx->header; qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; aliasvrt_t *verts; @@ -201,11 +203,11 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, int pose; vec3_t pos; - if (hdr->mdl.ident == HEADER_MDL16) - VectorScale (hdr->mdl.scale, 1/256.0, hdr->mdl.scale); + if (header->mdl.ident == HEADER_MDL16) + VectorScale (header->mdl.scale, 1/256.0, header->mdl.scale); - numverts = hdr->mdl.numverts; - numtris = hdr->mdl.numtris; + numverts = header->mdl.numverts; + numtris = header->mdl.numtris; // initialize indexmap to -1 (unduplicated). any other value indicates // both that the vertex has been duplicated and the index of the @@ -217,8 +219,9 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, // back-facing triangles for (i = 0; i < numtris; i++) { for (j = 0; j < 3; j++) { - int vind = triangles.a[i].vertindex[j]; - if (stverts.a[vind].onseam && !triangles.a[i].facesfront) { + int vind = alias_ctx->triangles.a[i].vertindex[j]; + if (alias_ctx->stverts.a[vind].onseam + && !alias_ctx->triangles.a[i].facesfront) { // duplicate the vertex if it has not alreaddy been // duplicated if (indexmap[vind] == -1) { @@ -239,7 +242,7 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, // current and previous pose, uvbuff "statically" bound as uvs are not // animated by pose, and the same for ibuf: indices will never change for // the mesh - size_t vert_count = numverts * hdr->numposes; + size_t vert_count = numverts * header->numposes; size_t vert_size = vert_count * sizeof (aliasvrt_t); size_t uv_size = numverts * sizeof (aliasuv_t); size_t ind_size = 3 * numtris * sizeof (uint32_t); @@ -255,13 +258,13 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, vbuff, va (ctx->va_ctx, "buffer:alias:vertex:%s", - mod->name)); + alias_ctx->mod->name)); QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, uvbuff, va (ctx->va_ctx, "buffer:alias:uv:%s", - mod->name)); + alias_ctx->mod->name)); QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, ibuff, va (ctx->va_ctx, "buffer:alias:index:%s", - mod->name)); + alias_ctx->mod->name)); size_t voffs = 0; size_t uvoffs = voffs + get_buffer_size (device, vbuff); size_t ioffs = uvoffs + get_buffer_size (device, uvbuff); @@ -272,7 +275,7 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, buff_size, 0); QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, mem, va (ctx->va_ctx, "memory:alias:vuvi:%s", - mod->name)); + alias_ctx->mod->name)); QFV_BindBufferMemory (device, vbuff, mem, voffs); QFV_BindBufferMemory (device, uvbuff, mem, uvoffs); QFV_BindBufferMemory (device, ibuff, mem, ioffs); @@ -280,7 +283,7 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, va (ctx->va_ctx, "alias:%s", - mod->name), + alias_ctx->mod->name), buff_size, ctx->cmdpool); qfv_packet_t *packet = QFV_PacketAcquire (stage); verts = QFV_PacketExtend (packet, vert_size); @@ -291,10 +294,10 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, // and associated with back-facing triangles (marked by non-negative // indexmap entry). // the s coordinate is shifted right by half the skin width. - for (i = 0; i < hdr->mdl.numverts; i++) { + for (i = 0; i < header->mdl.numverts; i++) { int vind = indexmap[i]; - uv[i].u = (float) stverts.a[i].s / hdr->mdl.skinwidth; - uv[i].v = (float) stverts.a[i].t / hdr->mdl.skinheight; + uv[i].u = (float) alias_ctx->stverts.a[i].s / header->mdl.skinwidth; + uv[i].v = (float) alias_ctx->stverts.a[i].t / header->mdl.skinheight; if (vind != -1) { uv[vind] = uv[i]; uv[vind].u += 0.5; @@ -303,15 +306,15 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, // poputlate the vertex position and normal data, duplicating for // back-facing on-seam verts (indicated by non-negative indexmap entry) - for (i = 0, pose = 0; i < hdr->numposes; i++, pose += numverts) { - for (j = 0; j < hdr->mdl.numverts; j++) { - pv = &poseverts.a[i][j]; + for (i = 0, pose = 0; i < header->numposes; i++, pose += numverts) { + for (j = 0; j < header->mdl.numverts; j++) { + pv = &alias_ctx->poseverts.a[i][j]; if (extra) { - VectorMultAdd (pv[hdr->mdl.numverts].v, 256, pv->v, pos); + VectorMultAdd (pv[header->mdl.numverts].v, 256, pv->v, pos); } else { VectorCopy (pv->v, pos); } - VectorCompMultAdd (hdr->mdl.scale_origin, hdr->mdl.scale, + VectorCompMultAdd (header->mdl.scale_origin, header->mdl.scale, pos, verts[pose + j].vertex); verts[pose + j].vertex[3] = 1; VectorCopy (vertex_normals[pv->lightnormalindex], @@ -327,8 +330,9 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, // now build the indices for DrawElements for (i = 0; i < numtris; i++) { for (j = 0; j < 3; j++) { - int vind = triangles.a[i].vertindex[j]; - if (stverts.a[vind].onseam && !triangles.a[i].facesfront) { + int vind = alias_ctx->triangles.a[i].vertindex[j]; + if (alias_ctx->stverts.a[vind].onseam + && !alias_ctx->triangles.a[i].facesfront) { vind = indexmap[vind]; } indices[3 * i + j] = vind; @@ -337,7 +341,7 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, // finished with indexmap free (indexmap); - hdr->poseverts = numverts; + header->poseverts = numverts; VkBufferMemoryBarrier wr_barriers[] = { { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, @@ -394,5 +398,5 @@ Vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, void *_m, mesh->uv_buffer = uvbuff; mesh->index_buffer = ibuff; mesh->memory = mem; - hdr->commands = (byte *) mesh - (byte *) hdr; + header->commands = (byte *) mesh - (byte *) header; } diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 0ef7a0108..2f790d847 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -50,8 +50,8 @@ static vid_model_funcs_t model_funcs = { sw_Mod_MakeAliasModelDisplayLists, sw_Mod_LoadSkin, - sw_Mod_FinalizeAliasModel, - sw_Mod_LoadExternalSkins, + 0, + 0, sw_Mod_IQMFinish, 1, sw_Mod_SpriteLoadTexture, diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index a3fe10d97..db94b291d 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -55,8 +55,8 @@ static vid_model_funcs_t model_funcs = { sw_Mod_MakeAliasModelDisplayLists, sw_Mod_LoadSkin, - sw_Mod_FinalizeAliasModel, - sw_Mod_LoadExternalSkins, + 0, + 0, sw_Mod_IQMFinish, 1, sw_Mod_SpriteLoadTexture, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 3473a92cf..8441795c1 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -418,28 +418,30 @@ vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx) } static void -vulkan_Mod_MakeAliasModelDisplayLists (model_t *mod, aliashdr_t *hdr, +vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, int _s, int extra) { - Vulkan_Mod_MakeAliasModelDisplayLists (mod, hdr, _m, _s, extra, vulkan_ctx); + Vulkan_Mod_MakeAliasModelDisplayLists (alias_ctx, _m, _s, extra, + vulkan_ctx); } static void * -vulkan_Mod_LoadSkin (model_t *mod, byte *skin, int skinsize, int snum, - int gnum, qboolean group, maliasskindesc_t *skindesc) +vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skin, int skinsize, + int snum, int gnum, qboolean group, + maliasskindesc_t *skindesc) { - return Vulkan_Mod_LoadSkin (mod, skin, skinsize, snum, gnum, group, + return Vulkan_Mod_LoadSkin (alias_ctx, skin, skinsize, snum, gnum, group, skindesc, vulkan_ctx); } static void -vulkan_Mod_FinalizeAliasModel (model_t *m, aliashdr_t *hdr) +vulkan_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx) { - Vulkan_Mod_FinalizeAliasModel (m, hdr, vulkan_ctx); + Vulkan_Mod_FinalizeAliasModel (alias_ctx, vulkan_ctx); } static void -vulkan_Mod_LoadExternalSkins (model_t *mod) +vulkan_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx) { } From 0d4ca46923d77c88a74f0fe8e8b95cbc06671652 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 2 Feb 2021 00:04:45 +0900 Subject: [PATCH 321/435] [vulkan] Move mip map generation commands to image --- include/QF/Vulkan/image.h | 1 + libs/video/renderer/vulkan/image.c | 30 +++++++++++++++++++++ libs/video/renderer/vulkan/vulkan_texture.c | 26 +----------------- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index 71ca57389..9942562b2 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -82,5 +82,6 @@ VkImageView QFV_CreateImageView (struct qfv_device_s *device, void QFV_GenerateMipMaps (struct qfv_device_s *device, VkCommandBuffer cmd, VkImage image, unsigned mips, unsigned width, unsigned height, unsigned layers); +int QFV_MipLevels (int width, int height) __attribute__((const)); #endif//__QF_Vulkan_image_h diff --git a/libs/video/renderer/vulkan/image.c b/libs/video/renderer/vulkan/image.c index 92d584f80..41b4586f0 100644 --- a/libs/video/renderer/vulkan/image.c +++ b/libs/video/renderer/vulkan/image.c @@ -275,3 +275,33 @@ QFV_GenerateMipMaps (qfv_device_t *device, VkCommandBuffer cmd, 0, 0, 0, 0, 1, &final_barrier); } + +static int +ilog2 (unsigned x) +{ + unsigned o = x; + if (x > 0x7fffffff) { + // avoid overflow + return 31; + } + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + int y = 0; + y |= ((x & 0xffff0000) != 0) << 4; + y |= ((x & 0xff00ff00) != 0) << 3; + y |= ((x & 0xf0f0f0f0) != 0) << 2; + y |= ((x & 0xcccccccc) != 0) << 1; + y |= ((x & 0xaaaaaaaa) != 0) << 0; + return y - ((o & (x - 1)) != 0); +} + +int +QFV_MipLevels (int width, int height) +{ + return ilog2 (max (width, height)) + 1; +} diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index 4a1e2d2ab..7d8b13155 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -64,30 +64,6 @@ #include "r_scrap.h" #include "vid_vulkan.h" -static int -ilog2 (unsigned x) -{ - unsigned o = x; - if (x > 0x7fffffff) { - // avoid overflow - return 31; - } - x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - x++; - int y = 0; - y |= ((x & 0xffff0000) != 0) << 4; - y |= ((x & 0xff00ff00) != 0) << 3; - y |= ((x & 0xf0f0f0f0) != 0) << 2; - y |= ((x & 0xcccccccc) != 0) << 1; - y |= ((x & 0xaaaaaaaa) != 0) << 0; - return y - ((o & (x - 1)) != 0); -} - void Vulkan_ExpandPalette (byte *dst, const byte *src, const byte *palette, int alpha, int count) @@ -164,7 +140,7 @@ Vulkan_LoadTex (vulkan_ctx_t *ctx, tex_t *tex, int mip, const char *name) } if (mip) { - mip = ilog2 (max (tex->width, tex->height)) + 1; + mip = QFV_MipLevels (tex->width, tex->height); } else { mip = 1; } From 8e63ab9f94b8d028cb38b2c1918abde127d39e3c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 2 Feb 2021 00:11:47 +0900 Subject: [PATCH 322/435] [vulkan] Use 4 layer arrays for alias skins Doesn't seem to make much difference performance-wise, but speed does seem to be fill-rate limited due to the 8x msaa. Still, it does mean fewer bindings to worry about. --- include/QF/Vulkan/qf_alias.h | 9 +- libs/models/alias/vulkan_model_alias.c | 139 +++++++++++++++----- libs/video/renderer/vulkan/alias.frag | 13 +- libs/video/renderer/vulkan/qfpipeline.plist | 18 --- libs/video/renderer/vulkan/vulkan_alias.c | 11 +- 5 files changed, 112 insertions(+), 78 deletions(-) diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index ebf4f6996..6f96e0fa0 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -37,13 +37,6 @@ #include "QF/modelgen.h" #include "QF/Vulkan/qf_vid.h" -typedef struct aliasskin_s { - struct qfv_tex_s *tex; - struct qfv_tex_s *glow; - struct qfv_tex_s *colora; - struct qfv_tex_s *colorb; -} aliasskin_t; - typedef struct aliasvrt_s { float vertex[4]; float normal[4]; @@ -77,7 +70,7 @@ typedef struct qfv_light_buffer_s { } qfv_light_buffer_t; #define ALIAS_BUFFER_INFOS 2 -#define ALIAS_IMAGE_INFOS 4 +#define ALIAS_IMAGE_INFOS 1 typedef struct aliasframe_s { VkCommandBuffer cmd; diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index c6493c750..5b3ce995c 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -46,9 +46,11 @@ #include "QF/vid.h" #include "QF/Vulkan/qf_alias.h" #include "QF/Vulkan/qf_texture.h" +#include "QF/Vulkan/barrier.h" #include "QF/Vulkan/buffer.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/debug.h" +#include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" #include "QF/Vulkan/staging.h" @@ -63,17 +65,13 @@ static vec3_t vertex_normals[NUMVERTEXNORMALS] = { static void skin_clear (int skin_offset, aliashdr_t *hdr, vulkan_ctx_t *ctx) { - aliasskin_t *skin = (aliasskin_t *) ((byte *) hdr + skin_offset); - Vulkan_UnloadTex (ctx, skin->tex); - if (skin->glow) { - Vulkan_UnloadTex (ctx, skin->glow); - } - if (skin->colora) { - Vulkan_UnloadTex (ctx, skin->colora); - } - if (skin->colorb) { - Vulkan_UnloadTex (ctx, skin->colorb); - } + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + qfv_tex_t *skin = (qfv_tex_t *) ((byte *) hdr + skin_offset); + + dfunc->vkDestroyImageView (device->dev, skin->view, 0); + dfunc->vkDestroyImage (device->dev, skin->image, 0); + dfunc->vkFreeMemory (device->dev, skin->memory, 0); } static void @@ -114,12 +112,14 @@ Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize, int snum, int gnum, qboolean group, maliasskindesc_t *skindesc, vulkan_ctx_t *ctx) { + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; aliashdr_t *header = alias_ctx->header; - aliasskin_t *skin; + qfv_tex_t *skin; byte *tskin; int w, h; - skin = Hunk_Alloc (sizeof (aliasskin_t)); + skin = Hunk_Alloc (sizeof (qfv_tex_t)); skindesc->skin = (byte *) skin - (byte *) header; //FIXME move all skins into arrays(?) w = header->mdl.skinwidth; @@ -128,30 +128,97 @@ Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize, memcpy (tskin, skinpix, skinsize); Mod_FloodFillSkin (tskin, w, h); - tex_t skin_tex = {w, h, tex_palette, 1, vid.palette, tskin + skinsize}; - if (Mod_CalcFullbright (tskin, tskin + skinsize, skinsize)) { - skin->glow = Vulkan_LoadTex (ctx, &skin_tex, 1, - va (ctx->va_ctx, "%s:%d:%d:glow", - alias_ctx->mod->name, snum, gnum)); - Mod_ClearFullbright (tskin, tskin, skinsize); + int mipLevels = QFV_MipLevels (w, h); + VkExtent3D extent = { w, h, 1 }; + skin->offset = 0; + skin->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, extent, + mipLevels, 4, VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT + | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, skin->image, + va (ctx->va_ctx, "image:%s:%d:%d", + alias_ctx->mod->name, snum, gnum)); + skin->memory = QFV_AllocImageMemory (device, skin->image, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, skin->memory, + va (ctx->va_ctx, "memory:%s:%d:%d", + alias_ctx->mod->name, snum, gnum)); + QFV_BindImageMemory (device, skin->image, skin->memory, 0); + skin->view = QFV_CreateImageView (device, skin->image, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, skin->view, + va (ctx->va_ctx, "iview:%s:%d:%d", + alias_ctx->mod->name, snum, gnum)); + + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, "alias stage", + 4 * skinsize * 4, + ctx->cmdpool); + qfv_packet_t *packet = QFV_PacketAcquire (stage); + byte *base_data = QFV_PacketExtend (packet, skinsize * 4); + byte *cola_data = QFV_PacketExtend (packet, skinsize * 4); + byte *colb_data = QFV_PacketExtend (packet, skinsize * 4); + byte *glow_data = QFV_PacketExtend (packet, skinsize * 4); + + Mod_CalcFullbright (tskin, tskin + skinsize, skinsize); + Vulkan_ExpandPalette (glow_data, tskin + skinsize, vid.palette, 1, + skinsize); + Mod_ClearFullbright (tskin, tskin, skinsize); + + Skin_CalcTopColors (tskin, tskin + skinsize, skinsize); + Vulkan_ExpandPalette (cola_data, tskin + skinsize, vid.palette, 1, + skinsize); + Skin_ClearTopColors (tskin, tskin, skinsize); + + Skin_CalcBottomColors (tskin, tskin + skinsize, skinsize); + Vulkan_ExpandPalette (colb_data, tskin + skinsize, vid.palette, 1, + skinsize); + Skin_ClearBottomColors (tskin, tskin, skinsize); + + Vulkan_ExpandPalette (base_data, tskin, vid.palette, 1, skinsize); + + VkImageMemoryBarrier barrier; + qfv_pipelinestagepair_t stages; + + stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_TransferDst]; + barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_TransferDst]; + barrier.image = skin->image; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + + VkBufferImageCopy copy = { + packet->offset, 0, 0, + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 4}, + {0, 0, 0}, {w, h, 1}, + }; + dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer, + skin->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ©); + + if (mipLevels == 1) { + stages = imageLayoutTransitionStages[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier=imageLayoutTransitionBarriers[qfv_LT_TransferDst_to_ShaderReadOnly]; + barrier.image = skin->image; + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, + 0, 0, 0, 0, 0, + 1, &barrier); + + } else { + QFV_GenerateMipMaps (device, packet->cmd, skin->image, + mipLevels, w, h, 4); } - if (Skin_CalcTopColors (tskin, tskin + skinsize, skinsize)) { - skin->colora = Vulkan_LoadTex (ctx, &skin_tex, 1, - va (ctx->va_ctx, "%s:%d:%d:colora", - alias_ctx->mod->name, snum, gnum)); - Skin_ClearTopColors (tskin, tskin, skinsize); - } - if (Skin_CalcBottomColors (tskin, tskin + skinsize, skinsize)) { - skin->colorb = Vulkan_LoadTex (ctx, &skin_tex, 1, - va (ctx->va_ctx, "%s:%d:%d:colorb", - alias_ctx->mod->name, snum, gnum)); - Skin_ClearBottomColors (tskin, tskin, skinsize); - } - skin_tex.data = tskin; - skin->tex = Vulkan_LoadTex (ctx, &skin_tex, 1, - va (ctx->va_ctx, "%s:%d:%d:tex", - alias_ctx->mod->name, - snum, gnum)); + QFV_PacketSubmit (packet); + QFV_DestroyStagingBuffer (stage); free (tskin); diff --git a/libs/video/renderer/vulkan/alias.frag b/libs/video/renderer/vulkan/alias.frag index eff6ff10a..bff1b87dd 100644 --- a/libs/video/renderer/vulkan/alias.frag +++ b/libs/video/renderer/vulkan/alias.frag @@ -1,8 +1,5 @@ #version 450 -layout (set = 0, binding = 2) uniform sampler2D Texture; -layout (set = 0, binding = 3) uniform sampler2D GlowMap; -layout (set = 0, binding = 4) uniform sampler2D ColorA; -layout (set = 0, binding = 5) uniform sampler2D ColorB; +layout (set = 0, binding = 2) uniform sampler2DArray Skin; /* layout (set = 2, binding = 0) uniform sampler2D Texture; layout (set = 2, binding = 1) uniform sampler2D GlowMap; @@ -59,9 +56,9 @@ main (void) vec4 c; int i; vec3 light = vec3 (0); - c = texture (Texture, st); - c += texture (ColorA, st); - c += texture (ColorB, st); + c = texture (Skin, vec3 (st, 0)); + c += texture (Skin, vec3 (st, 1)); + c += texture (Skin, vec3 (st, 2)); if (MaxLights > 0) { for (i = 0; i < light_count; i++) { @@ -70,7 +67,7 @@ main (void) } c *= vec4 (light, 1); - c += texture (GlowMap, st); + c += texture (Skin, vec3 (st, 3)); //frag_color = vec4((normal + 1)/2, 1); frag_color = c;//fogBlend (c); } diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 3cbf8db5e..5d44ec6ff 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -172,24 +172,6 @@ descriptorCount = 1; stageFlags = fragment; }, - { - binding = 3; - descriptorType = combined_image_sampler; - descriptorCount = 1; - stageFlags = fragment; - }, - { - binding = 4; - descriptorType = combined_image_sampler; - descriptorCount = 1; - stageFlags = fragment; - }, - { - binding = 5; - descriptorType = combined_image_sampler; - descriptorCount = 1; - stageFlags = fragment; - }, ); }; alias.matrices = { diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index fec2d2cd6..d7f933cb9 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -88,7 +88,7 @@ Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx) aliashdr_t *hdr; qfv_alias_mesh_t *mesh; float blend; - aliasskin_t *skin; + qfv_tex_t *skin; if (!(hdr = model->aliashdr)) { hdr = Cache_Get (&model->cache); @@ -102,7 +102,7 @@ Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx) } else { maliasskindesc_t *skindesc; skindesc = R_AliasGetSkindesc (ent->skinnum, hdr); - skin = (aliasskin_t *) ((byte *) hdr + skindesc->skin); + skin = (qfv_tex_t *) ((byte *) hdr + skindesc->skin); } VkDeviceSize offsets[] = { @@ -124,12 +124,7 @@ Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx) dfunc->vkCmdPushConstants (aframe->cmd, actx->layout, VK_SHADER_STAGE_VERTEX_BIT, 64, sizeof (float), &blend); - aframe->imageInfo[0].imageView = get_view (skin->tex, ctx->default_white); - aframe->imageInfo[1].imageView = get_view (skin->glow, ctx->default_black); - aframe->imageInfo[2].imageView = get_view (skin->colora, - ctx->default_black); - aframe->imageInfo[3].imageView = get_view (skin->colorb, - ctx->default_black); + aframe->imageInfo[0].imageView = get_view (skin, 0); dfunc->vkCmdPushDescriptorSetKHR (aframe->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, actx->layout, From d6b678ac78785f8df92fabee0dbf3993e5c77769 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 2 Feb 2021 19:53:36 +0900 Subject: [PATCH 323/435] [vulkan] Implement team colors It's not quite as expected, but that may be due to one of msaa, the 0-15 range in the palette not being all the way to white, the color gradients being not quite linear (haven't checked yet) or some combination of the above. However, it's that what should be yellow is more green. At least the zombies are no longer white and the ogres don't look like they're wearing skeleton suits. --- include/QF/Vulkan/qf_alias.h | 8 +++++ libs/models/alias/vulkan_model_alias.c | 10 +++--- libs/video/renderer/vulkan/alias.frag | 11 ++++--- libs/video/renderer/vulkan/qfpipeline.plist | 4 +-- libs/video/renderer/vulkan/vulkan_alias.c | 34 +++++++++------------ 5 files changed, 36 insertions(+), 31 deletions(-) diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index 6f96e0fa0..714cb06b3 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -53,6 +53,14 @@ typedef struct qfv_alias_mesh_s { VkDeviceMemory memory; } qfv_alias_mesh_t; +typedef struct qfv_alias_skin_s { + VkDeviceMemory memory; + VkImage image; + VkImageView view; + byte colora[4]; + byte colorb[4]; +} qfv_alias_skin_t; + typedef struct qfv_light_s { vec3_t color; float dist; diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index 5b3ce995c..fd1f8c731 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -67,7 +67,7 @@ skin_clear (int skin_offset, aliashdr_t *hdr, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - qfv_tex_t *skin = (qfv_tex_t *) ((byte *) hdr + skin_offset); + qfv_alias_skin_t *skin = (qfv_alias_skin_t *) ((byte *) hdr + skin_offset); dfunc->vkDestroyImageView (device->dev, skin->view, 0); dfunc->vkDestroyImage (device->dev, skin->image, 0); @@ -115,11 +115,13 @@ Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize, qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; aliashdr_t *header = alias_ctx->header; - qfv_tex_t *skin; + qfv_alias_skin_t *skin; byte *tskin; int w, h; - skin = Hunk_Alloc (sizeof (qfv_tex_t)); + skin = Hunk_Alloc (sizeof (qfv_alias_skin_t)); + QuatCopy (vid.palette32 + (TOP_RANGE + 15) * 4, skin->colora); + QuatCopy (vid.palette32 + (BOTTOM_RANGE + 15) * 4, skin->colorb); skindesc->skin = (byte *) skin - (byte *) header; //FIXME move all skins into arrays(?) w = header->mdl.skinwidth; @@ -130,7 +132,6 @@ Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize, int mipLevels = QFV_MipLevels (w, h); VkExtent3D extent = { w, h, 1 }; - skin->offset = 0; skin->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, extent, mipLevels, 4, VK_SAMPLE_COUNT_1_BIT, @@ -212,7 +213,6 @@ Vulkan_Mod_LoadSkin (mod_alias_ctx_t *alias_ctx, byte *skinpix, int skinsize, dfunc->vkCmdPipelineBarrier (packet->cmd, stages.src, stages.dst, 0, 0, 0, 0, 0, 1, &barrier); - } else { QFV_GenerateMipMaps (device, packet->cmd, skin->image, mipLevels, w, h, 4); diff --git a/libs/video/renderer/vulkan/alias.frag b/libs/video/renderer/vulkan/alias.frag index bff1b87dd..3b5c9fddd 100644 --- a/libs/video/renderer/vulkan/alias.frag +++ b/libs/video/renderer/vulkan/alias.frag @@ -23,7 +23,10 @@ layout (set = 0, binding = 1) uniform Lights { }; layout (push_constant) uniform PushConstants { - layout (offset = 80) + layout (offset = 68) + uint base_color; + uint colorA; + uint colorB; vec4 fog; vec4 color; }; @@ -56,9 +59,9 @@ main (void) vec4 c; int i; vec3 light = vec3 (0); - c = texture (Skin, vec3 (st, 0)); - c += texture (Skin, vec3 (st, 1)); - c += texture (Skin, vec3 (st, 2)); + c = texture (Skin, vec3 (st, 0)) * unpackUnorm4x8(base_color); + c += texture (Skin, vec3 (st, 1)) * unpackUnorm4x8(colorA); + c += texture (Skin, vec3 (st, 2)) * unpackUnorm4x8(colorB); if (MaxLights > 0) { for (i = 0; i < light_count; i++) { diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 5d44ec6ff..33bc11b27 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -271,8 +271,8 @@ }, { stageFlags = fragment; - offset = 80; - size = "2 * 4 * 4"; + offset = 68; + size = "3 * 4 + 2 * 4 * 4"; }, ); }; diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index d7f933cb9..76f4ac7b5 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -65,18 +65,6 @@ #include "vid_vulkan.h" #include "vkparse.h" -static VkImageView -get_view (qfv_tex_t *tex, qfv_tex_t *default_tex) -{ - if (tex) { - return tex->view; - } - if (default_tex) { - return default_tex->view; - } - return 0; -} - void Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx) { @@ -87,23 +75,28 @@ Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx) model_t *model = ent->model; aliashdr_t *hdr; qfv_alias_mesh_t *mesh; - float blend; - qfv_tex_t *skin; + qfv_alias_skin_t *skin; + float vertex_constants[17]; + byte fragment_constants[3][4]; if (!(hdr = model->aliashdr)) { hdr = Cache_Get (&model->cache); } mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands); - blend = R_AliasGetLerpedFrames (ent, hdr); + memcpy (vertex_constants, ent->transform, sizeof (ent->transform)); + vertex_constants[16] = R_AliasGetLerpedFrames (ent, hdr); if (0/*XXX ent->skin && ent->skin->tex*/) { //skin = ent->skin->tex; } else { maliasskindesc_t *skindesc; skindesc = R_AliasGetSkindesc (ent->skinnum, hdr); - skin = (qfv_tex_t *) ((byte *) hdr + skindesc->skin); + skin = (qfv_alias_skin_t *) ((byte *) hdr + skindesc->skin); } + QuatScale (ent->colormod, 255, fragment_constants[0]); + QuatCopy (skin->colora, fragment_constants[1]); + QuatCopy (skin->colorb, fragment_constants[2]); VkDeviceSize offsets[] = { ent->pose1 * hdr->poseverts * sizeof (aliasvrt_t), @@ -120,11 +113,12 @@ Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx) VK_INDEX_TYPE_UINT32); dfunc->vkCmdPushConstants (aframe->cmd, actx->layout, VK_SHADER_STAGE_VERTEX_BIT, - 0, 16 * sizeof (float), ent->transform); + 0, sizeof (vertex_constants), vertex_constants); dfunc->vkCmdPushConstants (aframe->cmd, actx->layout, - VK_SHADER_STAGE_VERTEX_BIT, - 64, sizeof (float), &blend); - aframe->imageInfo[0].imageView = get_view (skin, 0); + VK_SHADER_STAGE_FRAGMENT_BIT, + 68, sizeof (fragment_constants), + fragment_constants); + aframe->imageInfo[0].imageView = skin->view; dfunc->vkCmdPushDescriptorSetKHR (aframe->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, actx->layout, From ebb73e19b2309e0e5025215d99a7a267d4880c16 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Feb 2021 00:08:33 +0900 Subject: [PATCH 324/435] [vulkan] Use the msaaSamples cvar That took a bit of fiddling with the render pass to get things working for both sampling and no sampling (ie, msaaSamples = 1). --- libs/video/renderer/vid_render_vulkan.c | 16 ++-- libs/video/renderer/vulkan/qfpipeline.plist | 76 +++++++++++++++++-- libs/video/renderer/vulkan/renderpass.c | 10 ++- .../video/renderer/vulkan/vulkan_vid_common.c | 25 +++--- 4 files changed, 100 insertions(+), 27 deletions(-) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 8441795c1..ebca7b9b0 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -135,12 +135,15 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) framebuffer->imageAvailableSemaphore, 0, &imageIndex); - __auto_type attachments = DARRAY_ALLOCFIXED (qfv_imageviewset_t, 3, - alloca); + int attachCount = vulkan_ctx->msaaSamples > 1 ? 3 : 2; + __auto_type attachments = DARRAY_ALLOCFIXED (qfv_imageviewset_t, + attachCount, alloca); qfv_swapchain_t *sc = vulkan_ctx->swapchain; - attachments->a[0] = vulkan_ctx->renderpass.colorImage->view; + attachments->a[0] = sc->imageViews->a[imageIndex]; attachments->a[1] = vulkan_ctx->renderpass.depthImage->view; - attachments->a[2] = sc->imageViews->a[imageIndex]; + if (attachCount > 2) { + attachments->a[2] = vulkan_ctx->renderpass.colorImage->view; + } VkRenderPass renderpass = vulkan_ctx->renderpass.renderpass; framebuffer->framebuffer = QFV_CreateFramebuffer (device, renderpass, @@ -157,15 +160,16 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - VkClearValue clearValues[2] = { + VkClearValue clearValues[3] = { { { {0.0, 0.0, 0.0, 1.0} } }, { { {1.0, 0.0} } }, + { { {0.0, 0.0, 0.0, 1.0} } }, }; VkRenderPassBeginInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 0, vulkan_ctx->renderpass.renderpass, 0, { {0, 0}, sc->extent }, - 2, clearValues + 3, clearValues }; dfunc->vkBeginCommandBuffer (framebuffer->cmdBuffer, &beginInfo); diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 33bc11b27..96de769c9 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -707,13 +707,75 @@ { flags = 0; format = $swapchain.format; - samples = $msaaSamples; + samples = 1; loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; storeOp = VK_ATTACHMENT_STORE_OP_STORE; stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + }, + { + flags = 0; + format = VK_FORMAT_D32_SFLOAT; + samples = 1; + loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + }, + ); + subpasses = ( + { + pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + colorAttachments = ( + { + attachment = 0; + layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + ); + depthStencilAttachment = { + attachment = 1; + layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + }; + preserveAttachments = (); + }, + ); + dependencies = ( + { + srcSubpass = VK_SUBPASS_EXTERNAL; + dstSubpass = 0; + srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + }, + { + srcSubpass = 0; + dstSubpass = VK_SUBPASS_EXTERNAL; + srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + }, + ); + }; + renderpass.msaa = { + attachments = ( + { + flags = 0; + format = $swapchain.format; + samples = VK_SAMPLE_COUNT_1_BIT; + loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + storeOp = VK_ATTACHMENT_STORE_OP_STORE; + stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; }, { flags = 0; @@ -729,13 +791,13 @@ { flags = 0; format = $swapchain.format; - samples = VK_SAMPLE_COUNT_1_BIT; - loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + samples = $msaaSamples; + loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; storeOp = VK_ATTACHMENT_STORE_OP_STORE; stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; }, ); subpasses = ( @@ -743,13 +805,13 @@ pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; colorAttachments = ( { - attachment = 0; + attachment = 2; layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } ); resolveAttachments = ( { - attachment = 2; + attachment = 0; layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } ); diff --git a/libs/video/renderer/vulkan/renderpass.c b/libs/video/renderer/vulkan/renderpass.c index 65134ffd7..4970b050b 100644 --- a/libs/video/renderer/vulkan/renderpass.c +++ b/libs/video/renderer/vulkan/renderpass.c @@ -106,9 +106,13 @@ QFV_CreateRenderPass (qfv_device_t *device, const VkAttachmentReference *ref = &sp->pColorAttachments[j]; Sys_Printf (" c %d %d\n", ref->attachment, ref->layout); } - for (size_t j = 0; j < sp->colorAttachmentCount; j++) { - const VkAttachmentReference *ref = &sp->pResolveAttachments[j]; - Sys_Printf (" r %d %d\n", ref->attachment, ref->layout); + if (sp->pResolveAttachments) { + for (size_t j = 0; j < sp->colorAttachmentCount; j++) { + const VkAttachmentReference *ref + = &sp->pResolveAttachments[j]; + Sys_Printf (" r %d %d\n", ref->attachment, + ref->layout); + } } Sys_Printf (" pDepthStencilAttachment: %p\n", sp->pDepthStencilAttachment); diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index ddd20e82c..ff026331a 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -240,28 +240,31 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) { qfv_load_pipeline (ctx); const char *name = "renderpass";//FIXME - - plitem_t *item = ctx->pipelineDef; - if (!item || !(item = PL_ObjectForKey (item, name))) { - Sys_Printf ("error loading renderpass\n"); - return; - } else { - Sys_Printf ("Found renderpass def\n"); - } qfv_device_t *device = ctx->device; VkDevice dev = device->dev; qfv_devfuncs_t *df = device->funcs; VkCommandBuffer cmd = ctx->cmdbuffer; qfv_swapchain_t *sc = ctx->swapchain; + ctx->msaaSamples = min ((VkSampleCountFlagBits) msaaSamples->int_val, + QFV_GetMaxSampleCount (device->physDev)); + if (ctx->msaaSamples > 1) { + name = "renderpass.msaa"; + } + + plitem_t *item = ctx->pipelineDef; + if (!item || !(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading renderpass: %s\n", name); + return; + } else { + Sys_Printf ("Found renderpass def: %s\n", name); + } + qfv_imageresource_t *colorImage = malloc (sizeof (*colorImage)); qfv_imageresource_t *depthImage = malloc (sizeof (*depthImage)); VkExtent3D extent = {sc->extent.width, sc->extent.height, 1}; - //FIXME incorporate cvar setting - ctx->msaaSamples = QFV_GetMaxSampleCount (device->physDev); - Sys_MaskPrintf (SYS_VULKAN, "color resource\n"); colorImage->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, From bc7858bb87b7150077a77c8da2a562bd74bbc0f5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Feb 2021 11:41:38 +0900 Subject: [PATCH 325/435] [model] Move parent pointer out of leaf/node struct The node struct was 72 bytes thus two cache line. Moving the pointer into the brush model data block allows nodes to fit in a single cache line (not that they're aligned yet, but that's next). It doesn't seem to have made any difference to performance (at least in the vulkan renderer), but it hasn't hurt, either, as the only place that needed the parent pointer was R_MarkLeaves. --- include/QF/model.h | 7 +++---- libs/models/brush/model_brush.c | 17 +++++++++++------ libs/video/renderer/r_bsp.c | 16 +++++++++------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/include/QF/model.h b/include/QF/model.h index a05d489a4..b65a5ad18 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -179,8 +179,6 @@ typedef struct mnode_s { float minmaxs[6]; // for bounding box culling - struct mnode_s *parent; - // node specific plane_t *plane; struct mnode_s *children[2]; @@ -198,8 +196,6 @@ typedef struct mleaf_s { float mins[3]; float maxs[3]; - struct mnode_s *parent; - // leaf specific byte *compressed_vis; efrag_t *efrags; @@ -274,6 +270,9 @@ typedef struct mod_brush_s { byte *lightdata; char *entities; //FIXME should not be here + mnode_t **node_parents; + mnode_t **leaf_parents; + unsigned int checksum; unsigned int checksum2; } mod_brush_t; diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index 8a703050d..b18de9076 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -585,13 +585,15 @@ Mod_LoadFaces (model_t *mod, bsp_t *bsp) } static void -Mod_SetParent (mnode_t *node, mnode_t *parent) +Mod_SetParent (mod_brush_t *brush, mnode_t *node, mnode_t *parent) { - node->parent = parent; - if (node->contents < 0) + if (node->contents < 0) { + brush->leaf_parents[(mleaf_t *)node - brush->leafs] = parent; return; - Mod_SetParent (node->children[0], node); - Mod_SetParent (node->children[1], node); + } + brush->node_parents[node - brush->nodes] = parent; + Mod_SetParent (brush, node->children[0], node); + Mod_SetParent (brush, node->children[1], node); } static void @@ -646,7 +648,10 @@ Mod_LoadNodes (model_t *mod, bsp_t *bsp) } } - Mod_SetParent (brush->nodes, NULL); // sets nodes and leafs + size_t size = (brush->numleafs + brush->numnodes) * sizeof (mnode_t *); + brush->node_parents = Hunk_AllocName (size, mod->name); + brush->leaf_parents = brush->node_parents + brush->numnodes; + Mod_SetParent (brush, brush->nodes, NULL); // sets nodes and leafs } static void diff --git a/libs/video/renderer/r_bsp.c b/libs/video/renderer/r_bsp.c index 2475873a5..47b78a643 100644 --- a/libs/video/renderer/r_bsp.c +++ b/libs/video/renderer/r_bsp.c @@ -54,6 +54,7 @@ R_MarkLeaves (void) mleaf_t *leaf; mnode_t *node; msurface_t **mark; + mod_brush_t *brush = &r_worldentity.model->brush; if (r_oldviewleaf == r_viewleaf && !r_novis->int_val) return; @@ -67,13 +68,13 @@ R_MarkLeaves (void) r_oldviewleaf = 0; // so vis will be recalcualted when novis gets // turned off vis = solid; - memset (solid, 0xff, (r_worldentity.model->brush.numleafs + 7) >> 3); + memset (solid, 0xff, (brush->numleafs + 7) >> 3); } else vis = Mod_LeafPVS (r_viewleaf, r_worldentity.model); - for (i = 0; (int) i < r_worldentity.model->brush.numleafs; i++) { + for (i = 0; (int) i < brush->numleafs; i++) { if (vis[i >> 3] & (1 << (i & 7))) { - leaf = &r_worldentity.model->brush.leafs[i + 1]; + leaf = &brush->leafs[i + 1]; if ((c = leaf->nummarksurfaces)) { mark = leaf->firstmarksurface; do { @@ -81,13 +82,14 @@ R_MarkLeaves (void) mark++; } while (--c); } - node = (mnode_t *) leaf; - do { + leaf->visframe = r_visframecount; + node = brush->leaf_parents[leaf - brush->leafs]; + while (node) { if (node->visframe == r_visframecount) break; node->visframe = r_visframecount; - node = node->parent; - } while (node); + node = brush->node_parents[node - brush->nodes]; + } } } } From 0bfb60775e204a5dedf3a1df8699d212f5c602ac Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Feb 2021 13:19:19 +0900 Subject: [PATCH 326/435] [util] Ensure hunk allocs are cache alligned This doesn't seem to make much difference in the vulkan renderer, but it certainly doesn't hurt. --- include/QF/sys.h | 3 ++- libs/audio/test/testsound.c | 2 +- libs/util/sys.c | 14 ++++++++++++-- libs/util/zone.c | 10 ++++++---- nq/source/host.c | 2 +- qtv/source/qtv.c | 2 +- qw/source/cl_main.c | 2 +- qw/source/sv_demo.c | 2 +- qw/source/sv_main.c | 2 +- ruamoko/qwaq/builtins/main.c | 2 +- ruamoko/qwaq/builtins/qwaq.c | 2 +- tools/bsp2img/bsp2img.c | 2 +- tools/qfcc/test/test-harness.c | 2 +- tools/qflmp/lmp.c | 2 +- tools/wad/wad.c | 2 +- 15 files changed, 32 insertions(+), 19 deletions(-) diff --git a/include/QF/sys.h b/include/QF/sys.h index 8d32d14e2..58aa08b76 100644 --- a/include/QF/sys.h +++ b/include/QF/sys.h @@ -122,7 +122,8 @@ void Sys_Init_Cvars (void); // memory protection // void Sys_MakeCodeWriteable (uintptr_t startaddr, size_t length); -void Sys_PageIn (void *ptr, int size); +void Sys_PageIn (void *ptr, size_t size); +void *Sys_Alloc (size_t size); // // system IO diff --git a/libs/audio/test/testsound.c b/libs/audio/test/testsound.c index f4518d7ac..698fc40ec 100644 --- a/libs/audio/test/testsound.c +++ b/libs/audio/test/testsound.c @@ -68,7 +68,7 @@ init (void) COM_ParseConfig (); Cvar_Get ("cmd_warncmd", "1", CVAR_NONE, NULL, NULL); - Memory_Init (malloc (MEMSIZE), MEMSIZE); + Memory_Init (Sys_Alloc (MEMSIZE), MEMSIZE); QFS_Init ("qw"); PI_Init (); diff --git a/libs/util/sys.c b/libs/util/sys.c index 7e09b4f91..db0777f07 100644 --- a/libs/util/sys.c +++ b/libs/util/sys.c @@ -612,11 +612,11 @@ Sys_TimeID (void) //FIXME I need a new name, one that doesn't make me feel 3 fee } VISIBLE void -Sys_PageIn (void *ptr, int size) +Sys_PageIn (void *ptr, size_t size) { //may or may not be useful in linux #ifdef _WIN32 byte *x; - int m, n; + size_t m, n; // touch all the memory to make sure it's there. The 16-page skip is to // keep Win 95 from thinking we're trying to page ourselves in (we are @@ -632,6 +632,16 @@ Sys_PageIn (void *ptr, int size) //#endif } +VISIBLE void * +Sys_Alloc (size_t size) +{ + size_t page_size = sysconf (_SC_PAGESIZE); + size_t page_mask = page_size - 1; + size = (size + page_mask) & ~page_mask; + return mmap (0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); +} + VISIBLE void Sys_DebugLog (const char *file, const char *fmt, ...) { diff --git a/libs/util/zone.c b/libs/util/zone.c index f52226d55..fdd440764 100644 --- a/libs/util/zone.c +++ b/libs/util/zone.c @@ -56,6 +56,7 @@ static qboolean Cache_FreeLRU (void); #define HUNK_SENTINAL 0x1df001ed #define MINFRAGMENT 64 +#define HUNK_ALIGN 64 /* ZONE MEMORY ALLOCATION @@ -413,6 +414,7 @@ typedef struct { int sentinal; int size; // including sizeof(hunk_t), -1 = not allocated char name[8]; + char fill[48]; // pad out to 64 bytes } hunk_t; byte *hunk_base; @@ -551,7 +553,7 @@ Hunk_AllocName (int size, const char *name) if (size < 0) Sys_Error ("Hunk_Alloc: bad size: %i", size); - size = sizeof (hunk_t) + ((size + 15) & ~15); + size = sizeof (hunk_t) + ((size + HUNK_ALIGN - 1) & ~(HUNK_ALIGN - 1)); if (hunk_size - hunk_low_used - hunk_high_used < size) { Hunk_HighMark(); @@ -618,7 +620,7 @@ Hunk_HighAlloc (int size) Hunk_Check (); #endif - size = ((size + 15) & ~15); + size = ((size + HUNK_ALIGN - 1) & ~(HUNK_ALIGN - 1)); if (hunk_size - hunk_low_used - hunk_high_used < size) { Sys_Printf ("Hunk_HighAlloc: failed on %i bytes\n", size); @@ -640,7 +642,7 @@ Hunk_TempAlloc (int size) { void *buf; - size = (size + 15) & ~15; + size = (size + HUNK_ALIGN - 1) & ~(HUNK_ALIGN - 1); if (hunk_tempactive) { if (hunk_high_used - hunk_tempmark >= size + (int) sizeof (hunk_t)) { @@ -1009,7 +1011,7 @@ Cache_Alloc (cache_user_t *c, int size, const char *name) if (size <= 0) Sys_Error ("Cache_Alloc: size %i", size); - size = (size + sizeof (cache_system_t) + 15) & ~15; + size = (size + sizeof (cache_system_t) + HUNK_ALIGN - 1) & ~(HUNK_ALIGN-1); // find memory for it while (1) { diff --git a/nq/source/host.c b/nq/source/host.c index 65266f801..dba8202e4 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -859,7 +859,7 @@ Host_Init_Memory (void) Sys_Error ("Only %4.1f megs of memory reported, can't execute game", mem_size / (float) 0x100000); - mem_base = malloc (mem_size); + mem_base = Sys_Alloc (mem_size); if (!mem_base) Sys_Error ("Can't allocate %d", mem_size); diff --git a/qtv/source/qtv.c b/qtv/source/qtv.c index 513bb069e..049f0a568 100644 --- a/qtv/source/qtv.c +++ b/qtv/source/qtv.c @@ -214,7 +214,7 @@ qtv_memory_init (void) Cvar_SetFlags (qtv_mem_size, qtv_mem_size->flags | CVAR_ROM); mem_size = (int) (qtv_mem_size->value * 1024 * 1024); - mem_base = malloc (mem_size); + mem_base = Sys_Alloc (mem_size); if (!mem_base) Sys_Error ("Can't allocate %d", mem_size); Memory_Init (mem_base, mem_size); diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index d9ee07b56..5fcf0364e 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -1756,7 +1756,7 @@ CL_Init_Memory (void) Sys_Error ("Only %4.1f megs of memory reported, can't execute game", mem_size / (float) 0x100000); - mem_base = malloc (mem_size); + mem_base = Sys_Alloc (mem_size); if (!mem_base) Sys_Error ("Can't allocate %d", mem_size); diff --git a/qw/source/sv_demo.c b/qw/source/sv_demo.c index b13135c93..1018ecb6c 100644 --- a/qw/source/sv_demo.c +++ b/qw/source/sv_demo.c @@ -774,7 +774,7 @@ Demo_Init (void) if (p < com_argc - 1) size = atoi (com_argv[p + 1]) * 1024; else - Sys_Error ("Memory_Init: you must specify a size in KB after " + Sys_Error ("Demo_Init: you must specify a size in KB after " "-democache"); } diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index 0156d689a..d91a24832 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -2470,7 +2470,7 @@ SV_Init_Memory (void) Sys_Error ("Only %4.1f megs of memory reported, can't execute game", mem_size / (float) 0x100000); - mem_base = malloc (mem_size); + mem_base = Sys_Alloc (mem_size); if (!mem_base) Sys_Error ("Can't allocate %d", mem_size); diff --git a/ruamoko/qwaq/builtins/main.c b/ruamoko/qwaq/builtins/main.c index dbafed33f..f8800df93 100644 --- a/ruamoko/qwaq/builtins/main.c +++ b/ruamoko/qwaq/builtins/main.c @@ -136,7 +136,7 @@ init_qf (void) //Cvar_Set (developer, "1"); - Memory_Init (malloc (8 * 1024 * 1024), 8 * 1024 * 1024); + Memory_Init (Sys_Alloc (8 * 1024 * 1024), 8 * 1024 * 1024); Cvar_Get ("pr_debug", "2", 0, 0, 0); Cvar_Get ("pr_boundscheck", "0", 0, 0, 0); diff --git a/ruamoko/qwaq/builtins/qwaq.c b/ruamoko/qwaq/builtins/qwaq.c index f74b429cf..c1733ae0e 100644 --- a/ruamoko/qwaq/builtins/qwaq.c +++ b/ruamoko/qwaq/builtins/qwaq.c @@ -114,7 +114,7 @@ init_qf (void) //Cvar_Set (developer, "1"); - Memory_Init (malloc (8 * 1024 * 1024), 8 * 1024 * 1024); + Memory_Init (Sys_Alloc (8 * 1024 * 1024), 8 * 1024 * 1024); Cvar_Get ("pr_debug", "2", 0, 0, 0); Cvar_Get ("pr_boundscheck", "0", 0, 0, 0); diff --git a/tools/bsp2img/bsp2img.c b/tools/bsp2img/bsp2img.c index 7b95c35a6..bf99eea67 100644 --- a/tools/bsp2img/bsp2img.c +++ b/tools/bsp2img/bsp2img.c @@ -925,7 +925,7 @@ write_pcx (image_t *image) Sys_Init (); - Memory_Init (malloc (MEMSIZE), MEMSIZE); + Memory_Init (Sys_Alloc (MEMSIZE), MEMSIZE); pcx = EncodePCX (image->image, image->width, image->height, image->width, palette, false, &pcx_len); if (Qwrite (outfile, pcx, pcx_len) != pcx_len) { diff --git a/tools/qfcc/test/test-harness.c b/tools/qfcc/test/test-harness.c index ba9759c19..69de8c47b 100644 --- a/tools/qfcc/test/test-harness.c +++ b/tools/qfcc/test/test-harness.c @@ -134,7 +134,7 @@ init_qf (void) Sys_Init (); Cvar_Get ("developer", va ("%d", options.developer), 0, 0, 0); - Memory_Init (malloc (1024 * 1024), 1024 * 1024); + Memory_Init (Sys_Alloc (1024 * 1024), 1024 * 1024); cvar_t *debug = Cvar_Get ("pr_debug", "2", 0, 0, 0); Cvar_Get ("pr_boundscheck", "2", 0, 0, 0); diff --git a/tools/qflmp/lmp.c b/tools/qflmp/lmp.c index 1840ce328..06a77e370 100644 --- a/tools/qflmp/lmp.c +++ b/tools/qflmp/lmp.c @@ -334,7 +334,7 @@ main (int argc, char **argv) this_program = argv[0]; Sys_Init (); - Memory_Init (malloc (MEMSIZE), MEMSIZE); + Memory_Init (Sys_Alloc (MEMSIZE), MEMSIZE); decode_args (argc, argv); diff --git a/tools/wad/wad.c b/tools/wad/wad.c index a1caf6fc9..08abf6d81 100644 --- a/tools/wad/wad.c +++ b/tools/wad/wad.c @@ -396,7 +396,7 @@ main (int argc, char **argv) lumpinfo_t *pf; Sys_Init (); - Memory_Init (malloc (MEMSIZE), MEMSIZE); + Memory_Init (Sys_Alloc (MEMSIZE), MEMSIZE); this_program = argv[0]; From 5d1d85f72e09f1ee385559b1c6f32b167e46a705 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Feb 2021 13:21:08 +0900 Subject: [PATCH 327/435] [util] Resurrect Hunk_Print and fix some errors It turned out that Hunk_HighAlloc was not creating a hunk header (ancient bug by me), and I cleaned up a bunch of name-size issues, along the way. --- include/QF/zone.h | 1 + libs/util/zone.c | 42 +++++++++++++++++++++++------------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/include/QF/zone.h b/include/QF/zone.h index 10063b2cc..023ff07d6 100644 --- a/include/QF/zone.h +++ b/include/QF/zone.h @@ -105,6 +105,7 @@ void Z_SetError (memzone_t *zone, void (*err) (void *data, const char *msg), void *data); void Z_CheckPointer (const memzone_t *zone, const void *ptr, int size); +void Hunk_Print (qboolean all); void *Hunk_Alloc (int size); // returns 0 filled memory void *Hunk_AllocName (int size, const char *name); int Hunk_LowMark (void) __attribute__((pure)); diff --git a/libs/util/zone.c b/libs/util/zone.c index fdd440764..14ef0b503 100644 --- a/libs/util/zone.c +++ b/libs/util/zone.c @@ -438,7 +438,8 @@ Hunk_Check (void) for (h = (hunk_t *) hunk_base; (byte *) h != hunk_base + hunk_low_used;) { if (h->sentinal != HUNK_SENTINAL) Sys_Error ("Hunk_Check: trashed sentinal"); - if (h->size < 16 || h->size + (byte *) h - hunk_base > hunk_size) + if (h->size < (int) sizeof (hunk_t) + || h->size + (byte *) h - hunk_base > hunk_size) Sys_Error ("Hunk_Check: bad size"); h = (hunk_t *) ((byte *) h + h->size); } @@ -451,15 +452,13 @@ Hunk_Check (void) Otherwise, allocations with the same name will be totaled up before printing. */ -/* -static void + +VISIBLE void Hunk_Print (qboolean all) { - char name[9]; hunk_t *h, *next, *endlow, *starthigh, *endhigh; int count, sum, totalblocks; - name[8] = 0; count = 0; sum = 0; totalblocks = 0; @@ -488,7 +487,8 @@ Hunk_Print (qboolean all) // run consistancy checks if (h->sentinal != HUNK_SENTINAL) Sys_Error ("Hunk_Check: trahsed sentinal"); - if (h->size < 16 || h->size + (byte *) h - hunk_base > hunk_size) + if (h->size < (int) sizeof (hunk_t) + || h->size + (byte *) h - hunk_base > hunk_size) Sys_Error ("Hunk_Check: bad size"); next = (hunk_t *) ((byte *) h + h->size); @@ -497,15 +497,14 @@ Hunk_Print (qboolean all) sum += h->size; // print the single block - memcpy (name, h->name, 8); if (all) - Sys_Printf ("%8p :%8i %8s\n", h, h->size, name); + Sys_Printf ("%8p :%8i %8.8s\n", h, h->size, h->name); // print the total if (next == endlow || next == endhigh || strncmp (h->name, next->name, 8)) { if (!all) - Sys_Printf (" :%8i %8s (TOTAL)\n", sum, name); + Sys_Printf (" :%8i %8.8s (TOTAL)\n", sum, h->name); count = 0; sum = 0; } @@ -516,7 +515,7 @@ Hunk_Print (qboolean all) Sys_Printf ("-------------------------\n"); Sys_Printf ("%8i total blocks\n", totalblocks); } -*/ + static void Hunk_FreeToHighMark (int mark) { @@ -579,8 +578,7 @@ Hunk_AllocName (int size, const char *name) h->size = size; h->sentinal = HUNK_SENTINAL; - memcpy (h->name, name, 8); - h->name[7] = 0; + memcpy (h->name, name, sizeof (h->name)); return (void *) (h + 1); } @@ -609,6 +607,8 @@ Hunk_FreeToLowMark (int mark) static void * Hunk_HighAlloc (int size) { + hunk_t *h; + if (size < 0) Sys_Error ("Hunk_HighAlloc: bad size: %i", size); @@ -620,7 +620,7 @@ Hunk_HighAlloc (int size) Hunk_Check (); #endif - size = ((size + HUNK_ALIGN - 1) & ~(HUNK_ALIGN - 1)); + size = sizeof (hunk_t) + ((size + HUNK_ALIGN - 1) & ~(HUNK_ALIGN - 1)); if (hunk_size - hunk_low_used - hunk_high_used < size) { Sys_Printf ("Hunk_HighAlloc: failed on %i bytes\n", size); @@ -629,7 +629,11 @@ Hunk_HighAlloc (int size) hunk_high_used += size; - return (void *) (hunk_base + hunk_size - hunk_high_used); + h = (void *) (hunk_base + hunk_size - hunk_high_used); + h->sentinal = HUNK_SENTINAL; + h->size = size; + h->name[0] = 0; + return h + 1; } /* @@ -744,7 +748,7 @@ static inline void Cache_UnlinkLRU (cache_system_t * cs) { if (!cs->lru_next || !cs->lru_prev) - Sys_Error ("Cache_UnlinkLRU: NULL link: %s %p %p", + Sys_Error ("Cache_UnlinkLRU: NULL link: %.16s %p %p", cs->name, cs->lru_next, cs->lru_prev); cs->lru_next->lru_prev = cs->lru_prev; @@ -757,7 +761,7 @@ static void Cache_MakeLRU (cache_system_t * cs) { if (cs->lru_next || cs->lru_prev) - Sys_Error ("Cache_MakeLRU: active link: %s %p %p", + Sys_Error ("Cache_MakeLRU: active link: %.16s %p %p", cs->name, cs->lru_next, cs->lru_prev); cache_head.lru_next->lru_prev = cs; @@ -896,7 +900,7 @@ Cache_Print (void) cache_system_t *cd; for (cd = cache_head.next; cd != &cache_head; cd = cd->next) { - Sys_Printf ("%8d : %s\n", (int) cd->size, cd->name); + Sys_Printf ("%8d : %.16s\n", (int) cd->size, cd->name); } } @@ -929,7 +933,7 @@ Cache_Flush (void) while (cache_head.prev != &cache_head) { if (!cache_head.prev->user->data) Sys_Error ("Cache_Flush: user/system out of sync for " - "'%s' with %d size", + "'%.16s' with %d size", cache_head.prev->name, (int) cache_head.prev->size); Cache_Free (cache_head.prev->user); // reclaim the space } @@ -970,7 +974,7 @@ Cache_Free (cache_user_t *c) if (cs->readlock) Sys_Error ("Cache_Free: attempt to free locked block"); - Sys_MaskPrintf (SYS_DEV, "Cache_Free: freeing '%s' %p\n", cs->name, cs); + Sys_MaskPrintf (SYS_DEV, "Cache_Free: freeing '%.16s' %p\n", cs->name, cs); Cache_UnlinkLRU (cs); From 846fcc276c68a6d6a01ff0b3697746e8b76c86e6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Feb 2021 18:24:15 +0900 Subject: [PATCH 328/435] [nq] Allow free-fps for demo playback I still need to look into making physics (and network, I imagine) work with unlimited frame rates, but this gets in what I need for now. --- nq/source/host.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nq/source/host.c b/nq/source/host.c index dba8202e4..bb4721677 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -529,7 +529,7 @@ Host_FilterTime (float time) //FIXME not having the framerate cap is nice, but it breaks net play timedifference = (timescale / 72.0) - (realtime - oldrealtime); - if (!cls.timedemo && (timedifference > 0)) + if (!cls.demoplayback && (timedifference > 0)) return timedifference; // framerate is too high host_frametime = realtime - oldrealtime; @@ -541,7 +541,7 @@ Host_FilterTime (float time) if (host_framerate->value > 0) host_frametime = host_framerate->value; else // don't allow really long or short frames - host_frametime = bound (0.001, host_frametime, 0.1); + host_frametime = bound (0.000, host_frametime, 0.1); return 0; } From d2536e584f112bdbfaf3e23002678c16832eab96 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 4 Feb 2021 16:58:13 +0900 Subject: [PATCH 329/435] [util] Add plist support to cexpr This allows plist objects to be accessed directly from cexpr expressions using struct.field syntax for dictionary objects and array[index] syntax for array objects. --- include/QF/cexpr.h | 1 + libs/util/cexpr-parse.y | 30 +++++++++++++++ libs/util/cexpr-type.c | 83 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index 53fc159e7..f511b6a9c 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -132,6 +132,7 @@ extern exprtype_t cexpr_quaternion; extern exprtype_t cexpr_exprval; extern exprtype_t cexpr_field; extern exprtype_t cexpr_function; +extern exprtype_t cexpr_plitem; extern binop_t cexpr_struct_binops[]; extern binop_t cexpr_struct_pointer_binops[]; diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y index f208f4680..07993af9b 100644 --- a/libs/util/cexpr-parse.y +++ b/libs/util/cexpr-parse.y @@ -56,6 +56,8 @@ static exprval_t *binary_expr (int op, const exprval_t *a, const exprval_t *b, exprctx_t *context); static exprval_t *field_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context); +static exprval_t *index_expr (const exprval_t *a, const exprval_t *b, + exprctx_t *context); static exprval_t *unary_expr (int op, const exprval_t *val, exprctx_t *context); static exprval_t *vector_expr (exprlist_t *list, exprctx_t *context); @@ -126,6 +128,7 @@ uexpr | '(' expr ')' { $$ = $2; } | NAME '(' opt_arg_list ')' { $$ = function_expr ($1, $3, context); } | uexpr '.' field { $$ = field_expr ($1, $3, context); } + | uexpr '[' field ']' { $$ = index_expr ($1, $3, context); } | '+' uexpr %prec UNARY { $$ = $2; } | '-' uexpr %prec UNARY { $$ = unary_expr ('-', $2, context); } | '!' uexpr %prec UNARY { $$ = unary_expr ('!', $2, context); } @@ -237,6 +240,10 @@ field_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context) binop_t *binop; exprval_t *result = 0; + if (!a) { + return 0; + } + for (binop = a->type->binops; binop->op; binop++) { if (binop->op == '.' && binop->other == b->type) { break; @@ -254,6 +261,29 @@ field_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context) return result; } +static exprval_t * +index_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context) +{ + binop_t *binop; + exprval_t *result = 0; + + for (binop = a->type->binops; binop->op; binop++) { + if (binop->op == '[' && binop->other == b->type) { + break; + } + } + if (!binop->op) { + cexpr_error (context, "invalid index expression: %s.%s", + a->type->name, b->type->name); + result = cexpr_value (&cexpr_int, context); + *(int *) result->value = 0; + } else { + exprval_t c = { 0, &result }; + binop->func (a, b, &c, context); + } + return result; +} + static exprval_t * unary_expr (int op, const exprval_t *val, exprctx_t *context) { diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index 57c7a945b..c01e0cac0 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -30,6 +30,7 @@ #include #include "QF/cexpr.h" +#include "QF/cmem.h" #include "QF/mathlib.h" #include "QF/qfplist.h" #include "QF/simd/vec4f.h" @@ -594,6 +595,88 @@ exprtype_t cexpr_function = { 0, }; +static void +plitem_field (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + __auto_type dict = *(plitem_t **) a->value; + __auto_type key = (const char *) b->value; + + if (PL_Type (dict) != QFDictionary) { + cexpr_error(ctx, "not a dictionary object"); + return; + } + plitem_t *item = PL_ObjectForKey (dict, key); + exprval_t *val = 0; + if (!item) { + cexpr_error (ctx, "key not found: %s", key); + } else { + val = cexpr_value (&cexpr_plitem, ctx); + *(plitem_t **) val->value = item; + } + *(exprval_t **) c->value = val; +} + +static void +plitem_index (const exprval_t *a, int index, exprval_t *c, + exprctx_t *ctx) +{ + __auto_type array = *(plitem_t **) a->type->data; + + if (PL_Type (array) != QFArray) { + cexpr_error(ctx, "not an array object"); + return; + } + plitem_t *item = PL_ObjectAtIndex (array, index); + exprval_t *val = 0; + if (!item) { + cexpr_error (ctx, "invalid index: %d", index); + } else { + val = cexpr_value (&cexpr_plitem, ctx); + *(plitem_t **) val->value = item; + } + *(exprval_t **) c->value = val; +} + +static void +plitem_int (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + int index = *(int *) a->value; + plitem_index (a, index, c, ctx); +} + +static void +plitem_uint (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + int index = *(int *) a->value; + plitem_index (a, index, c, ctx); +} + +static void +plitem_size_t (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + int index = *(int *) a->value; + plitem_index (a, index, c, ctx); +} + +binop_t plitem_binops[] = { + { '.', &cexpr_field, &cexpr_plitem, plitem_field }, + { '[', &cexpr_int, &cexpr_plitem, plitem_int }, + { '[', &cexpr_uint, &cexpr_plitem, plitem_uint }, + { '[', &cexpr_size_t, &cexpr_plitem, plitem_size_t }, + {} +}; + +exprtype_t cexpr_plitem = { + "plitem", + sizeof (plitem_t *), + plitem_binops, + 0, +}; + VISIBLE binop_t * cexpr_find_cast (exprtype_t *dst_type, exprtype_t *src_type) { From 8179c44042c60ef4db469e1302cc1b029f7a616d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 4 Feb 2021 17:03:49 +0900 Subject: [PATCH 330/435] [vulkan] Rework pipeline parsing for better reuse It's not entirely there yet, but the basics are working. Work is still needed for avoiding duplication of objects (different threads will have different contexts and thus different tables, so necessary per-thread duplication should not become a problem) and general access to arbitrary fields (mostly just parsing the strings) --- include/QF/Vulkan/qf_vid.h | 10 +- include/vid_vulkan.h | 1 + libs/video/renderer/vulkan/qfpipeline.plist | 103 +++--- .../video/renderer/vulkan/vkgen/Makemodule.am | 2 - libs/video/renderer/vulkan/vkgen/vkgen.r | 32 -- libs/video/renderer/vulkan/vkgen/vkhandle.h | 8 - libs/video/renderer/vulkan/vkgen/vkhandle.r | 74 ---- libs/video/renderer/vulkan/vkgen/vkresource.h | 9 - libs/video/renderer/vulkan/vkgen/vkresource.r | 44 --- libs/video/renderer/vulkan/vkparse.c | 323 ++++++++++++------ libs/video/renderer/vulkan/vkparse.h | 13 +- libs/video/renderer/vulkan/vkparse.plist | 69 +--- libs/video/renderer/vulkan/vulkan_alias.c | 9 +- libs/video/renderer/vulkan/vulkan_bsp.c | 13 +- libs/video/renderer/vulkan/vulkan_draw.c | 9 +- .../video/renderer/vulkan/vulkan_vid_common.c | 100 ++++-- 16 files changed, 388 insertions(+), 431 deletions(-) delete mode 100644 libs/video/renderer/vulkan/vkgen/vkhandle.h delete mode 100644 libs/video/renderer/vulkan/vkgen/vkhandle.r delete mode 100644 libs/video/renderer/vulkan/vkgen/vkresource.h delete mode 100644 libs/video/renderer/vulkan/vkgen/vkresource.r diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index 7e30a3a57..1102845b5 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -40,7 +40,6 @@ void Vulkan_DestroyFramebuffers (struct vulkan_ctx_s *ctx); void Vulkan_CreateFramebuffers (struct vulkan_ctx_s *ctx); void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx); void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx); -VkPipeline Vulkan_CreatePipeline (struct vulkan_ctx_s *ctx, const char *name); void Vulkan_CreateMatrices (struct vulkan_ctx_s *ctx); void Vulkan_DestroyMatrices (struct vulkan_ctx_s *ctx); void Vulkan_CalcProjectionMatrices (struct vulkan_ctx_s *ctx, float aspect); @@ -51,4 +50,13 @@ void Vulkan_Init_Common (struct vulkan_ctx_s *ctx); void Vulkan_Shutdown_Common (struct vulkan_ctx_s *ctx); void Vulkan_CreateStagingBuffers (struct vulkan_ctx_s *ctx); +VkPipeline Vulkan_CreatePipeline (struct vulkan_ctx_s *ctx, const char *name); +VkDescriptorPool Vulkan_CreateDescriptorPool (struct vulkan_ctx_s *ctx, + const char *name); +VkPipelineLayout Vulkan_CreatePipelineLayout (struct vulkan_ctx_s *ctx, + const char *name); +VkSampler Vulkan_CreateSampler (struct vulkan_ctx_s *ctx, const char *name); +VkDescriptorSetLayout Vulkan_CreateDescriptorSetLayout(struct vulkan_ctx_s*ctx, + const char *name); + #endif // __QF_Vulkan_vid_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index a213c7ac5..38aa4b69f 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -58,6 +58,7 @@ typedef struct vulkan_ctx_s { struct hashlink_s *hashlinks; //FIXME want per thread VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain struct plitem_s *pipelineDef; + struct hashtab_s *shaderModules; struct hashtab_s *setLayouts; struct hashtab_s *pipelineLayouts; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 96de769c9..8ba2937c2 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -1,19 +1,4 @@ { - shaderModules = { - // specify shader modules to load into memory - // key is the name of the module for referecy by the pipeline - // value the path to the spv file to load - // $shader refers to the shader install path - // $builtin refers to compiled-in shaders - passthrough = $builtin/passthrough.vert; - pushcolor = $builtin/pushcolor.frag; - twodv = $builtin/twod.vert; - twodf = $builtin/twod.frag; - quakebspv = $builtin/quakebsp.vert; - quakebspf = $builtin/quakebsp.frag; - aliasv = $builtin/alias.vert; - aliasf = $builtin/alias.frag; - }; samplers = { quakepic = { magFilter = nearest; @@ -32,7 +17,7 @@ borderColor = float_transparent_black; unnormalizedCoordinates = false; }; - quakebsp.sampler = { + quakebsp_sampler = { magFilter = linear; minFilter = linear; mipmapMode = linear; @@ -49,7 +34,7 @@ borderColor = float_transparent_black; unnormalizedCoordinates = false; }; - alias.sampler = { + alias_sampler = { magFilter = linear; minFilter = linear; mipmapMode = linear; @@ -68,7 +53,7 @@ }; }; descriptorPools = { - twod.pool = { + twod_pool = { flags = 0; maxSets = $framebuffers.size; bindings = ( @@ -82,7 +67,7 @@ }, ); }; - alias.pool = { + alias_pool = { flags = 0; maxSets = "2z * $framebuffers.size"; bindings = ( @@ -94,7 +79,7 @@ }; }; setLayouts = { - twod.set = { + twod_set = { bindings = ( { binding = 0; @@ -110,7 +95,7 @@ }, ); }; - quakebsp.set = { + quakebsp_set = { flags = push_descriptor; bindings = ( { @@ -151,7 +136,7 @@ }, ); }; - alias.set = { + alias_set = { flags = push_descriptor; bindings = ( { @@ -174,7 +159,7 @@ }, ); }; - alias.matrices = { + alias_matrices = { bindings = ( { binding = 0; @@ -184,7 +169,7 @@ }, ); }; - alias.textures = { + alias_textures = { flags = push_descriptor; bindings = ( { @@ -213,7 +198,7 @@ }, ); }; - alias.lights = { + alias_lights = { bindings = ( { binding = 0; @@ -242,11 +227,11 @@ }; }; pipelineLayouts = { - twod.layout = { - setLayouts = (twod.set); + twod_layout = { + setLayouts = (twod_set); }; - quakebsp.layout = { - setLayouts = (quakebsp.set); + quakebsp_layout = { + setLayouts = (quakebsp_set); pushConstantRanges = ( { stageFlags = vertex; @@ -260,9 +245,9 @@ }, ); }; - alias.layout = { - //setLayouts = (alias.matrices, alias.lights, alias.textures); - setLayouts = (alias.set); + alias_layout = { + //setLayouts = (alias_matrices, alias_lights, alias_textures); + setLayouts = (alias_set); pushConstantRanges = ( { stageFlags = vertex; @@ -290,11 +275,15 @@ pipelines = { alias = { stages = ( - { stage = vertex; name = main; module = aliasv; }, + { + stage = vertex; + name = main; + module = $builtin/alias.vert; + }, { stage = fragment; name = main; - module = aliasf; + module = $builtin/alias.frag; specializationInfo = { mapEntries = ( { size = 4; offset = 0; constantID = 0; }, @@ -412,13 +401,21 @@ dynamic = { dynamicState = ( viewport, scissor, blend_constants ); }; - layout = alias.layout; + layout = alias_layout; //renderPass = renderpass; }; - quakebsp.main = { + quakebsp_main = { stages = ( - { stage = vertex; name = main; module = quakebspv; }, - { stage = fragment; name = main; module = quakebspf; }, + { + stage = vertex; + name = main; + module = $builtin/quakebsp.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/quakebsp.frag; + }, ); vertexInput = { bindings = ( @@ -501,16 +498,20 @@ dynamic = { dynamicState = ( viewport, scissor, blend_constants ); }; - layout = quakebsp.layout; + layout = quakebsp_layout; //renderPass = renderpass; }; - quakebsp.skysheet = { + quakebsp_skysheet = { stages = ( - { stage = vertex; name = main; module = quakebspv; }, + { + stage = vertex; + name = main; + module = $builtin/quakebsp.vert; + }, { stage = fragment; name = main; - module = quakebspf; + module = $builtin/quakebsp.frag; specializationInfo = { mapEntries = ( { size = 4; offset = 0; constantID = 0; }, @@ -603,13 +604,21 @@ dynamic = { dynamicState = ( viewport, scissor, blend_constants ); }; - layout = quakebsp.layout; + layout = quakebsp_layout; //renderPass = renderpass; }; twod = { stages = ( - { stage = vertex; name = main; module = twodv; }, - { stage = fragment; name = main; module = twodf; }, + { + stage = vertex; + name = main; + module = $builtin/twod.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/twod.frag; + }, ); vertexInput = { bindings = ( @@ -698,7 +707,7 @@ dynamic = { dynamicState = ( viewport, scissor ); }; - layout = twod.layout; + layout = twod_layout; //renderPass = renderpass; }; }; @@ -764,7 +773,7 @@ }, ); }; - renderpass.msaa = { + renderpass_msaa = { attachments = ( { flags = 0; diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am index 2fba61b0b..b60e97f1d 100644 --- a/libs/video/renderer/vulkan/vkgen/Makemodule.am +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -13,8 +13,6 @@ vkgen_dat_src= \ libs/video/renderer/vulkan/vkgen/vkfieldstring.r \ libs/video/renderer/vulkan/vkgen/vkfieldtype.r \ libs/video/renderer/vulkan/vkgen/vkgen.r \ - libs/video/renderer/vulkan/vkgen/vkhandle.r \ - libs/video/renderer/vulkan/vkgen/vkresource.r \ libs/video/renderer/vulkan/vkgen/vkstruct.r \ libs/video/renderer/vulkan/vkgen/vktype.r \ libs/video/renderer/vulkan/vkgen/vulkan.r diff --git a/libs/video/renderer/vulkan/vkgen/vkgen.r b/libs/video/renderer/vulkan/vkgen/vkgen.r index a336a861c..25bcbaf69 100644 --- a/libs/video/renderer/vulkan/vkgen/vkgen.r +++ b/libs/video/renderer/vulkan/vkgen/vkgen.r @@ -10,8 +10,6 @@ #include "vkgen.h" #include "vkstruct.h" #include "vkenum.h" -#include "vkhandle.h" -#include "vkresource.h" static AutoreleasePool *autorelease_pool; static void @@ -154,7 +152,6 @@ main(int argc, string *argv) PLItem *plist; PLItem *search; PLItem *handles; - PLItem *resources; arp_start (); @@ -179,7 +176,6 @@ main(int argc, string *argv) } search = [[plist getObjectForKey: "search"] retain]; handles = [[plist getObjectForKey: "handles"] retain]; - resources = [[plist getObjectForKey: "resources"] retain]; parse = [[plist getObjectForKey: "parse"] retain]; encodings = PR_FindGlobal (".type_encodings"); @@ -204,17 +200,6 @@ main(int argc, string *argv) } } - PLItem *handle_keys = [[handles allKeys] retain]; - for (int i = [handle_keys count]; i-- > 0; ) { - string search_name = [[handle_keys getObjectAtIndex:i] string]; - id obj = (id) Hash_Find (available_types, search_name); - obj = [obj resolveType]; - printf("handle: %d %s\n", obj, class_get_class_name([obj class])); - if (obj && [obj class] == [Struct class]) { - [obj addToQueue]; - } - } - while ([queue count]) { id obj = [queue objectAtIndex:0]; [queue removeObjectAtIndex:0]; @@ -261,23 +246,6 @@ main(int argc, string *argv) [obj writeTable]; arp_end (); } - for (int i = [handle_keys count]; i-- > 0; ) { - string key = [[handle_keys getObjectAtIndex:i] string]; - output_handle (key, [handles getObjectForKey: key]); - } - for (int i = [resources count]; i-- > 0; ) { - PLItem *res = [resources getObjectAtIndex:i]; - output_resource_data (res); - } - // keep the order intuitive (since it matters) - fprintf (output_file, "static parseres_t parse_resources[] = {\n"); - for (int i = 0; i < [resources count]; i++) { - PLItem *res = [resources getObjectAtIndex:i]; - output_resource_entry (res); - } - fprintf (output_file, "\t{}\n"); - fprintf (output_file, "};\n"); - fprintf (output_file, "static void\n"); fprintf (output_file, "vkgen_init_symtabs (exprctx_t *context)\n"); fprintf (output_file, "{\n"); diff --git a/libs/video/renderer/vulkan/vkgen/vkhandle.h b/libs/video/renderer/vulkan/vkgen/vkhandle.h deleted file mode 100644 index 47a68798b..000000000 --- a/libs/video/renderer/vulkan/vkgen/vkhandle.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __renderer_vulkan_vkgen_vkhandle_h -#define __renderer_vulkan_vkgen_vkhandle_h - -@class PLItem; - -void output_handle (string name, PLItem *handle); - -#endif//__renderer_vulkan_vkgen_vkhandle_h diff --git a/libs/video/renderer/vulkan/vkgen/vkhandle.r b/libs/video/renderer/vulkan/vkgen/vkhandle.r deleted file mode 100644 index ec78c22ba..000000000 --- a/libs/video/renderer/vulkan/vkgen/vkhandle.r +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include - -#include "vkgen.h" -#include "vkhandle.h" - -void -output_handle (string name, PLItem *handle) -{ - string symtab = str_hold ([[handle getObjectForKey:"symtab"] string]); - string class = str_hold ([[handle getObjectForKey:"class"] string]); - string create = str_hold ([[handle getObjectForKey:"create"] string]); - string custom = str_hold ([[handle getObjectForKey:"custom"] string]); - if (!custom) { - fprintf (output_file, "static int parse_%s (const plitem_t *item, void **data, plitem_t *messages, parsectx_t *context)\n", name); - fprintf (output_file, "{\n"); - fprintf (output_file, "\t__auto_type handle = (%s *) data[0];\n", name); - fprintf (output_file, "\tvulkan_ctx_t *ctx = context->vctx;\n"); - fprintf (output_file, "\tqfv_device_t *device = ctx->device;\n"); - fprintf (output_file, "\tqfv_devfuncs_t *dfunc = device->funcs;\n"); - fprintf (output_file, "\tif (PL_Type (item) == QFString) {\n"); - fprintf (output_file, "\t\tconst char *name = PL_String (item);\n"); - fprintf (output_file, "\t\thandleref_t *hr = Hash_Find (ctx->%s, name);\n", symtab); - fprintf (output_file, "\t\tif (!hr) {\n"); - fprintf (output_file, "\t\t\tPL_Message (messages, item, \"undefined %s %%s\", name);\n", class); - fprintf (output_file, "\t\t\treturn 0;\n"); - fprintf (output_file, "\t\t}\n"); - fprintf (output_file, "\t\t*handle = (%s) hr->handle;\n", name); - fprintf (output_file, "\t\treturn 1;\n"); - fprintf (output_file, "\t}\n"); - - fprintf (output_file, "\t%sCreateInfo createInfo = {};\n", name); - - fprintf (output_file, "\tif (!parse_%sCreateInfo (0, item, &createInfo, messages, context)) {\n", name); - fprintf (output_file, "\t\treturn 0;\n"); - fprintf (output_file, "\t}\n"); - fprintf (output_file, "\tVkResult res;\n"); - fprintf (output_file, "\tres = dfunc->%s (device->dev, &createInfo, 0, handle);\n", create); - fprintf (output_file, "\tif (res != VK_SUCCESS) {\n"); - fprintf (output_file, "\t\tPL_Message (messages, item, \"could not create %s\");\n", class); - fprintf (output_file, "\t\treturn 0;\n"); - fprintf (output_file, "\t}\n"); - fprintf (output_file, "\treturn 1;\n"); - fprintf (output_file, "}\n"); - } - - fprintf (output_file, "int parse_%s_handleref (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context)\n", name); - fprintf (output_file, "{\n"); - fprintf (output_file, "\thandleref_t *handleref = data;\n"); - fprintf (output_file, "\tvoid *hrdata[] = { &handleref->handle };\n"); - fprintf (output_file, "\thandleref->name = strdup (field->name);\n"); - if (custom) { - fprintf (output_file, "\treturn %s (item, hrdata, messages, context);\n", custom); - } else { - fprintf (output_file, "\treturn parse_%s (item, hrdata, messages, context);\n", name); - } - fprintf (output_file, "}\n"); - - fprintf (output_file, "%s QFV_Get%s (vulkan_ctx_t *ctx, const char *name)\n", name, str_mid (name, 2)); - fprintf (output_file, "{\n"); - fprintf (output_file, "\thandleref_t *handleref = Hash_Find (ctx->%s, name);\n", symtab); - fprintf (output_file, "\treturn handleref ? (%s) handleref->handle : 0;\n", name); - fprintf (output_file, "}\n"); - - if (!custom) { - fprintf (header_file, "static int parse_%s (const plitem_t *item, void **data, plitem_t *messages, parsectx_t *context);\n", name); - } - fprintf (header_file, "int parse_%s_handleref (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context);\n", name); - fprintf (output_file, "%s QFV_Get%s (vulkan_ctx_t *ctx, const char *name);\n", name, str_mid (name, 2)); - str_free (custom); - str_free (symtab); - str_free (class); - str_free (create); -} diff --git a/libs/video/renderer/vulkan/vkgen/vkresource.h b/libs/video/renderer/vulkan/vkgen/vkresource.h deleted file mode 100644 index e72042c3e..000000000 --- a/libs/video/renderer/vulkan/vkgen/vkresource.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __renderer_vulkan_vkgen_vkresource_h -#define __renderer_vulkan_vkgen_vkresource_h - -@class PLItem; - -void output_resource_data (PLItem *resource); -void output_resource_entry (PLItem *resource); - -#endif//__renderer_vulkan_vkgen_vkresource_h diff --git a/libs/video/renderer/vulkan/vkgen/vkresource.r b/libs/video/renderer/vulkan/vkgen/vkresource.r deleted file mode 100644 index 47478d9f8..000000000 --- a/libs/video/renderer/vulkan/vkgen/vkresource.r +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -#include "vkgen.h" -#include "vkresource.h" - -void -output_resource_data (PLItem *resource) -{ - string name = str_hold ([[resource getObjectForKey:"name"] string]); - string parse_type = str_hold ([[resource getObjectForKey:"parse_type"] string]); - string parser = str_hold ([[resource getObjectForKey:"parser"] string]); - string type = str_hold ([[resource getObjectForKey:"type"] string]); - - fprintf (output_file, "static plelement_t resource_%s_data = {\n", name); - fprintf (output_file, "\t%s,\n", parse_type); - fprintf (output_file, "\tsizeof (%s),\n", type); - fprintf (output_file, "\tmalloc,\n"); - fprintf (output_file, "\t%s,\n", parser); - fprintf (output_file, "\t0,\n"); - fprintf (output_file, "};\n"); - - fprintf (output_file, "static plfield_t resource_%s_field = {\n", name); - fprintf (output_file, "\t0, 0, %s, 0, &resource_%s_data\n", - parse_type, name); - fprintf (output_file, "};\n"); - - str_free (name); - str_free (parse_type); - str_free (parser); - str_free (type); -} - -void -output_resource_entry (PLItem *resource) -{ - string name = str_hold ([[resource getObjectForKey:"name"] string]); - string table = str_hold ([[resource getObjectForKey:"table"] string]); - fprintf (output_file, - "\t{\"%s\", &resource_%s_field, field_offset (vulkan_ctx_t, %s) },\n", - name, name, table); - str_free (name); - str_free (table); -} diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 4108a75f5..88c580506 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -362,48 +362,103 @@ parse_RGBA (const plitem_t *item, void **data, return ret; } +static void +add_handle (hashtab_t *tab, const char *name, uint64_t handle) +{ + handleref_t *hr = malloc (sizeof (handleref_t)); + hr->name = strdup (name); + hr->handle = handle; + Hash_Add (tab, hr); +} + static int parse_VkShaderModule (const plitem_t *item, void **data, plitem_t *messages, parsectx_t *context) { __auto_type handle = (VkShaderModule *) data[0]; vulkan_ctx_t *ctx = context->vctx; + qfv_device_t *device = ctx->device; const char *name = PL_String (item); handleref_t *hr = Hash_Find (ctx->shaderModules, name); - if (!hr) { - PL_Message (messages, item, "undefined shader module %s", name); + if (hr) { + *handle = (VkShaderModule) hr->handle; + return 1; + } + if (!(*handle = QFV_CreateShaderModule (device, name))) { + PL_Message (messages, item, "could not find shader %s", name); return 0; } - *handle = (VkShaderModule) hr->handle; + add_handle (ctx->shaderModules, name, (uint64_t) *handle); return 1; } static int -parse_VkShaderModule_resource (const plitem_t *item, void **data, - plitem_t *messages, parsectx_t *context) +parse_VkDescriptorSetLayout (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) { - __auto_type handle = (VkShaderModule *) data[0]; + __auto_type handle = (VkDescriptorSetLayout *) data; + int ret = 1; + exprctx_t ectx = *((parsectx_t *) context)->ectx; vulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx; - qfv_device_t *device = ctx->device; - const char *shader_path = PL_String (item); - if (!(*handle = QFV_CreateShaderModule (device, shader_path))) { - PL_Message (messages, item, "could not find shader %s", shader_path); - return 0; + const char *name = PL_String (item); + Sys_Printf ("parse_VkDescriptorSetLayout: %s\n", name); + name = va (ctx->va_ctx, "$properties.setLayouts.%s", name); + + handleref_t *hr = Hash_Find (ctx->setLayouts, name); + if (hr) { + *handle = (VkDescriptorSetLayout) hr->handle; + return 1; } - QFV_duSetObjectName (device, VK_OBJECT_TYPE_SHADER_MODULE, *handle, - va (ctx->va_ctx, "shader:%s", shader_path)); - return 1; + + plitem_t *setItem = 0; + exprval_t result = { &cexpr_plitem, &setItem }; + ectx.symtab = 0; + ectx.result = &result; + ret = !cexpr_eval_string (name, &ectx); + if (ret) { + VkDescriptorSetLayout setLayout; + setLayout = QFV_ParseDescriptorSetLayout (ctx, setItem); + *handle = (VkDescriptorSetLayout) setLayout; + + add_handle (ctx->setLayouts, name, (uint64_t) setLayout); + } + return ret; } static int -parse_VkDescriptorSetLayout_array (const plfield_t *field, - const plitem_t *item, void *data, - plitem_t *messages, void *context) +parse_VkPipelineLayout (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) { - void *layout[] = { data }; - return parse_VkDescriptorSetLayout (item, layout, messages, context); + __auto_type handle = (VkPipelineLayout *) data[0]; + int ret = 1; + exprctx_t ectx = *((parsectx_t *) context)->ectx; + vulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx; + + const char *name = PL_String (item); + Sys_Printf ("parse_VkPipelineLayout: %s\n", name); + name = va (ctx->va_ctx, "$properties.pipelineLayouts.%s", name); + + handleref_t *hr = Hash_Find (ctx->pipelineLayouts, name); + if (hr) { + *handle = (VkPipelineLayout) hr->handle; + return 1; + } + + plitem_t *setItem = 0; + exprval_t result = { &cexpr_plitem, &setItem }; + ectx.symtab = 0; + ectx.result = &result; + ret = !cexpr_eval_string (name, &ectx); + if (ret) { + VkPipelineLayout layout; + layout = QFV_ParsePipelineLayout (ctx, setItem); + *handle = (VkPipelineLayout) layout; + + add_handle (ctx->pipelineLayouts, name, (uint64_t) layout); + } + return ret; } static const char * @@ -600,54 +655,6 @@ handlref_symtab (void (*free_func)(void*,void*), vulkan_ctx_t *ctx) ctx, &ctx->hashlinks); } -void -QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *pipelinedef) -{ - plitem_t *messages = PL_NewArray (); - exprsym_t var_syms[] = { - {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, - {"framebuffers", &vulkan_framebufferset_t_type, &ctx->framebuffers}, - {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, - {} - }; - exprtab_t vars_tab = { var_syms, 0 }; - exprctx_t exprctx = {}; - parsectx_t parsectx = { &exprctx, ctx }; - int ret = 1; - - exprctx.memsuper = new_memsuper (); - exprctx.messages = messages; - exprctx.hashlinks = &ctx->hashlinks; - exprctx.external_variables = &vars_tab; - cexpr_init_symtab (&vars_tab, &exprctx); - - if (!ctx->setLayouts) { - ctx->shaderModules = handlref_symtab (shaderModule_free, ctx); - ctx->setLayouts = handlref_symtab (setLayout_free, ctx); - ctx->pipelineLayouts = handlref_symtab (pipelineLayout_free, ctx); - ctx->descriptorPools = handlref_symtab (descriptorPool_free, ctx); - ctx->samplers = handlref_symtab (sampler_free, ctx); - } - - for (parseres_t *res = parse_resources; res->name; res++) { - plitem_t *item = PL_ObjectForKey (pipelinedef, res->name); - if (item) { - __auto_type table = *(hashtab_t **) ((size_t) ctx + res->offset); - Sys_Printf ("found %s\n", res->name); - ret &= PL_ParseSymtab (res->field, item, table, messages, - &parsectx); - } - } - if (!ret || developer->int_val & SYS_VULKAN) { - for (int i = 0; i < PL_A_NumObjects (messages); i++) { - Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); - } - } - - PL_Free (messages); - delete_memsuper (exprctx.memsuper); -} - static const char * enum_symtab_getkey (const void *e, void *unused) { @@ -666,6 +673,14 @@ QFV_InitParse (vulkan_ctx_t *ctx) cexpr_init_symtab (&qfv_swapchain_t_symtab, &context); cexpr_init_symtab (&vulkan_framebufferset_t_symtab, &context); cexpr_init_symtab (&imageset_symtab, &context); + + if (!ctx->setLayouts) { + ctx->shaderModules = handlref_symtab (shaderModule_free, ctx); + ctx->setLayouts = handlref_symtab (setLayout_free, ctx); + ctx->pipelineLayouts = handlref_symtab (pipelineLayout_free, ctx); + ctx->descriptorPools = handlref_symtab (descriptorPool_free, ctx); + ctx->samplers = handlref_symtab (sampler_free, ctx); + } } exprenum_t * @@ -674,13 +689,79 @@ QFV_GetEnum (const char *name) return Hash_Find (enum_symtab, name); } +static int +parse_object (vulkan_ctx_t *ctx, plitem_t *plist, + plparser_t parser, void *object) +{ + plitem_t *messages = PL_NewArray (); + exprctx_t exprctx = {}; + parsectx_t parsectx = { &exprctx, ctx }; + exprsym_t var_syms[] = { + {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, + {"framebuffers", &vulkan_framebufferset_t_type, &ctx->framebuffers}, + {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, + {"properties", &cexpr_plitem, &ctx->pipelineDef}, + {} + }; + exprtab_t vars_tab = { var_syms, 0 }; + + exprctx.external_variables = &vars_tab; + exprctx.memsuper = new_memsuper (); + exprctx.messages = messages; + exprctx.hashlinks = &ctx->hashlinks; + + cexpr_init_symtab (&vars_tab, &exprctx); + + + if (!parser (0, plist, object, messages, &parsectx)) { + for (int i = 0; i < PL_A_NumObjects (messages); i++) { + Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); + } + return 0; + } + PL_Free (messages); + delete_memsuper (exprctx.memsuper); + + return 1; +} + +static int +parse_qfv_renderpass (const plfield_t *field, const plitem_t *item, void *data, + plitem_t *messages, void *context) +{ + return PL_ParseStruct (renderpass_fields, item, data, messages, context); +} + VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) { qfv_device_t *device = ctx->device; + qfv_renderpass_t renderpass_data = {}; - plitem_t *messages = PL_NewArray (); + + if (!parse_object (ctx, plist, parse_qfv_renderpass, &renderpass_data)) { + return 0; + } + VkRenderPass renderpass; + renderpass = QFV_CreateRenderPass (device, + renderpass_data.attachments, + renderpass_data.subpasses, + renderpass_data.dependencies); + + free (renderpass_data.attachments); + for (size_t i = 0; i < renderpass_data.subpasses->size; i++) { + free ((void *) renderpass_data.subpasses->a[i].pInputAttachments); + free ((void *) renderpass_data.subpasses->a[i].pColorAttachments); + free ((void *) renderpass_data.subpasses->a[i].pResolveAttachments); + free ((void *) renderpass_data.subpasses->a[i].pDepthStencilAttachment); + free ((void *) renderpass_data.subpasses->a[i].pPreserveAttachments); + } + free (renderpass_data.subpasses); + free (renderpass_data.dependencies); + return renderpass; + +/* plitem_t *messages = PL_NewArray (); exprsym_t var_syms[] = { {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, {"framebuffers", &vulkan_framebufferset_t_type, &ctx->framebuffers}, @@ -707,11 +788,6 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) PL_Free (messages); delete_memsuper (exprctx.memsuper); - renderpass = QFV_CreateRenderPass (device, - renderpass_data.attachments, - renderpass_data.subpasses, - renderpass_data.dependencies); - free (renderpass_data.attachments); for (size_t i = 0; i < renderpass_data.subpasses->size; i++) { free ((void *) renderpass_data.subpasses->a[i].pInputAttachments); @@ -722,7 +798,7 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) } free (renderpass_data.subpasses); free (renderpass_data.dependencies); - return renderpass; + return renderpass;*/ } VkPipeline @@ -730,34 +806,13 @@ QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist) { qfv_device_t *device = ctx->device; - plitem_t *messages = PL_NewArray (); - exprctx_t exprctx = {}; - parsectx_t parsectx = { &exprctx, ctx }; - exprsym_t var_syms[] = { - {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, - {} - }; - exprtab_t vars_tab = { var_syms, 0 }; - - exprctx.external_variables = &vars_tab; - exprctx.memsuper = new_memsuper (); - exprctx.messages = messages; - exprctx.hashlinks = &ctx->hashlinks; - - cexpr_init_symtab (&vars_tab, &exprctx); - __auto_type cInfo = QFV_AllocGraphicsPipelineCreateInfoSet (1, alloca); memset (&cInfo->a[0], 0, sizeof (cInfo->a[0])); - if (!parse_VkGraphicsPipelineCreateInfo (0, plist, &cInfo->a[0], - messages, &parsectx)) { - for (int i = 0; i < PL_A_NumObjects (messages); i++) { - Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); - } + if (!parse_object (ctx, plist, parse_VkGraphicsPipelineCreateInfo, + &cInfo->a[0])) { return 0; } - PL_Free (messages); - delete_memsuper (exprctx.memsuper); cInfo->a[0].renderPass = ctx->renderpass.renderpass; __auto_type plSet = QFV_CreateGraphicsPipelines (device, 0, cInfo); @@ -765,3 +820,77 @@ QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist) free (plSet); return pipeline; } + +VkDescriptorPool +QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + VkDescriptorPoolCreateInfo cInfo = {}; + + if (!parse_object (ctx, plist, parse_VkDescriptorPoolCreateInfo, &cInfo)) { + return 0; + } + + VkDescriptorPool pool; + dfunc->vkCreateDescriptorPool (device->dev, &cInfo, 0, &pool); + + return pool; +} + +VkDescriptorSetLayout +QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, plitem_t *plist) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + VkDescriptorSetLayoutCreateInfo cInfo = {}; + + if (!parse_object (ctx, plist, parse_VkDescriptorSetLayoutCreateInfo, + &cInfo)) { + return 0; + } + + VkDescriptorSetLayout setLayout; + dfunc->vkCreateDescriptorSetLayout (device->dev, &cInfo, 0, &setLayout); + + return setLayout; +} + +VkPipelineLayout +QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + VkPipelineLayoutCreateInfo cInfo = {}; + + if (!parse_object (ctx, plist, parse_VkPipelineLayoutCreateInfo, + &cInfo)) { + return 0; + } + + VkPipelineLayout layout; + dfunc->vkCreatePipelineLayout (device->dev, &cInfo, 0, &layout); + + return layout; +} + +VkSampler +QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + VkSamplerCreateInfo cInfo = {}; + + if (!parse_object (ctx, plist, parse_VkSamplerCreateInfo, &cInfo)) { + return 0; + } + + VkSampler sampler; + dfunc->vkCreateSampler (device->dev, &cInfo, 0, &sampler); + + return sampler; +} diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index 459c0f6a2..480c8bc99 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -24,18 +24,15 @@ typedef struct handleref_s { uint64_t handle; } handleref_t; -VkShaderModule QFV_GetShaderModule (vulkan_ctx_t *ctx, const char *name); -VkDescriptorPool QFV_GetDescriptorPool (vulkan_ctx_t *ctx, const char *name); -VkDescriptorSetLayout QFV_GetDescriptorSetLayout (vulkan_ctx_t *ctx, - const char *name); -VkPipelineLayout QFV_GetPipelineLayout (vulkan_ctx_t *ctx, const char *name); -VkSampler QFV_GetSampler (vulkan_ctx_t *ctx, const char *name); - -void QFV_ParseResources (vulkan_ctx_t *ctx, plitem_t *plist); void QFV_InitParse (vulkan_ctx_t *ctx); exprenum_t *QFV_GetEnum (const char *name); VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); VkPipeline QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist); +VkDescriptorPool QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist); +VkDescriptorSetLayout QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, + plitem_t *plist); +VkPipelineLayout QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist); +VkSampler QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist); #endif//__vkparse_h diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index edf68541e..c3a0bfdd9 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -21,70 +21,6 @@ VkDescriptorPoolCreateInfo, VkSamplerCreateInfo, ); - handles = { - VkShaderModule = { - symtab = shaderModules; - class = "shader module"; - custom = parse_VkShaderModule_resource; - }; - VkDescriptorPool = { - symtab = descriptorPools; - class = "descriptor pool"; - create = vkCreateDescriptorPool; - }; - VkDescriptorSetLayout = { - symtab = setLayouts; - class = "set layout"; - create = vkCreateDescriptorSetLayout; - }; - VkPipelineLayout = { - symtab = pipelineLayouts; - class = "pipeline layout"; - create = vkCreatePipelineLayout; - }; - VkSampler = { - symtab = samplers; - class = "sampler"; - create = vkCreateSampler; - }; - }; - resources = ( - { - name = shaderModules; - parse_type = QFString; - parser = parse_VkShaderModule_handleref; - type = handleref_t; - table = shaderModules; - }, - { - name = setLayouts; - parse_type = QFDictionary; - parser = parse_VkDescriptorSetLayout_handleref; - type = handleref_t; - table = setLayouts; - }, - { - name = pipelineLayouts; - parse_type = QFDictionary; - parser = parse_VkPipelineLayout_handleref; - type = handleref_t; - table = pipelineLayouts; - }, - { - name = descriptorPools; - parse_type = QFDictionary; - parser = parse_VkDescriptorPool_handleref; - type = handleref_t; - table = descriptorPools; - }, - { - name = samplers; - parse_type = QFDictionary; - parser = parse_VkSampler_handleref; - type = handleref_t; - table = samplers; - }, - ); parse = { VkSubpassDescription = { flags = auto; @@ -279,7 +215,7 @@ type = (array, { parse_type = (QFDictionary, QFString); type = VkDescriptorSetLayout; - parser = parse_VkDescriptorSetLayout_array; + parser = parse_VkDescriptorSetLayout; }); size = setLayoutCount; values = pSetLayouts; @@ -338,8 +274,7 @@ value = pDynamicState; }; layout = { - type = (custom, (QFDictionary, QFString), - parse_VkPipelineLayout); + type = (custom, QFString, parse_VkPipelineLayout); fields = (layout); }; basePipelineHandle = { diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 76f4ac7b5..ad42daed4 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -63,7 +63,6 @@ #include "r_internal.h" #include "vid_vulkan.h" -#include "vkparse.h" void Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx) @@ -259,12 +258,8 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) actx->frames.grow = 0; actx->pipeline = Vulkan_CreatePipeline (ctx, "alias"); - actx->layout = QFV_GetPipelineLayout (ctx, "alias.layout"); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, actx->layout, - va (ctx->va_ctx, "layout:%s", "alias.layout")); - actx->sampler = QFV_GetSampler (ctx, "alias.sampler"); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_SAMPLER, actx->sampler, - va (ctx->va_ctx, "sampler:%s", "alias.sampler")); + actx->layout = Vulkan_CreatePipelineLayout (ctx, "alias_layout"); + actx->sampler = Vulkan_CreateSampler (ctx, "alias_sampler"); /*__auto_type layouts = QFV_AllocDescriptorSetLayoutSet (2 * frames, alloca); for (size_t i = 0; i < layouts->size / 2; i++) { diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index a0dcd9134..5ae835897 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -68,7 +68,6 @@ #include "r_internal.h" #include "vid_vulkan.h" -#include "vkparse.h" static float identity[] = { 1, 0, 0, 0, @@ -1449,14 +1448,10 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) DARRAY_RESIZE (&bctx->frames, frames); bctx->frames.grow = 0; - bctx->main = Vulkan_CreatePipeline (ctx, "quakebsp.main"); - bctx->sky = Vulkan_CreatePipeline (ctx, "quakebsp.skysheet"); - bctx->layout = QFV_GetPipelineLayout (ctx, "quakebsp.layout"); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, bctx->layout, - va (ctx->va_ctx, "layout:%s", "quakebsp.layout")); - bctx->sampler = QFV_GetSampler (ctx, "quakebsp.sampler"); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_SAMPLER, bctx->sampler, - va (ctx->va_ctx, "sampler:%s", "quakebsp.sampler")); + bctx->main = Vulkan_CreatePipeline (ctx, "quakebsp_main"); + bctx->sky = Vulkan_CreatePipeline (ctx, "quakebsp_skysheet"); + bctx->layout = Vulkan_CreatePipelineLayout (ctx, "quakebsp_layout"); + bctx->sampler = Vulkan_CreateSampler (ctx, "quakebsp_sampler"); __auto_type cmdBuffers = QFV_AllocCommandBufferSet (3 * frames, alloca); QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 16b563600..ff7e6ed15 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -64,7 +64,6 @@ #include "r_internal.h" #include "vid_vulkan.h" -#include "vkparse.h" typedef struct { float xy[2]; @@ -371,7 +370,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) ctx->cmdpool); dctx->scrap = QFV_CreateScrap (device, "draw_atlas", 2048, tex_rgba, dctx->stage); - dctx->sampler = QFV_GetSampler (ctx, "quakepic"); + dctx->sampler = Vulkan_CreateSampler (ctx, "quakepic"); qpic_t *charspic = Draw_Font8x8Pic (); @@ -384,13 +383,13 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) dctx->pipeline = Vulkan_CreatePipeline (ctx, "twod"); - dctx->layout = QFV_GetPipelineLayout (ctx, "twod.layout"); + dctx->layout = Vulkan_CreatePipelineLayout (ctx, "twod_layout"); __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (frames, alloca); for (size_t i = 0; i < layouts->size; i++) { - layouts->a[i] = QFV_GetDescriptorSetLayout (ctx, "twod.set"); + layouts->a[i] = Vulkan_CreateDescriptorSetLayout (ctx, "twod_set"); } - __auto_type pool = QFV_GetDescriptorPool (ctx, "twod.pool"); + __auto_type pool = Vulkan_CreateDescriptorPool (ctx, "twod_pool"); VkDescriptorBufferInfo bufferInfo = { ctx->matrices.buffer_2d, 0, VK_WHOLE_SIZE diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index ff026331a..979d30a7c 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -224,21 +224,25 @@ Vulkan_CreateSwapchain (vulkan_ctx_t *ctx) } } -static void -qfv_load_pipeline (vulkan_ctx_t *ctx) +static plitem_t * +qfv_load_pipeline (vulkan_ctx_t *ctx, const char *name) { if (!ctx->pipelineDef) { ctx->pipelineDef = PL_GetPropertyList (quakeforge_pipeline); - if (ctx->pipelineDef) { - QFV_ParseResources (ctx, ctx->pipelineDef); - } } + + plitem_t *item = ctx->pipelineDef; + if (!item || !(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading %s\n", name); + } else { + Sys_Printf ("Found %s def\n", name); + } + return item; } void Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) { - qfv_load_pipeline (ctx); const char *name = "renderpass";//FIXME qfv_device_t *device = ctx->device; VkDevice dev = device->dev; @@ -249,15 +253,13 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) ctx->msaaSamples = min ((VkSampleCountFlagBits) msaaSamples->int_val, QFV_GetMaxSampleCount (device->physDev)); if (ctx->msaaSamples > 1) { - name = "renderpass.msaa"; + name = "renderpass_msaa"; } - plitem_t *item = ctx->pipelineDef; - if (!item || !(item = PL_ObjectForKey (item, name))) { - Sys_Printf ("error loading renderpass: %s\n", name); + //FIXME a tad inconsistent + plitem_t *item = qfv_load_pipeline (ctx, name); + if (!item) { return; - } else { - Sys_Printf ("Found renderpass def: %s\n", name); } qfv_imageresource_t *colorImage = malloc (sizeof (*colorImage)); @@ -375,15 +377,7 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) VkPipeline Vulkan_CreatePipeline (vulkan_ctx_t *ctx, const char *name) { - qfv_load_pipeline (ctx); - - plitem_t *item = ctx->pipelineDef; - if (!item || !(item = PL_ObjectForKey (item, "pipelines"))) { - Sys_Printf ("error loading pipelines\n"); - return 0; - } else { - Sys_Printf ("Found pipelines def\n"); - } + plitem_t *item = qfv_load_pipeline (ctx, "pipelines"); if (!(item = PL_ObjectForKey (item, name))) { Sys_Printf ("error loading pipeline %s\n", name); return 0; @@ -396,6 +390,70 @@ Vulkan_CreatePipeline (vulkan_ctx_t *ctx, const char *name) return pipeline; } +VkDescriptorPool +Vulkan_CreateDescriptorPool (vulkan_ctx_t *ctx, const char *name) +{ + plitem_t *item = qfv_load_pipeline (ctx, "descriptorPools"); + if (!(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading descriptor pool %s\n", name); + return 0; + } else { + Sys_Printf ("Found descriptor pool def %s\n", name); + } + VkDescriptorPool pool = QFV_ParseDescriptorPool (ctx, item); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_DESCRIPTOR_POOL, pool, + va (ctx->va_ctx, "descriptor_pool:%s", name)); + return pool; +} + +VkPipelineLayout +Vulkan_CreatePipelineLayout (vulkan_ctx_t *ctx, const char *name) +{ + plitem_t *item = qfv_load_pipeline (ctx, "pipelineLayouts"); + if (!(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading pipeline layout %s\n", name); + return 0; + } else { + Sys_Printf ("Found pipeline layout def %s\n", name); + } + VkPipelineLayout layout = QFV_ParsePipelineLayout (ctx, item); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, layout, + va (ctx->va_ctx, "pipeline_layout:%s", name)); + return layout; +} + +VkSampler +Vulkan_CreateSampler (vulkan_ctx_t *ctx, const char *name) +{ + plitem_t *item = qfv_load_pipeline (ctx, "samplers"); + if (!(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading sampler %s\n", name); + return 0; + } else { + Sys_Printf ("Found sampler def %s\n", name); + } + VkSampler sampler = QFV_ParseSampler (ctx, item); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_SAMPLER, sampler, + va (ctx->va_ctx, "sampler:%s", name)); + return sampler; +} + +VkDescriptorSetLayout +Vulkan_CreateDescriptorSetLayout(vulkan_ctx_t *ctx, const char *name) +{ + plitem_t *item = qfv_load_pipeline (ctx, "setLayouts"); + if (!(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading descriptor set %s\n", name); + return 0; + } else { + Sys_Printf ("Found descriptor set def %s\n", name); + } + VkDescriptorSetLayout set = QFV_ParseDescriptorSetLayout (ctx, item); + QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, + set, va (ctx->va_ctx, "descriptor_set:%s", name)); + return set; +} + void Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) { From a54de63feedcbd44962139153dca1345b1829b54 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 4 Feb 2021 20:40:28 +0900 Subject: [PATCH 331/435] [vulkan] Take care of the duplicate handles --- libs/video/renderer/vulkan/vkparse.c | 41 ++++++++++------- libs/video/renderer/vulkan/vkparse.h | 5 +++ .../video/renderer/vulkan/vulkan_vid_common.c | 44 +++++++++++++++++-- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 88c580506..aa6c88325 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -362,8 +362,18 @@ parse_RGBA (const plitem_t *item, void **data, return ret; } -static void -add_handle (hashtab_t *tab, const char *name, uint64_t handle) +uint64_t +QFV_GetHandle (hashtab_t *tab, const char *name) +{ + handleref_t *hr = Hash_Find (tab, name); + if (hr) { + return hr->handle; + } + return 0; +} + +void +QFV_AddHandle (hashtab_t *tab, const char *name, uint64_t handle) { handleref_t *hr = malloc (sizeof (handleref_t)); hr->name = strdup (name); @@ -380,16 +390,15 @@ parse_VkShaderModule (const plitem_t *item, void **data, qfv_device_t *device = ctx->device; const char *name = PL_String (item); - handleref_t *hr = Hash_Find (ctx->shaderModules, name); - if (hr) { - *handle = (VkShaderModule) hr->handle; + *handle = (VkShaderModule) QFV_GetHandle (ctx->shaderModules, name); + if (*handle) { return 1; } if (!(*handle = QFV_CreateShaderModule (device, name))) { PL_Message (messages, item, "could not find shader %s", name); return 0; } - add_handle (ctx->shaderModules, name, (uint64_t) *handle); + QFV_AddHandle (ctx->shaderModules, name, (uint64_t) *handle); return 1; } @@ -404,11 +413,10 @@ parse_VkDescriptorSetLayout (const plfield_t *field, const plitem_t *item, const char *name = PL_String (item); Sys_Printf ("parse_VkDescriptorSetLayout: %s\n", name); - name = va (ctx->va_ctx, "$properties.setLayouts.%s", name); + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".setLayouts.%s", name); - handleref_t *hr = Hash_Find (ctx->setLayouts, name); - if (hr) { - *handle = (VkDescriptorSetLayout) hr->handle; + *handle = (VkDescriptorSetLayout) QFV_GetHandle (ctx->setLayouts, name); + if (*handle) { return 1; } @@ -422,7 +430,7 @@ parse_VkDescriptorSetLayout (const plfield_t *field, const plitem_t *item, setLayout = QFV_ParseDescriptorSetLayout (ctx, setItem); *handle = (VkDescriptorSetLayout) setLayout; - add_handle (ctx->setLayouts, name, (uint64_t) setLayout); + QFV_AddHandle (ctx->setLayouts, name, (uint64_t) setLayout); } return ret; } @@ -438,11 +446,10 @@ parse_VkPipelineLayout (const plitem_t *item, void **data, const char *name = PL_String (item); Sys_Printf ("parse_VkPipelineLayout: %s\n", name); - name = va (ctx->va_ctx, "$properties.pipelineLayouts.%s", name); + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".pipelineLayouts.%s", name); - handleref_t *hr = Hash_Find (ctx->pipelineLayouts, name); - if (hr) { - *handle = (VkPipelineLayout) hr->handle; + *handle = (VkPipelineLayout) QFV_GetHandle (ctx->pipelineLayouts, name); + if (*handle) { return 1; } @@ -456,7 +463,7 @@ parse_VkPipelineLayout (const plitem_t *item, void **data, layout = QFV_ParsePipelineLayout (ctx, setItem); *handle = (VkPipelineLayout) layout; - add_handle (ctx->pipelineLayouts, name, (uint64_t) layout); + QFV_AddHandle (ctx->pipelineLayouts, name, (uint64_t) layout); } return ret; } @@ -700,7 +707,7 @@ parse_object (vulkan_ctx_t *ctx, plitem_t *plist, {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, {"framebuffers", &vulkan_framebufferset_t_type, &ctx->framebuffers}, {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, - {"properties", &cexpr_plitem, &ctx->pipelineDef}, + {QFV_PROPERTIES, &cexpr_plitem, &ctx->pipelineDef}, {} }; exprtab_t vars_tab = { var_syms, 0 }; diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index 480c8bc99..c443e98e3 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -13,6 +13,8 @@ typedef struct parsectx_s { #include "libs/video/renderer/vulkan/vkparse.hinc" #endif +#define QFV_PROPERTIES "properties" + typedef struct parseres_s { const char *name; plfield_t *field; @@ -27,6 +29,9 @@ typedef struct handleref_s { void QFV_InitParse (vulkan_ctx_t *ctx); exprenum_t *QFV_GetEnum (const char *name); +uint64_t QFV_GetHandle (struct hashtab_s *tab, const char *name); +void QFV_AddHandle (struct hashtab_s *tab, const char *name, uint64_t handle); + VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); VkPipeline QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist); VkDescriptorPool QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist); diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 979d30a7c..21c21b085 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -393,6 +393,14 @@ Vulkan_CreatePipeline (vulkan_ctx_t *ctx, const char *name) VkDescriptorPool Vulkan_CreateDescriptorPool (vulkan_ctx_t *ctx, const char *name) { + hashtab_t *tab = ctx->descriptorPools; + const char *path; + path = va (ctx->va_ctx, "$"QFV_PROPERTIES".descriptorPools.%s", name); + __auto_type pool = (VkDescriptorPool) QFV_GetHandle (tab, path); + if (pool) { + return pool; + } + plitem_t *item = qfv_load_pipeline (ctx, "descriptorPools"); if (!(item = PL_ObjectForKey (item, name))) { Sys_Printf ("error loading descriptor pool %s\n", name); @@ -400,7 +408,8 @@ Vulkan_CreateDescriptorPool (vulkan_ctx_t *ctx, const char *name) } else { Sys_Printf ("Found descriptor pool def %s\n", name); } - VkDescriptorPool pool = QFV_ParseDescriptorPool (ctx, item); + pool = QFV_ParseDescriptorPool (ctx, item); + QFV_AddHandle (tab, path, (uint64_t) pool); QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_DESCRIPTOR_POOL, pool, va (ctx->va_ctx, "descriptor_pool:%s", name)); return pool; @@ -409,6 +418,14 @@ Vulkan_CreateDescriptorPool (vulkan_ctx_t *ctx, const char *name) VkPipelineLayout Vulkan_CreatePipelineLayout (vulkan_ctx_t *ctx, const char *name) { + hashtab_t *tab = ctx->pipelineLayouts; + const char *path; + path = va (ctx->va_ctx, "$"QFV_PROPERTIES".pipelineLayouts.%s", name); + __auto_type layout = (VkPipelineLayout) QFV_GetHandle (tab, path); + if (layout) { + return layout; + } + plitem_t *item = qfv_load_pipeline (ctx, "pipelineLayouts"); if (!(item = PL_ObjectForKey (item, name))) { Sys_Printf ("error loading pipeline layout %s\n", name); @@ -416,7 +433,8 @@ Vulkan_CreatePipelineLayout (vulkan_ctx_t *ctx, const char *name) } else { Sys_Printf ("Found pipeline layout def %s\n", name); } - VkPipelineLayout layout = QFV_ParsePipelineLayout (ctx, item); + layout = QFV_ParsePipelineLayout (ctx, item); + QFV_AddHandle (tab, path, (uint64_t) layout); QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, layout, va (ctx->va_ctx, "pipeline_layout:%s", name)); return layout; @@ -425,6 +443,14 @@ Vulkan_CreatePipelineLayout (vulkan_ctx_t *ctx, const char *name) VkSampler Vulkan_CreateSampler (vulkan_ctx_t *ctx, const char *name) { + hashtab_t *tab = ctx->samplers; + const char *path; + path = va (ctx->va_ctx, "$"QFV_PROPERTIES".samplers.%s", name); + __auto_type sampler = (VkSampler) QFV_GetHandle (tab, path); + if (sampler) { + return sampler; + } + plitem_t *item = qfv_load_pipeline (ctx, "samplers"); if (!(item = PL_ObjectForKey (item, name))) { Sys_Printf ("error loading sampler %s\n", name); @@ -432,7 +458,8 @@ Vulkan_CreateSampler (vulkan_ctx_t *ctx, const char *name) } else { Sys_Printf ("Found sampler def %s\n", name); } - VkSampler sampler = QFV_ParseSampler (ctx, item); + sampler = QFV_ParseSampler (ctx, item); + QFV_AddHandle (tab, path, (uint64_t) sampler); QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_SAMPLER, sampler, va (ctx->va_ctx, "sampler:%s", name)); return sampler; @@ -441,6 +468,14 @@ Vulkan_CreateSampler (vulkan_ctx_t *ctx, const char *name) VkDescriptorSetLayout Vulkan_CreateDescriptorSetLayout(vulkan_ctx_t *ctx, const char *name) { + hashtab_t *tab = ctx->setLayouts; + const char *path; + path = va (ctx->va_ctx, "$"QFV_PROPERTIES".setLayouts.%s", name); + __auto_type set = (VkDescriptorSetLayout) QFV_GetHandle (tab, path); + if (set) { + return set; + } + plitem_t *item = qfv_load_pipeline (ctx, "setLayouts"); if (!(item = PL_ObjectForKey (item, name))) { Sys_Printf ("error loading descriptor set %s\n", name); @@ -448,7 +483,8 @@ Vulkan_CreateDescriptorSetLayout(vulkan_ctx_t *ctx, const char *name) } else { Sys_Printf ("Found descriptor set def %s\n", name); } - VkDescriptorSetLayout set = QFV_ParseDescriptorSetLayout (ctx, item); + set = QFV_ParseDescriptorSetLayout (ctx, item); + QFV_AddHandle (tab, path, (uint64_t) set); QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, set, va (ctx->va_ctx, "descriptor_set:%s", name)); return set; From e929dca3006b1b549994056386f1f32ac4bf5916 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 4 Feb 2021 22:37:20 +0900 Subject: [PATCH 332/435] [util] Auto-cast plist string items The casting uses a recursive call to the expression parser, so the expressions are type-checked automatically. --- include/QF/cexpr.h | 3 +++ libs/util/cexpr-type.c | 25 +++++++++++++++++++++++ libs/video/renderer/vulkan/vkgen/vkenum.r | 2 +- libs/video/renderer/vulkan/vkparse.c | 6 ++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index f511b6a9c..4e2dd3bcb 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -118,6 +118,9 @@ void cexpr_struct_pointer_getfield (const exprval_t *a, const exprval_t *b, exprval_t *cexpr_cvar (const char *name, exprctx_t *ctx); exprval_t *cexpr_cvar_struct (exprctx_t *ctx); +void cexpr_cast_plitem (const exprval_t *val1, const exprval_t *src, + exprval_t *result, exprctx_t *ctx); + void cexpr_init_symtab (exprtab_t *symtab, exprctx_t *ctx); char *cexpr_yyget_text (void *scanner); diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index c01e0cac0..1ba3b3f0f 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -100,6 +100,7 @@ binop_t int_binops[] = { { '^', &cexpr_int, &cexpr_int, int_xor }, { '%', &cexpr_int, &cexpr_int, int_rem }, { MOD, &cexpr_int, &cexpr_int, int_mod }, + { '=', &cexpr_plitem, &cexpr_int, cexpr_cast_plitem }, {} }; @@ -154,6 +155,7 @@ binop_t uint_binops[] = { { '%', &cexpr_uint, &cexpr_uint, uint_rem }, { MOD, &cexpr_uint, &cexpr_uint, uint_rem }, { '=', &cexpr_int, &cexpr_uint, uint_cast_int }, + { '=', &cexpr_plitem, &cexpr_uint, cexpr_cast_plitem }, {} }; @@ -222,6 +224,7 @@ binop_t size_t_binops[] = { { MOD, &cexpr_size_t, &cexpr_size_t, size_t_rem }, { '=', &cexpr_int, &cexpr_size_t, size_t_cast_int }, { '=', &cexpr_uint, &cexpr_size_t, size_t_cast_uint }, + { '=', &cexpr_plitem, &cexpr_size_t, cexpr_cast_plitem }, {} }; @@ -310,6 +313,7 @@ binop_t float_binops[] = { { '%', &cexpr_float, &cexpr_float, float_rem }, { MOD, &cexpr_float, &cexpr_float, float_mod }, { '=', &cexpr_int, &cexpr_float, float_cast_int }, + { '=', &cexpr_plitem, &cexpr_float, cexpr_cast_plitem }, {} }; @@ -366,6 +370,7 @@ binop_t double_binops[] = { { '/', &cexpr_double, &cexpr_double, double_div }, { '%', &cexpr_double, &cexpr_double, double_rem }, { MOD, &cexpr_double, &cexpr_double, double_mod }, + { '=', &cexpr_plitem, &cexpr_double, cexpr_cast_plitem }, {} }; @@ -595,6 +600,26 @@ exprtype_t cexpr_function = { 0, }; +void +cexpr_cast_plitem (const exprval_t *val1, const exprval_t *src, + exprval_t *result, exprctx_t *ctx) +{ + plitem_t *item = *(plitem_t **) src->value; + const char *str = PL_String (item); + if (!str) { + cexpr_error (ctx, "not a string object: %d", PL_Line (item)); + return; + } + + exprctx_t ectx = *ctx; + ectx.result = result; + cexpr_eval_string (str, &ectx); + ctx->errors += ectx.errors; + if (ectx.errors) { + cexpr_error (ctx, "could not convert: %d", PL_Line (item)); + } +} + static void plitem_field (const exprval_t *a, const exprval_t *b, exprval_t *c, exprctx_t *ctx) diff --git a/libs/video/renderer/vulkan/vkgen/vkenum.r b/libs/video/renderer/vulkan/vkgen/vkenum.r index 7c974f6fb..b4dc8b79f 100644 --- a/libs/video/renderer/vulkan/vkgen/vkenum.r +++ b/libs/video/renderer/vulkan/vkgen/vkenum.r @@ -79,7 +79,7 @@ skip_value(string name) fprintf (output_file, "\tflag_binops,\n"); fprintf (output_file, "\tflag_unops,\n"); } else { - fprintf (output_file, "\t0,\n"); + fprintf (output_file, "\tenum_binops,\n"); fprintf (output_file, "\t0,\n"); } fprintf (output_file, "};\n"); diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index aa6c88325..90e8d5d5e 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -103,6 +103,12 @@ binop_t flag_binops[] = { { '|', 0, 0, flag_or }, { '&', 0, 0, flag_and }, { '=', &cexpr_int, 0, flag_cast_int }, + { '=', &cexpr_plitem, 0, cexpr_cast_plitem }, + {} +}; + +binop_t enum_binops[] = { + { '=', &cexpr_plitem, 0, cexpr_cast_plitem }, {} }; From 7ffe197564c20d990741ce7b1234f78dc7442596 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 5 Feb 2021 10:19:57 +0900 Subject: [PATCH 333/435] [vulkan] Remove some dead code I forgot to delete that block of code after getting the new code working. --- libs/video/renderer/vulkan/vkparse.c | 39 ---------------------------- 1 file changed, 39 deletions(-) diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 90e8d5d5e..1155e3242 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -773,45 +773,6 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) free (renderpass_data.subpasses); free (renderpass_data.dependencies); return renderpass; - -/* plitem_t *messages = PL_NewArray (); - exprsym_t var_syms[] = { - {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, - {"framebuffers", &vulkan_framebufferset_t_type, &ctx->framebuffers}, - {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, - {} - }; - exprtab_t vars_tab = { var_syms, 0 }; - exprctx_t exprctx = {}; - parsectx_t parsectx = { &exprctx, ctx }; - - exprctx.memsuper = new_memsuper (); - exprctx.messages = messages; - exprctx.hashlinks = &ctx->hashlinks; - exprctx.external_variables = &vars_tab; - cexpr_init_symtab (&vars_tab, &exprctx); - - if (!PL_ParseStruct (renderpass_fields, plist, &renderpass_data, - messages, &parsectx)) { - for (int i = 0; i < PL_A_NumObjects (messages); i++) { - Sys_Printf ("%s\n", PL_String (PL_ObjectAtIndex (messages, i))); - } - return 0; - } - PL_Free (messages); - delete_memsuper (exprctx.memsuper); - - free (renderpass_data.attachments); - for (size_t i = 0; i < renderpass_data.subpasses->size; i++) { - free ((void *) renderpass_data.subpasses->a[i].pInputAttachments); - free ((void *) renderpass_data.subpasses->a[i].pColorAttachments); - free ((void *) renderpass_data.subpasses->a[i].pResolveAttachments); - free ((void *) renderpass_data.subpasses->a[i].pDepthStencilAttachment); - free ((void *) renderpass_data.subpasses->a[i].pPreserveAttachments); - } - free (renderpass_data.subpasses); - free (renderpass_data.dependencies); - return renderpass;*/ } VkPipeline From 1275067655b0f083be5a0d25a7c6608ec2889a16 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 5 Feb 2021 10:22:32 +0900 Subject: [PATCH 334/435] [vulkan] Rename vulkan_framebuffer_t It turns out I had conflated frame buffers with frames and wound up making a minor mess when separating the number of frames the renderer could have in flight from the number of swap-chain images. This is the first step towards correcting that mistake. --- include/vid_vulkan.h | 8 +-- libs/video/renderer/vid_render_vulkan.c | 49 +++++++++---------- libs/video/renderer/vulkan/qfpipeline.plist | 10 ++-- libs/video/renderer/vulkan/vkparse.c | 20 ++++---- libs/video/renderer/vulkan/vulkan_alias.c | 4 +- libs/video/renderer/vulkan/vulkan_bsp.c | 6 +-- libs/video/renderer/vulkan/vulkan_draw.c | 6 +-- .../video/renderer/vulkan/vulkan_vid_common.c | 20 ++++---- 8 files changed, 60 insertions(+), 63 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 38aa4b69f..4ddab99e3 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -22,7 +22,7 @@ typedef struct vulkan_framebuffer_s { VkCommandBuffer cmdBuffer; struct qfv_cmdbufferset_s *subCommand; -} vulkan_framebuffer_t; +} vulkan_frame_t; typedef struct vulkan_matrices_s { VkBuffer buffer_2d; @@ -34,8 +34,8 @@ typedef struct vulkan_matrices_s { float *sky_3d; } vulkan_matrices_t; -typedef struct vulkan_framebufferset_s - DARRAY_TYPE (vulkan_framebuffer_t) vulkan_framebufferset_t; +typedef struct vulkan_frameset_s + DARRAY_TYPE (vulkan_frame_t) vulkan_frameset_t; typedef struct vulkan_ctx_s { void (*load_vulkan) (struct vulkan_ctx_s *ctx); @@ -76,7 +76,7 @@ typedef struct vulkan_ctx_s { struct qfv_stagebuf_s *staging; VkPipeline pipeline; size_t curFrame; - vulkan_framebufferset_t framebuffers; + vulkan_frameset_t frames; struct qfv_tex_s *default_black; struct qfv_tex_s *default_white; diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index ebca7b9b0..92e68b0a2 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -124,15 +124,14 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) VkDevice dev = device->dev; qfv_queue_t *queue = &vulkan_ctx->device->queue; - __auto_type framebuffer - = &vulkan_ctx->framebuffers.a[vulkan_ctx->curFrame]; + __auto_type frame = &vulkan_ctx->frames.a[vulkan_ctx->curFrame]; - dfunc->vkWaitForFences (dev, 1, &framebuffer->fence, VK_TRUE, 2000000000); - if (framebuffer->framebuffer) { - dfunc->vkDestroyFramebuffer (dev, framebuffer->framebuffer, 0); + dfunc->vkWaitForFences (dev, 1, &frame->fence, VK_TRUE, 2000000000); + if (frame->framebuffer) { + dfunc->vkDestroyFramebuffer (dev, frame->framebuffer, 0); } QFV_AcquireNextImage (vulkan_ctx->swapchain, - framebuffer->imageAvailableSemaphore, + frame->imageAvailableSemaphore, 0, &imageIndex); int attachCount = vulkan_ctx->msaaSamples > 1 ? 3 : 2; @@ -146,9 +145,8 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) } VkRenderPass renderpass = vulkan_ctx->renderpass.renderpass; - framebuffer->framebuffer = QFV_CreateFramebuffer (device, renderpass, - attachments, - sc->extent, 1); + frame->framebuffer = QFV_CreateFramebuffer (device, renderpass, + attachments, sc->extent, 1); scr_3dfunc (); while (*scr_funcs) { @@ -172,41 +170,40 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) 3, clearValues }; - dfunc->vkBeginCommandBuffer (framebuffer->cmdBuffer, &beginInfo); - renderPassInfo.framebuffer = framebuffer->framebuffer; - dfunc->vkCmdBeginRenderPass (framebuffer->cmdBuffer, &renderPassInfo, - VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + dfunc->vkBeginCommandBuffer (frame->cmdBuffer, &beginInfo); + renderPassInfo.framebuffer = frame->framebuffer; + dfunc->vkCmdBeginRenderPass (frame->cmdBuffer, &renderPassInfo, + VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); - dfunc->vkCmdExecuteCommands (framebuffer->cmdBuffer, - framebuffer->subCommand->size, - framebuffer->subCommand->a); + dfunc->vkCmdExecuteCommands (frame->cmdBuffer, frame->subCommand->size, + frame->subCommand->a); // reset for next time around - framebuffer->subCommand->size = 0; + frame->subCommand->size = 0; - dfunc->vkCmdEndRenderPass (framebuffer->cmdBuffer); - dfunc->vkEndCommandBuffer (framebuffer->cmdBuffer); + dfunc->vkCmdEndRenderPass (frame->cmdBuffer); + dfunc->vkEndCommandBuffer (frame->cmdBuffer); VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, - 1, &framebuffer->imageAvailableSemaphore, &waitStage, - 1, &framebuffer->cmdBuffer, - 1, &framebuffer->renderDoneSemaphore, + 1, &frame->imageAvailableSemaphore, &waitStage, + 1, &frame->cmdBuffer, + 1, &frame->renderDoneSemaphore, }; - dfunc->vkResetFences (dev, 1, &framebuffer->fence); - dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, framebuffer->fence); + dfunc->vkResetFences (dev, 1, &frame->fence); + dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, frame->fence); VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, 0, - 1, &framebuffer->renderDoneSemaphore, + 1, &frame->renderDoneSemaphore, 1, &vulkan_ctx->swapchain->swapchain, &imageIndex, 0 }; dfunc->vkQueuePresentKHR (queue->queue, &presentInfo); vulkan_ctx->curFrame++; - vulkan_ctx->curFrame %= vulkan_ctx->framebuffers.size; + vulkan_ctx->curFrame %= vulkan_ctx->frames.size; if (++count >= 100) { double currenTime = Sys_DoubleTime (); diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 8ba2937c2..324e08e7c 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -55,25 +55,25 @@ descriptorPools = { twod_pool = { flags = 0; - maxSets = $framebuffers.size; + maxSets = $frames.size; bindings = ( { type = uniform_buffer; - descriptorCount = $framebuffers.size; + descriptorCount = $frames.size; }, { type = combined_image_sampler; - descriptorCount = $framebuffers.size; + descriptorCount = $frames.size; }, ); }; alias_pool = { flags = 0; - maxSets = "2z * $framebuffers.size"; + maxSets = "2z * $frames.size"; bindings = ( { type = uniform_buffer; - descriptorCount = "2z * $framebuffers.size"; + descriptorCount = "2z * $frames.size"; }, ); }; diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 1155e3242..7e336a167 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -606,19 +606,19 @@ exprtype_t qfv_swapchain_t_type = { &qfv_swapchain_t_symtab, }; -static exprsym_t vulkan_framebufferset_t_symbols[] = { - {"size", &cexpr_size_t, (void *)field_offset (vulkan_framebufferset_t, size)}, +static exprsym_t vulkan_frameset_t_symbols[] = { + {"size", &cexpr_size_t, (void *)field_offset (vulkan_frameset_t, size)}, { } }; -static exprtab_t vulkan_framebufferset_t_symtab = { - vulkan_framebufferset_t_symbols, +static exprtab_t vulkan_frameset_t_symtab = { + vulkan_frameset_t_symbols, }; -exprtype_t vulkan_framebufferset_t_type = { - "framebufferset", - sizeof (vulkan_framebufferset_t *), +exprtype_t vulkan_frameset_t_type = { + "frameset", + sizeof (vulkan_frameset_t *), cexpr_struct_binops, 0, - &vulkan_framebufferset_t_symtab, + &vulkan_frameset_t_symtab, }; typedef struct qfv_renderpass_s { @@ -684,7 +684,7 @@ QFV_InitParse (vulkan_ctx_t *ctx) context.hashlinks = &ctx->hashlinks; vkgen_init_symtabs (&context); cexpr_init_symtab (&qfv_swapchain_t_symtab, &context); - cexpr_init_symtab (&vulkan_framebufferset_t_symtab, &context); + cexpr_init_symtab (&vulkan_frameset_t_symtab, &context); cexpr_init_symtab (&imageset_symtab, &context); if (!ctx->setLayouts) { @@ -711,7 +711,7 @@ parse_object (vulkan_ctx_t *ctx, plitem_t *plist, parsectx_t parsectx = { &exprctx, ctx }; exprsym_t var_syms[] = { {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, - {"framebuffers", &vulkan_framebufferset_t_type, &ctx->framebuffers}, + {"frames", &vulkan_frameset_t_type, &ctx->frames}, {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, {QFV_PROPERTIES, &cexpr_plitem, &ctx->pipelineDef}, {} diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index ad42daed4..67598dc96 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -153,7 +153,7 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx) dlight_t *lights[ALIAS_LIGHTS]; //XXX quat_t fog; - __auto_type cframe = &ctx->framebuffers.a[ctx->curFrame]; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; VkCommandBuffer cmd = aframe->cmd; DARRAY_APPEND (cframe->subCommand, cmd); @@ -252,7 +252,7 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) aliasctx_t *actx = calloc (1, sizeof (aliasctx_t)); ctx->alias_context = actx; - size_t frames = ctx->framebuffers.size; + size_t frames = ctx->frames.size; DARRAY_INIT (&actx->frames, frames); DARRAY_RESIZE (&actx->frames, frames); actx->frames.grow = 0; diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 5ae835897..7028aa754 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -838,7 +838,7 @@ bsp_begin (vulkan_ctx_t *ctx) bctx->default_color[3] = 1; QuatCopy (bctx->default_color, bctx->last_color); - __auto_type cframe = &ctx->framebuffers.a[ctx->curFrame]; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; VkCommandBuffer cmd = bframe->bsp_cmd; DARRAY_APPEND (cframe->subCommand, cmd); @@ -991,7 +991,7 @@ sky_begin (vulkan_ctx_t *ctx) spin (ctx->matrices.sky_3d, bctx); - __auto_type cframe = &ctx->framebuffers.a[ctx->curFrame]; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; VkCommandBuffer cmd = bframe->sky_cmd; DARRAY_APPEND (cframe->subCommand, cmd); @@ -1443,7 +1443,7 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) DARRAY_INIT (&bctx->texture_chains, 64); - size_t frames = ctx->framebuffers.size; + size_t frames = ctx->frames.size; DARRAY_INIT (&bctx->frames, frames); DARRAY_RESIZE (&bctx->frames, frames); bctx->frames.grow = 0; diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index ff7e6ed15..249ff933e 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -120,7 +120,7 @@ create_quad_buffers (vulkan_ctx_t *ctx) size_t vert_size; size_t ind_size; - size_t frames = ctx->framebuffers.size; + size_t frames = ctx->frames.size; VkBuffer vbuf, ibuf; VkDeviceMemory vmem, imem; @@ -357,7 +357,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) drawctx_t *dctx = calloc (1, sizeof (drawctx_t)); ctx->draw_context = dctx; - size_t frames = ctx->framebuffers.size; + size_t frames = ctx->frames.size; DARRAY_INIT (&dctx->frames, frames); DARRAY_RESIZE (&dctx->frames, frames); dctx->frames.grow = 0; @@ -680,7 +680,7 @@ Vulkan_FlushText (vulkan_ctx_t *ctx) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - __auto_type cframe = &ctx->framebuffers.a[ctx->curFrame]; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; drawctx_t *dctx = ctx->draw_context; drawframe_t *dframe = &dctx->frames.a[ctx->curFrame]; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 21c21b085..54879cdbb 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -168,7 +168,7 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) if (ctx->pipeline) { QFV_DestroyPipeline (ctx->device, ctx->pipeline); } - if (ctx->framebuffers.size) { + if (ctx->frames.size) { Vulkan_DestroyFramebuffers (ctx); } if (ctx->renderpass.colorImage) { @@ -496,18 +496,18 @@ Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) qfv_device_t *device = ctx->device; VkCommandPool cmdpool = ctx->cmdpool; - if (!ctx->framebuffers.grow) { - DARRAY_INIT (&ctx->framebuffers, 4); + if (!ctx->frames.grow) { + DARRAY_INIT (&ctx->frames, 4); } - DARRAY_RESIZE (&ctx->framebuffers, 3);//FIXME cvar + DARRAY_RESIZE (&ctx->frames, 3);//FIXME cvar - __auto_type cmdBuffers = QFV_AllocCommandBufferSet (ctx->framebuffers.size, + __auto_type cmdBuffers = QFV_AllocCommandBufferSet (ctx->frames.size, alloca); QFV_AllocateCommandBuffers (device, cmdpool, 0, cmdBuffers); - for (size_t i = 0; i < ctx->framebuffers.size; i++) { - __auto_type frame = &ctx->framebuffers.a[i]; + for (size_t i = 0; i < ctx->frames.size; i++) { + __auto_type frame = &ctx->frames.a[i]; frame->framebuffer = 0; frame->fence = QFV_CreateFence (device, 1); frame->imageAvailableSemaphore = QFV_CreateSemaphore (device); @@ -526,13 +526,13 @@ Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx) qfv_devfuncs_t *df = device->funcs; VkDevice dev = device->dev; - for (size_t i = 0; i < ctx->framebuffers.size; i++) { - __auto_type frame = &ctx->framebuffers.a[i]; + for (size_t i = 0; i < ctx->frames.size; i++) { + __auto_type frame = &ctx->frames.a[i]; df->vkDestroyFence (dev, frame->fence, 0); df->vkDestroySemaphore (dev, frame->imageAvailableSemaphore, 0); df->vkDestroySemaphore (dev, frame->renderDoneSemaphore, 0); df->vkDestroyFramebuffer (dev, frame->framebuffer, 0); } - DARRAY_CLEAR (&ctx->framebuffers); + DARRAY_CLEAR (&ctx->frames); } From f633a846a123e2f9390e85bab53ee176dac0e9d5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 5 Feb 2021 11:06:18 +0900 Subject: [PATCH 335/435] [vulkan] Make the frames in flight configurable --- include/QF/Vulkan/cvars.h | 1 + libs/video/renderer/vulkan/vulkan_vid_common.c | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/QF/Vulkan/cvars.h b/include/QF/Vulkan/cvars.h index 706bc44de..54a34048b 100644 --- a/include/QF/Vulkan/cvars.h +++ b/include/QF/Vulkan/cvars.h @@ -3,5 +3,6 @@ extern struct cvar_s *vulkan_use_validation; extern struct cvar_s *vulkan_presentation_mode; +extern struct cvar_s *vulkan_frame_count; #endif//__QF_Vulkan_cvars_h diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 54879cdbb..4dcda5d86 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -78,6 +78,7 @@ static const char quakeforge_pipeline[] = #include "libs/video/renderer/vulkan/qfpipeline.plc" ; +cvar_t *vulkan_frame_count; cvar_t *vulkan_presentation_mode; cvar_t *msaaSamples; @@ -98,6 +99,15 @@ vulkan_presentation_mode_f (cvar_t *var) } } +static void +vulkan_frame_count_f (cvar_t *var) +{ + if (var->int_val < 1) { + Sys_Printf ("Invalid frame count: %d. Setting to 1\n", var->int_val); + Cvar_Set (var, "1"); + } +} + static void msaaSamples_f (cvar_t *var) { @@ -125,6 +135,12 @@ Vulkan_Init_Cvars (void) CVAR_NONE, vulkan_presentation_mode_f, "desired presentation mode (may fall " "back to fifo)."); + vulkan_frame_count = Cvar_Get ("vulkan_frame_count", "3", CVAR_NONE, + vulkan_frame_count_f, + "Number of frames to render in the" + " background. More frames can increase" + " performance, but at the cost of latency." + " The default of 3 is recommended."); msaaSamples = Cvar_Get ("msaaSamples", "VK_SAMPLE_COUNT_1_BIT", CVAR_NONE, msaaSamples_f, "desired MSAA sample size."); @@ -500,7 +516,7 @@ Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) DARRAY_INIT (&ctx->frames, 4); } - DARRAY_RESIZE (&ctx->frames, 3);//FIXME cvar + DARRAY_RESIZE (&ctx->frames, vulkan_frame_count->int_val); __auto_type cmdBuffers = QFV_AllocCommandBufferSet (ctx->frames.size, alloca); From c536a363ecd902634195ff702d7cb2907340e130 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 5 Feb 2021 11:10:43 +0900 Subject: [PATCH 336/435] [vulkan] Remove namehack.h Never really wanted in the first place (back when I did the plugin renderers), but I didn't feel like doing the required work to avoid it at the time. At least with Vulkan being a fresh start in an environment that's already plugin-friendly, there was no real work involved. I'll get to the other renderers eventually (especially now that I know gdb does the right thing when there are multiple functions with the same name). --- libs/video/renderer/vid_render_vulkan.c | 5 - libs/video/renderer/vulkan/namehack.h | 135 ------------------- libs/video/renderer/vulkan/vulkan_draw.c | 3 - libs/video/renderer/vulkan/vulkan_lightmap.c | 3 - libs/video/renderer/vulkan/vulkan_main.c | 3 - 5 files changed, 149 deletions(-) delete mode 100644 libs/video/renderer/vulkan/namehack.h diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 92e68b0a2..a41a1d960 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -30,9 +30,6 @@ #include -//#define NH_DEFINE -//#include "vulkan/namehack.h" - #include "QF/darray.h" #include "QF/sys.h" @@ -59,8 +56,6 @@ #include "vid_internal.h" #include "vid_vulkan.h" -#include "vulkan/namehack.h" - static vulkan_ctx_t *vulkan_ctx; static tex_t * diff --git a/libs/video/renderer/vulkan/namehack.h b/libs/video/renderer/vulkan/namehack.h deleted file mode 100644 index 17f107080..000000000 --- a/libs/video/renderer/vulkan/namehack.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifdef NH_DEFINE -#undef NH_DEFINE -#define Draw_Init vulkan_Draw_Init -#define Draw_Character vulkan_Draw_Character -#define Draw_String vulkan_Draw_String -#define Draw_nString vulkan_Draw_nString -#define Draw_AltString vulkan_Draw_AltString -#define Draw_ConsoleBackground vulkan_Draw_ConsoleBackground -#define Draw_Crosshair vulkan_Draw_Crosshair -#define Draw_CrosshairAt vulkan_Draw_CrosshairAt -#define Draw_TileClear vulkan_Draw_TileClear -#define Draw_Fill vulkan_Draw_Fill -#define Draw_TextBox vulkan_Draw_TextBox -#define Draw_FadeScreen vulkan_Draw_FadeScreen -#define Draw_BlendScreen vulkan_Draw_BlendScreen -#define Draw_CachePic vulkan_Draw_CachePic -#define Draw_UncachePic vulkan_Draw_UncachePic -#define Draw_MakePic vulkan_Draw_MakePic -#define Draw_DestroyPic vulkan_Draw_DestroyPic -#define Draw_PicFromWad vulkan_Draw_PicFromWad -#define Draw_Pic vulkan_Draw_Pic -#define Draw_Picf vulkan_Draw_Picf -#define Draw_SubPic vulkan_Draw_SubPic -#define Fog_DisableGFog vulkan_Fog_DisableGFog -#define Fog_EnableGFog vulkan_Fog_EnableGFog -#define Fog_GetColor vulkan_Fog_GetColor -#define Fog_GetDensity vulkan_Fog_GetDensity -#define Fog_Init vulkan_Fog_Init -#define Fog_ParseWorldspawn vulkan_Fog_ParseWorldspawn -#define Fog_SetupFrame vulkan_Fog_SetupFrame -#define Fog_StartAdditive vulkan_Fog_StartAdditive -#define Fog_StopAdditive vulkan_Fog_StopAdditive -#define Fog_Update vulkan_Fog_Update -#define R_AddTexture vulkan_R_AddTexture -#define R_BlendLightmaps vulkan_R_BlendLightmaps -#define R_BuildLightMap vulkan_R_BuildLightMap -#define R_CalcLightmaps vulkan_R_CalcLightmaps -#define R_ClearParticles vulkan_R_ClearParticles -#define R_ClearState vulkan_R_ClearState -#define R_ClearTextures vulkan_R_ClearTextures -#define R_DrawAliasModel vulkan_R_DrawAliasModel -#define R_DrawBrushModel vulkan_R_DrawBrushModel -#define R_DrawParticles vulkan_R_DrawParticles -#define R_DrawSky vulkan_R_DrawSky -#define R_DrawSkyChain vulkan_R_DrawSkyChain -#define R_DrawSprite vulkan_R_DrawSprite -#define R_DrawSpriteModel vulkan_R_DrawSpriteModel -#define R_DrawWaterSurfaces vulkan_R_DrawWaterSurfaces -#define R_DrawWorld vulkan_R_DrawWorld -#define R_InitBubble vulkan_R_InitBubble -#define R_InitGraphTextures vulkan_R_InitGraphTextures -#define R_InitParticles vulkan_R_InitParticles -#define R_InitSky vulkan_R_InitSky -#define R_InitSprites vulkan_R_InitSprites -#define R_InitSurfaceChains vulkan_R_InitSurfaceChains -#define R_LineGraph vulkan_R_LineGraph -#define R_LoadSky_f vulkan_R_LoadSky_f -#define R_LoadSkys vulkan_R_LoadSkys -#define R_NewMap vulkan_R_NewMap -#define R_Particle_New vulkan_R_Particle_New -#define R_Particle_NewRandom vulkan_R_Particle_NewRandom -#define R_Particles_Init_Cvars vulkan_R_Particles_Init_Cvars -#define R_ReadPointFile_f vulkan_R_ReadPointFile_f -#define R_RenderDlights vulkan_R_RenderDlights -#define R_RenderView vulkan_R_RenderView -#define R_RotateForEntity vulkan_R_RotateForEntity -#define R_SetupFrame vulkan_R_SetupFrame -#define R_SpriteBegin vulkan_R_SpriteBegin -#define R_SpriteEnd vulkan_R_SpriteEnd -#define R_TimeRefresh_f vulkan_R_TimeRefresh_f -#define R_ViewChanged vulkan_R_ViewChanged -#define SCR_CaptureBGR vulkan_SCR_CaptureBGR -#define SCR_ScreenShot vulkan_SCR_ScreenShot -#define SCR_ScreenShot_f vulkan_SCR_ScreenShot_f -#define c_alias_polys vulkan_c_alias_polys -#define c_brush_polys vulkan_c_brush_polys -#define r_easter_eggs_f vulkan_r_easter_eggs_f -#define r_particles_style_f vulkan_r_particles_style_f -#define r_world_matrix vulkan_r_world_matrix -#else -#undef Fog_DisableGFog -#undef Fog_EnableGFog -#undef Fog_GetColor -#undef Fog_GetDensity -#undef Fog_Init -#undef Fog_ParseWorldspawn -#undef Fog_SetupFrame -#undef Fog_StartAdditive -#undef Fog_StopAdditive -#undef Fog_Update -#undef R_AddTexture -#undef R_BlendLightmaps -#undef R_BuildLightMap -#undef R_CalcLightmaps -#undef R_ClearParticles -#undef R_ClearState -#undef R_ClearTextures -#undef R_DrawAliasModel -#undef R_DrawBrushModel -#undef R_DrawParticles -#undef R_DrawSky -#undef R_DrawSkyChain -#undef R_DrawSpriteModel -#undef R_DrawWaterSurfaces -#undef R_DrawWorld -#undef R_Init -#undef R_InitBubble -#undef R_InitGraphTextures -#undef R_InitParticles -#undef R_InitSky -#undef R_InitSprites -#undef R_InitSurfaceChains -#undef R_LineGraph -#undef R_LoadSky_f -#undef R_LoadSkys -#undef R_NewMap -#undef R_Particle_New -#undef R_Particle_NewRandom -#undef R_Particles_Init_Cvars -#undef R_ReadPointFile_f -#undef R_RenderDlights -#undef R_RenderView -#undef R_RotateForEntity -#undef R_SetupFrame -#undef R_TimeRefresh_f -#undef R_ViewChanged -#undef SCR_CaptureBGR -#undef SCR_ScreenShot -#undef SCR_ScreenShot_f -#undef c_alias_polys -#undef c_brush_polys -#undef r_easter_eggs_f -#undef r_particles_style_f -#undef r_world_matrix -#endif diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 249ff933e..b03cb9e38 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -31,9 +31,6 @@ # include "config.h" #endif -#define NH_DEFINE -#include "namehack.h" - #ifdef HAVE_STRING_H # include #endif diff --git a/libs/video/renderer/vulkan/vulkan_lightmap.c b/libs/video/renderer/vulkan/vulkan_lightmap.c index ca5d433e8..97c30c667 100644 --- a/libs/video/renderer/vulkan/vulkan_lightmap.c +++ b/libs/video/renderer/vulkan/vulkan_lightmap.c @@ -30,9 +30,6 @@ # include "config.h" #endif -#define NH_DEFINE -#include "namehack.h" - #ifdef HAVE_STRING_H # include #endif diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index 8df89eaa1..b4bdc8872 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -31,9 +31,6 @@ # include "config.h" #endif -#define NH_DEFINE -#include "namehack.h" - #ifdef HAVE_STRING_H # include "string.h" #endif From f023675f8c205d78c0de6202edf0a8a483406f52 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 5 Feb 2021 16:25:08 +0900 Subject: [PATCH 337/435] [vulkan] Clean up draw's memory handling a little Use cmem for pic and cachpic name allocations. If nothing else, it at least keeps memory a little less fragmented. --- libs/video/renderer/vulkan/vulkan_draw.c | 44 ++++++++++++++++-------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index b03cb9e38..93b73d7b3 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -38,6 +38,7 @@ # include #endif +#include "QF/cmem.h" #include "QF/cvar.h" #include "QF/draw.h" #include "QF/dstring.h" @@ -69,7 +70,6 @@ typedef struct { } drawvert_t; typedef struct cachepic_s { - struct cachepic_s *next; char *name; qpic_t *pic; } cachepic_t; @@ -92,6 +92,11 @@ typedef struct drawctx_s { qpic_t *conchars; qpic_t *conback; qpic_t *white_pic; + // use two separate cmem blocks for pics and strings (cachepic names) + // to ensure the names are never in the same cacheline as a pic since the + // names are used only for lookup + memsuper_t *pic_memsuper; + memsuper_t *string_memsuper; hashtab_t *pic_cache; VkBuffer vert_buffer; VkDeviceMemory vert_memory; @@ -211,32 +216,34 @@ flush_draw_scrap (vulkan_ctx_t *ctx) } static void -pic_free (qpic_t *pic) +pic_free (drawctx_t *dctx, qpic_t *pic) { subpic_t *subpic = *(subpic_t **) pic->data; QFV_SubpicDelete (subpic); - free (pic); + cmemfree (dctx->pic_memsuper, pic); } -//FIXME use cmem? static cachepic_t * -new_cachepic (const char *name, qpic_t *pic) +new_cachepic (drawctx_t *dctx, const char *name, qpic_t *pic) { cachepic_t *cp; + size_t size = strlen (name) + 1; - cp = malloc (sizeof (cachepic_t)); - cp->name = strdup (name); + cp = cmemalloc (dctx->pic_memsuper, sizeof (cachepic_t)); + cp->name = cmemalloc (dctx->string_memsuper, size); + memcpy (cp->name, name, size); cp->pic = pic; return cp; } static void -cachepic_free (void *_cp, void *unused) +cachepic_free (void *_cp, void *_dctx) { + drawctx_t *dctx = _dctx; cachepic_t *cp = (cachepic_t *) _cp; - pic_free (cp->pic); - free (cp->name); - free (cp); + pic_free (dctx, cp->pic); + cmemfree (dctx->string_memsuper, cp->name); + cmemfree (dctx->pic_memsuper, cp); } static const char * @@ -252,7 +259,8 @@ pic_data (const char *name, int w, int h, const byte *data, drawctx_t *dctx) subpic_t *subpic; byte *picdata; - pic = malloc (field_offset (qpic_t, data[sizeof (subpic_t)])); + pic = cmemalloc (dctx->pic_memsuper, + field_offset (qpic_t, data[sizeof (subpic_t *)])); pic->width = w; pic->height = h; @@ -292,7 +300,8 @@ Vulkan_Draw_PicFromWad (const char *name, vulkan_ctx_t *ctx) if (!wadpic) { return 0; } - return pic_data (name, wadpic->width, wadpic->height, wadpic->data, ctx->draw_context); + return pic_data (name, wadpic->width, wadpic->height, wadpic->data, + ctx->draw_context); } qpic_t * @@ -313,7 +322,7 @@ Vulkan_Draw_CachePic (const char *path, qboolean alpha, vulkan_ctx_t *ctx) pic = pic_data (path, p->width, p->height, p->data, dctx); free (p); - cpic = new_cachepic (path, pic); + cpic = new_cachepic (dctx, path, pic); Hash_Add (dctx->pic_cache, cpic); return pic; } @@ -341,6 +350,9 @@ Vulkan_Draw_Shutdown (vulkan_ctx_t *ctx) destroy_quad_buffers (ctx); dfunc->vkDestroyPipeline (device->dev, dctx->pipeline, 0); + Hash_DelTable (dctx->pic_cache); + delete_memsuper (dctx->pic_memsuper); + delete_memsuper (dctx->string_memsuper); QFV_DestroyScrap (dctx->scrap); QFV_DestroyStagingBuffer (dctx->stage); } @@ -359,8 +371,10 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) DARRAY_RESIZE (&dctx->frames, frames); dctx->frames.grow = 0; + dctx->pic_memsuper = new_memsuper (); + dctx->string_memsuper = new_memsuper (); dctx->pic_cache = Hash_NewTable (127, cachepic_getkey, cachepic_free, - 0, 0); + dctx, 0); create_quad_buffers (ctx); dctx->stage = QFV_CreateStagingBuffer (device, "draw", 4 * 1024 * 1024, From 84dc73da2c0cad9e469610aac169d4120cd44bb6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 5 Feb 2021 21:42:35 +0900 Subject: [PATCH 338/435] [test] Get the tests building again They happen to all pass, which is nice :) --- libs/models/test/testclip.c | 5 +++-- libs/models/test/testcontents.c | 4 ++-- libs/models/test/testportals.c | 4 ++-- libs/video/renderer/vulkan/staging.c | 2 +- libs/video/renderer/vulkan/test/test-staging.c | 2 +- tools/qfcc/test/test-harness.c | 4 ++-- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/libs/models/test/testclip.c b/libs/models/test/testclip.c index 6b6672e4b..f0f774c1e 100644 --- a/libs/models/test/testclip.c +++ b/libs/models/test/testclip.c @@ -6,6 +6,7 @@ #include "QF/va.h" #include "getopt.h" +#include "mod_internal.h" #include "world.h" #include "hulls.h" @@ -323,9 +324,9 @@ run_test (test_t *test) err = 1; if (test->desc) - desc = va ("(%d) %s", (int)(long)(test - tests), test->desc); + desc = va (0, "(%d) %s", (int)(long)(test - tests), test->desc); else - desc = va ("test #%d", (int)(long)(test - tests)); + desc = va (0, "test #%d", (int)(long)(test - tests)); if (verbose >= 0 || err) { if (output) puts(""); diff --git a/libs/models/test/testcontents.c b/libs/models/test/testcontents.c index 605ed7a6c..17b20f3ae 100644 --- a/libs/models/test/testcontents.c +++ b/libs/models/test/testcontents.c @@ -145,9 +145,9 @@ run_test (test_t *test) res = 1; if (test->desc) - desc = va ("(%d) %s", (int)(long)(test - tests), test->desc); + desc = va (0, "(%d) %s", (int)(long)(test - tests), test->desc); else - desc = va ("test #%d", (int)(long)(test - tests)); + desc = va (0, "test #%d", (int)(long)(test - tests)); if (verbose >= 0 || !res) { if (output) puts(""); diff --git a/libs/models/test/testportals.c b/libs/models/test/testportals.c index 1cc2f50ec..facfa2914 100644 --- a/libs/models/test/testportals.c +++ b/libs/models/test/testportals.c @@ -170,9 +170,9 @@ nodeleaf_bail: MOD_FreeBrushes (test->hull); if (test->desc) - desc = va ("(%d) %s", (int)(long)(test - tests), test->desc); + desc = va (0, "(%d) %s", (int)(long)(test - tests), test->desc); else - desc = va ("test #%d", (int)(long)(test - tests)); + desc = va (0, "test #%d", (int)(long)(test - tests)); if (verbose >= 0 || err) { if (output) puts(""); diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c index cb3bb8ad0..759962c4d 100644 --- a/libs/video/renderer/vulkan/staging.c +++ b/libs/video/renderer/vulkan/staging.c @@ -56,7 +56,7 @@ #include "vid_vulkan.h" qfv_stagebuf_t * -QFV_CreateStagingBuffer (qfv_device_t *device, const char * name, size_t size, +QFV_CreateStagingBuffer (qfv_device_t *device, const char *name, size_t size, VkCommandPool cmdPool) { size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; diff --git a/libs/video/renderer/vulkan/test/test-staging.c b/libs/video/renderer/vulkan/test/test-staging.c index 020af9ab2..fcfa4b8a9 100644 --- a/libs/video/renderer/vulkan/test/test-staging.c +++ b/libs/video/renderer/vulkan/test/test-staging.c @@ -179,7 +179,7 @@ _error (int line, const char *fmt, ...) int main (void) { - qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (&device, 1024, 0); + qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (&device, "", 1024, 0); if (stage->size != 1024) { error ("stage has incorrect size: %zd", stage->size); diff --git a/tools/qfcc/test/test-harness.c b/tools/qfcc/test/test-harness.c index 69de8c47b..822df9f41 100644 --- a/tools/qfcc/test/test-harness.c +++ b/tools/qfcc/test/test-harness.c @@ -104,7 +104,7 @@ load_file (progs_t *pr, const char *name, off_t *_size) file = open_file (name, &size); if (!file) { - file = open_file (va ("%s.gz", name), &size); + file = open_file (va (0, "%s.gz", name), &size); if (!file) { return 0; } @@ -132,7 +132,7 @@ static void init_qf (void) { Sys_Init (); - Cvar_Get ("developer", va ("%d", options.developer), 0, 0, 0); + Cvar_Get ("developer", va (0, "%d", options.developer), 0, 0, 0); Memory_Init (Sys_Alloc (1024 * 1024), 1024 * 1024); From dfa7af03c6d4b96c3e2339bf23a695f5d97203cb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Feb 2021 09:57:07 +0900 Subject: [PATCH 339/435] [util] Plug a thread-safety hole in plists --- include/QF/progs.h | 4 +++- include/QF/qfplist.h | 11 +++++++++-- libs/audio/cd_file.c | 2 +- libs/gamecode/pr_parse.c | 12 ++++++------ libs/ruamoko/rua_plist.c | 7 ++++--- libs/util/qfplist.c | 12 +++++++----- libs/util/quakefs.c | 4 ++-- libs/video/renderer/vulkan/vulkan_vid_common.c | 3 ++- nq/source/host_cmd.c | 8 ++++---- tools/qflight/source/entities.c | 4 ++-- tools/qflight/source/properties.c | 2 +- 11 files changed, 41 insertions(+), 28 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 64a9d20bb..89fa5d181 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -298,13 +298,15 @@ void ED_PrintNum (progs_t *pr, pr_int_t ent); // pr_parse.c struct script_s; struct plitem_s; +struct hashlink_s; qboolean ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s); struct plitem_s *ED_EntityDict (progs_t *pr, edict_t *ed); struct plitem_s *ED_GlobalsDict (progs_t *pr); void ED_InitGlobals (progs_t *pr, struct plitem_s *globals); void ED_InitEntity (progs_t *pr, struct plitem_s *entity, edict_t *ent); -struct plitem_s *ED_ConvertToPlist (struct script_s *script, int nohack); +struct plitem_s *ED_ConvertToPlist (struct script_s *script, int nohack, + struct hashlink_s **hashlinks); struct plitem_s *ED_Parse (progs_t *pr, const char *data); void ED_LoadFromFile (progs_t *pr, const char *data); void ED_EntityParseFunction (progs_t *pr); diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 8f8db669f..5de86d05f 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -28,6 +28,8 @@ #ifndef __QF_qfplist_h #define __QF_qfplist_h +struct hashlink_s; + /** \defgroup qfplist Property lists \ingroup utils */ @@ -115,11 +117,14 @@ typedef struct plelement_s { /** Create an in-memory representation of the contents of a property list. \param string the saved plist, as read from a file. + \param hashlinks Hashlink chain to use when creating dictionaries (see + Hash_NewTable()). May be null. \return Returns an object equivalent to the passed-in string. \note You are responsible for freeing the returned object. */ -plitem_t *PL_GetPropertyList (const char *string); +plitem_t *PL_GetPropertyList (const char *string, + struct hashlink_s **hashlinks); /** Create a property list string from the in-memory representation. @@ -275,9 +280,11 @@ plitem_t *PL_RemoveObjectAtIndex (plitem_t *array, int index); /** Create a new dictionary object. The dictionary will be empty. + \param hashlinks Hashlink chain to use when creating dictionaries (see + Hash_NewTable()). May be null. \return the new dictionary object */ -plitem_t *PL_NewDictionary (void); +plitem_t *PL_NewDictionary (struct hashlink_s **hashlinks); /** Create a new array object. The array will be empty. diff --git a/libs/audio/cd_file.c b/libs/audio/cd_file.c index ef9979bd9..5ffe88290 100644 --- a/libs/audio/cd_file.c +++ b/libs/audio/cd_file.c @@ -172,7 +172,7 @@ Load_Tracklist (void) buffile = calloc (size+10, sizeof (char)); Qread (oggfile, buffile, size); - tracklist = PL_GetPropertyList (buffile); + tracklist = PL_GetPropertyList (buffile, 0); if (!tracklist || PL_Type (tracklist) != QFDictionary) { Sys_Printf ("Malformed or empty tracklist file. check mus_ogglist\n"); return -1; diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index 6471a44bb..0f0a3dea5 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -109,7 +109,7 @@ VISIBLE plitem_t * ED_EntityDict (progs_t *pr, edict_t *ed) { dstring_t *dstr = dstring_newstr (); - plitem_t *entity = PL_NewDictionary (); + plitem_t *entity = PL_NewDictionary (pr->hashlink_freelist); pr_uint_t i; int j; int type; @@ -155,7 +155,7 @@ VISIBLE plitem_t * ED_GlobalsDict (progs_t *pr) { dstring_t *dstr = dstring_newstr (); - plitem_t *globals = PL_NewDictionary (); + plitem_t *globals = PL_NewDictionary (pr->hashlink_freelist); pr_uint_t i; const char *name; const char *value; @@ -290,7 +290,7 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s) */ VISIBLE plitem_t * -ED_ConvertToPlist (script_t *script, int nohack) +ED_ConvertToPlist (script_t *script, int nohack, struct hashlink_s **hashlinks) { dstring_t *dstr = dstring_newstr (); plitem_t *plist = PL_NewArray (); @@ -304,7 +304,7 @@ ED_ConvertToPlist (script_t *script, int nohack) token = script->token->str; if (!strequal (token, "{")) Sys_Error ("ED_ConvertToPlist: EOF without closing brace"); - ent = PL_NewDictionary (); + ent = PL_NewDictionary (hashlinks); while (1) { int n; @@ -499,11 +499,11 @@ ED_Parse (progs_t *pr, const char *data) if (Script_GetToken (script, 1)) { if (strequal (script->token->str, "(")) { // new style (plist) entity data - entity_list = PL_GetPropertyList (data); + entity_list = PL_GetPropertyList (data, pr->hashlink_freelist); } else { // oldstyle entity data Script_UngetToken (script); - entity_list = ED_ConvertToPlist (script, 0); + entity_list = ED_ConvertToPlist (script, 0, pr->hashlink_freelist); } } Script_Delete (script); diff --git a/libs/ruamoko/rua_plist.c b/libs/ruamoko/rua_plist.c index d45ee1b8d..ce5030e5c 100644 --- a/libs/ruamoko/rua_plist.c +++ b/libs/ruamoko/rua_plist.c @@ -195,7 +195,7 @@ bi_PL_GetFromFile (progs_t *pr) Qread (file, buf, len); buf[len] = 0; - plitem = PL_GetPropertyList (buf); + plitem = PL_GetPropertyList (buf, pr->hashlink_freelist); R_INT (pr) = plist_retain (res, plitem); } @@ -204,7 +204,8 @@ static void bi_PL_GetPropertyList (progs_t *pr) { plist_resources_t *res = PR_Resources_Find (pr, "plist"); - plitem_t *plitem = PL_GetPropertyList (P_GSTRING (pr, 0)); + plitem_t *plitem = PL_GetPropertyList (P_GSTRING (pr, 0), + pr->hashlink_freelist); R_INT (pr) = plist_retain (res, plitem); } @@ -373,7 +374,7 @@ static void bi_PL_NewDictionary (progs_t *pr) { plist_resources_t *res = PR_Resources_Find (pr, "plist"); - plitem_t *plitem = PL_NewDictionary (); + plitem_t *plitem = PL_NewDictionary (pr->hashlink_freelist); R_INT (pr) = plist_retain (res, plitem); } diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index f36b6552e..9d4a7b2bf 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -91,6 +91,7 @@ typedef struct pldata_s { // Unparsed property list string unsigned line; plitem_t *error; va_ctx_t *va_ctx; + hashlink_t **hashlinks; } pldata_t; // Ugly defines for fast checking and conversion from char to number @@ -157,11 +158,11 @@ PL_NewItem (pltype_t type) } VISIBLE plitem_t * -PL_NewDictionary (void) +PL_NewDictionary (hashlink_t **hashlinks) { plitem_t *item = PL_NewItem (QFDictionary); - //FIXME need a per-thread hashlink freelist for plist to be thread-safe - hashtab_t *dict = Hash_NewTable (1021, dict_get_key, dict_free, NULL, 0); + hashtab_t *dict = Hash_NewTable (1021, dict_get_key, dict_free, NULL, + hashlinks); item->data = dict; return item; } @@ -722,7 +723,7 @@ PL_ParsePropertyListItem (pldata_t *pl) switch (pl->ptr[pl->pos]) { case '{': { - item = PL_NewDictionary (); + item = PL_NewDictionary (pl->hashlinks); item->line = pl->line; pl->pos++; @@ -880,7 +881,7 @@ PL_ParsePropertyListItem (pldata_t *pl) } VISIBLE plitem_t * -PL_GetPropertyList (const char *string) +PL_GetPropertyList (const char *string, hashlink_t **hashlinks) { pldata_t *pl = calloc (1, sizeof (pldata_t)); plitem_t *newpl = NULL; @@ -894,6 +895,7 @@ PL_GetPropertyList (const char *string) pl->error = NULL; pl->line = 1; pl->va_ctx = va_create_context (4); + pl->hashlinks = hashlinks; if ((newpl = PL_ParsePropertyListItem (pl))) { va_destroy_context (pl->va_ctx); diff --git a/libs/util/quakefs.c b/libs/util/quakefs.c index 683378904..569fab341 100644 --- a/libs/util/quakefs.c +++ b/libs/util/quakefs.c @@ -672,7 +672,7 @@ qfs_load_config (void) buf[len + 2] = 0; if (qfs_gd_plist) PL_Free (qfs_gd_plist); - qfs_gd_plist = PL_GetPropertyList (buf); + qfs_gd_plist = PL_GetPropertyList (buf, 0); free (buf); if (qfs_gd_plist && PL_Type (qfs_gd_plist) == QFDictionary) return; // done @@ -680,7 +680,7 @@ qfs_load_config (void) no_config: if (qfs_gd_plist) PL_Free (qfs_gd_plist); - qfs_gd_plist = PL_GetPropertyList (qfs_default_dirconf); + qfs_gd_plist = PL_GetPropertyList (qfs_default_dirconf, 0); } /* diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 4dcda5d86..0132bf6d0 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -244,7 +244,8 @@ static plitem_t * qfv_load_pipeline (vulkan_ctx_t *ctx, const char *name) { if (!ctx->pipelineDef) { - ctx->pipelineDef = PL_GetPropertyList (quakeforge_pipeline); + ctx->pipelineDef = PL_GetPropertyList (quakeforge_pipeline, + &ctx->hashlinks); } plitem_t *item = ctx->pipelineDef; diff --git a/nq/source/host_cmd.c b/nq/source/host_cmd.c index 76529838e..c7e138f23 100644 --- a/nq/source/host_cmd.c +++ b/nq/source/host_cmd.c @@ -434,7 +434,7 @@ entities_array (void) static plitem_t * game_dict (void) { - plitem_t *game = PL_NewDictionary (); + plitem_t *game = PL_NewDictionary (0); PL_D_AddObject (game, "comment", PL_NewString (va (0, "%-21s kills:%3i/%3i", cl.levelname, @@ -455,7 +455,7 @@ game_dict (void) static plitem_t * convert_to_game_dict (script_t *script) { - plitem_t *game = PL_NewDictionary (); + plitem_t *game = PL_NewDictionary (0); plitem_t *item; plitem_t *list; int skill; @@ -500,7 +500,7 @@ convert_to_game_dict (script_t *script) PL_D_AddObject (game, "lightstyles", item); // load the edicts out of the savegame file - list = ED_ConvertToPlist (script, 0); + list = ED_ConvertToPlist (script, 0, 0); item = PL_RemoveObjectAtIndex (list, 0); PL_D_AddObject (game, "globals", item); PL_D_AddObject (game, "entities", list); @@ -647,7 +647,7 @@ Host_Loadgame_f (void) Sys_Printf ("Unexpected EOF reading %s\n", name->str); goto end; } - game = PL_GetPropertyList (script->p); + game = PL_GetPropertyList (script->p, 0); } else { sscanf (script->token->str, "%i", &version); if (version != SAVEGAME_VERSION) { diff --git a/tools/qflight/source/entities.c b/tools/qflight/source/entities.c index 1383004df..d3c608f6f 100644 --- a/tools/qflight/source/entities.c +++ b/tools/qflight/source/entities.c @@ -179,7 +179,7 @@ LoadEntities (void) script = Script_New (); Script_Start (script, "ent data", bsp->entdata); - entity_list = ED_ConvertToPlist (script, 1); + entity_list = ED_ConvertToPlist (script, 1, 0); Script_Delete (script); // start parsing @@ -208,7 +208,7 @@ LoadEntities (void) } entity->dict = PL_ObjectAtIndex (entity_list, i); - dict = PL_NewDictionary (); + dict = PL_NewDictionary (0); // go through all the keys in this entity keys = PL_D_AllKeys (entity->dict); diff --git a/tools/qflight/source/properties.c b/tools/qflight/source/properties.c index e7774f6d4..c9297984b 100644 --- a/tools/qflight/source/properties.c +++ b/tools/qflight/source/properties.c @@ -334,6 +334,6 @@ LoadProperties (const char *filename) Qread (f, buf, len); Qclose (f); buf[len] = 0; - properties = PL_GetPropertyList (buf); + properties = PL_GetPropertyList (buf, 0); free (buf); } From 8664a5b969a8f9f78a22bab9c55d9d38210f43a1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Feb 2021 10:02:04 +0900 Subject: [PATCH 340/435] [util] Enable parser debugging for cexpr Not actually turned on in the code, but cexpr_yydebug is present. --- libs/util/cexpr-lex.l | 2 ++ libs/util/cexpr-parse.y | 1 + 2 files changed, 3 insertions(+) diff --git a/libs/util/cexpr-lex.l b/libs/util/cexpr-lex.l index d34cd250a..46fbcdd55 100644 --- a/libs/util/cexpr-lex.l +++ b/libs/util/cexpr-lex.l @@ -50,6 +50,8 @@ #include "QF/qfplist.h" #include "QF/sys.h" +#define CEXPR_YYDEBUG 1 + #include "QF/cexpr.h" #include "libs/util/cexpr-parse.h" diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y index 07993af9b..599955afd 100644 --- a/libs/util/cexpr-parse.y +++ b/libs/util/cexpr-parse.y @@ -27,6 +27,7 @@ %define api.prefix {cexpr_yy} %define api.pure full %define api.push-pull push +%define parse.trace %parse-param {void *scanner} {exprctx_t *context} %{ From fdba8228099c2a547c530228b9861e31f80d8a45 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Feb 2021 14:43:45 +0900 Subject: [PATCH 341/435] [util] Fix a code-comment disagreement And the comment was correct :P --- include/QF/darray.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/darray.h b/include/QF/darray.h index 2b8689726..f79403283 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -121,9 +121,9 @@ #define DARRAY_CLEAR(array) \ do { \ __auto_type ar = (array); \ - free (ar->a); \ ar->size = 0; \ if (ar->grow) { \ + free (ar->a); \ ar->maxSize = 0; \ ar->a = 0; \ } \ From c8afbdf0f5a0f1e07ebfdb8fa8bb62f3e83137e6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Feb 2021 14:56:11 +0900 Subject: [PATCH 342/435] [util] Add an object-based fixed array allocator --- include/QF/darray.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/QF/darray.h b/include/QF/darray.h index f79403283..50dc6c348 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -88,6 +88,30 @@ ar; \ }) +/** Allocate a fixed-size array using the given allocator + + The allocated array is initilized to be ungrowable, and with both size + and maxSize set to the given size. + + \param array_type Expression acceptable by typeof for determining the + type of the array. + \param array_size The size of the array. + \param alloc Allocator taking (obj, size) where obj is allocator + specific data (eg, a memory pool). + \param data Additional data for the allocator. +*/ +#define DARRAY_ALLOCFIXED_OBJ(array_type, array_size, alloc, obj) \ + ({ \ + __auto_type s = (array_size); \ + typeof (array_type) *ar = alloc ((obj), \ + sizeof(*ar) \ + + s * sizeof (*ar->a)); \ + ar->size = ar->maxSize = s; \ + ar->grow = 0; \ + ar->a = (typeof (ar->a)) (ar + 1); \ + ar; \ + }) + /** Initialized the array. The array will be initialized to be empty but with grow set to the From a408fd40daacb4b15cfc2ee7d67defde3951c199 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Feb 2021 14:56:48 +0900 Subject: [PATCH 343/435] [util] Make plist more const-correct --- include/QF/qfplist.h | 8 ++++---- libs/util/qfplist.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 5de86d05f..89cb00a85 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -185,7 +185,7 @@ const char *PL_String (const plitem_t *string) __attribute__((pure)); \note You are NOT responsible for freeing the returned object. It will be destroyed when its container is. */ -plitem_t *PL_ObjectForKey (plitem_t *dict, const char *key); +plitem_t *PL_ObjectForKey (const plitem_t *dict, const char *key); /** Remove a value from a dictionary object. @@ -195,7 +195,7 @@ plitem_t *PL_ObjectForKey (plitem_t *dict, const char *key); isn't a dictionary. \note You are responsible for freeing the returned object. */ -plitem_t *PL_RemoveObjectForKey (plitem_t *dict, const char *key); +plitem_t *PL_RemoveObjectForKey (const plitem_t *dict, const char *key); /** Retrieve a value from an array object. @@ -206,7 +206,7 @@ plitem_t *PL_RemoveObjectForKey (plitem_t *dict, const char *key); \note You are NOT responsible for freeing the returned object. It will be destroyed when its container is. */ -plitem_t *PL_ObjectAtIndex (plitem_t *array, int index) __attribute__((pure)); +plitem_t *PL_ObjectAtIndex (const plitem_t *array, int index) __attribute__((pure)); /** Retrieve a list of all keys in a dictionary. @@ -222,7 +222,7 @@ plitem_t *PL_D_AllKeys (plitem_t *dict); \return Returns the number of keys in the dictionary. */ -int PL_D_NumKeys (plitem_t *dict) __attribute__((pure)); +int PL_D_NumKeys (const plitem_t *dict) __attribute__((pure)); /** Add a key/value pair to a dictionary. diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 9d4a7b2bf..b40fec69a 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -264,7 +264,7 @@ PL_String (const plitem_t *string) } VISIBLE plitem_t * -PL_ObjectForKey (plitem_t *dict, const char *key) +PL_ObjectForKey (const plitem_t *dict, const char *key) { hashtab_t *table = (hashtab_t *) dict->data; dictkey_t *k; @@ -277,7 +277,7 @@ PL_ObjectForKey (plitem_t *dict, const char *key) } VISIBLE plitem_t * -PL_RemoveObjectForKey (plitem_t *dict, const char *key) +PL_RemoveObjectForKey (const plitem_t *dict, const char *key) { hashtab_t *table = (hashtab_t *) dict->data; dictkey_t *k; @@ -320,7 +320,7 @@ PL_D_AllKeys (plitem_t *dict) } VISIBLE int -PL_D_NumKeys (plitem_t *dict) +PL_D_NumKeys (const plitem_t *dict) { if (dict->type != QFDictionary) return 0; @@ -328,7 +328,7 @@ PL_D_NumKeys (plitem_t *dict) } VISIBLE plitem_t * -PL_ObjectAtIndex (plitem_t *array, int index) +PL_ObjectAtIndex (const plitem_t *array, int index) { plarray_t *arr = (plarray_t *) array->data; From 14e4fd9f6a4a8403bead6e1c3dd62a7ea97039ae Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Feb 2021 15:01:55 +0900 Subject: [PATCH 344/435] [util] Pass context to the plist array/symtab parser allocator --- include/QF/qfplist.h | 10 +++++----- libs/util/qfplist.c | 8 ++++---- libs/video/renderer/vulkan/vkparse.c | 14 ++++++++++---- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 89cb00a85..67eb68588 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -109,7 +109,7 @@ typedef struct plfield_s { typedef struct plelement_s { pltype_t type; ///< the required type of the array elements size_t stride; ///< the size of each element - void *(*alloc) (size_t size); ///< allocator for array memory + void *(*alloc) (void *ctx, size_t size);///< allocator for array memory plparser_t parser; ///< custom parser function void *data; ///< additional data for \a parser } plelement_t; @@ -360,7 +360,7 @@ void PL_TypeMismatch (plitem_t *messages, const plitem_t *item, int PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data, plitem_t *messages, void *context); -/** Parse an array object into a dynamic arrah (see darray.h). +/** Parse an array object into a dynamic array (see darray.h). For each object in the array, the field item is used to determine how to parse the object. If the array is empty, the destination will be @@ -378,7 +378,7 @@ int PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, \param array The array object to parse \param data Pointer to the pointer to which the dynamic array will be written. The dynamic array is allocated using - DARRAY_ALLOCFIXED(). + DARRAY_ALLOCFIXED_OBJ(). \param messages Array object supplied by the caller used for storing messages. The messages may or may not indicate errors (its contents are not checked). This function itself will add @@ -390,7 +390,7 @@ int PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, message format is "[line number]: [message]". If the line number is 0, then the actual line is unknown (due to the source item not being parsed from a file or string). - \param context Additional context data passed to the parser. + \param context Additional context data passed to the parser and allocator. \return 0 if there are any errors, 1 if there are no errors. */ int PL_ParseArray (const plfield_t *field, const plitem_t *array, @@ -438,7 +438,7 @@ int PL_ParseArray (const plfield_t *field, const plitem_t *array, message format is "[line number]: [message]". If the line number is 0, then the actual line is unknown (due to the source item not being parsed from a file or string). - \param context Additional context data passed to the parser. + \param context Additional context data passed to the parser and allocator. \return 0 if there are any errors, 1 if there are no errors. */ int PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index b40fec69a..4b7e34e7a 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1272,8 +1272,8 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, parser = pl_default_parser; } - arr = DARRAY_ALLOCFIXED (arr_t, plarray->numvals * element->stride, - element->alloc); + arr = DARRAY_ALLOCFIXED_OBJ (arr_t, plarray->numvals * element->stride, + element->alloc, context); memset (arr->a, 0, arr->size); // the array is allocated using bytes, but need the actual number of // elements in the array @@ -1329,7 +1329,7 @@ PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, return 1; } - void *obj = element->alloc (element->stride); + void *obj = element->alloc (context, element->stride); memset (obj, 0, element->stride); while ((current = (dictkey_t *) *l++)) { const char *key = current->key; @@ -1349,7 +1349,7 @@ PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, result = 0; } else { Hash_Add (tab, obj); - obj = element->alloc (element->stride); + obj = element->alloc (context, element->stride); memset (obj, 0, element->stride); } } diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 7e336a167..3f02b8022 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -259,6 +259,12 @@ parse_single (const plfield_t *field, const plitem_t *item, return 1; } +static void * +array_alloc (void *context, size_t size) +{ + return malloc (size); +} + static int parse_array (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context) @@ -270,7 +276,7 @@ parse_array (const plfield_t *field, const plitem_t *item, plelement_t element = { array->type, array->stride, - malloc, + array_alloc, array->parser, 0, }; @@ -630,7 +636,7 @@ typedef struct qfv_renderpass_s { static plelement_t parse_qfv_renderpass_attachments_data = { QFDictionary, sizeof (VkAttachmentDescription), - malloc, + array_alloc, parse_VkAttachmentDescription, 0, }; @@ -638,7 +644,7 @@ static plelement_t parse_qfv_renderpass_attachments_data = { static plelement_t parse_qfv_renderpass_subpasses_data = { QFDictionary, sizeof (VkSubpassDescription), - malloc, + array_alloc, parse_VkSubpassDescription, 0, }; @@ -646,7 +652,7 @@ static plelement_t parse_qfv_renderpass_subpasses_data = { static plelement_t parse_qfv_renderpass_dependencies_data = { QFDictionary, sizeof (VkSubpassDependency), - malloc, + array_alloc, parse_VkSubpassDependency, 0, }; From bc763da9f696ac020358925216ed0d52f0b4777f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Feb 2021 15:02:22 +0900 Subject: [PATCH 345/435] [qfcc] Fix a typo in the man page --- tools/qfcc/doc/man/qfcc.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/doc/man/qfcc.1 b/tools/qfcc/doc/man/qfcc.1 index 4105eaa1d..045aa8963 100644 --- a/tools/qfcc/doc/man/qfcc.1 +++ b/tools/qfcc/doc/man/qfcc.1 @@ -100,7 +100,7 @@ For each source file (listed either on the command line, or in \fBprogs.src\fP, write a file whose name is the base name of the source file with an extension of \fB.frame\fP, and contains a list of frame macro names with their associated frame numbers. Eg, \fBplayer.qc\fP will produce -\fBplayer.frame\fPa. Note that files that do not create frame macros will +\fBplayer.frame\fP. Note that files that do not create frame macros will not generate a frame file. At this time, the file is always written to the current directory. From 0dcd946063e1b602c4b30850feab0407094c2e85 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Feb 2021 15:24:28 +0900 Subject: [PATCH 346/435] [util] Add plist parser for dictionary -> array PL_ParseLabeledArray works the same way as PL_ParseArray, but instead takes a dictionary object. The keys of the items are ignored, and the order is not preserved (at this stage), but this is a cleaner solution to getting an array of objects when the definitions of those objects need to be accessible by name as well. --- include/QF/qfplist.h | 39 +++++++++++++++++++++++++++ libs/util/qfplist.c | 63 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 67eb68588..3e1086be0 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -396,6 +396,45 @@ int PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, int PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, plitem_t *messages, void *context); +/** Parse a dictionary object into a dynamic array (see darray.h). + + This is useful when the dictionary object is meant to be a labeled list + rather than a representation of a structure. + + For each object in the array, the field item is used to determine how to + parse the object. If the array is empty, the destination will be + initialized to an empty array. + + When an error occurs (incorrect item type (item type does not match the + type specified in the element object) or the element object's \a parser + returns 0), processing continues but the error result is returned. + + Can be used recursively to parse deep hierarchies. + + \param field Pointer to a single field that has the field data pointer + set to reference a plelement_t object used to describe + the contents of the array. + \param dict The dict object to parse + \param data Pointer to the pointer to which the dynamic array will + be written. The dynamic array is allocated using + DARRAY_ALLOCFIXED_OBJ(). + \param messages Array object supplied by the caller used for storing + messages. The messages may or may not indicate errors (its + contents are not checked). This function itself will add + only string objects. + If there are any errors, suitable messages will be found in + the \a messages object. However, just because there are no + errors doesn't mean that \a messages will remain empty as + a field's \a parser may add other messages. The standard + message format is "[line number]: [message]". If the line + number is 0, then the actual line is unknown (due to the + source item not being parsed from a file or string). + \param context Additional context data passed to the parser and allocator. + \return 0 if there are any errors, 1 if there are no errors. +*/ +int PL_ParseLabeledArray (const plfield_t *field, const plitem_t *dict, + void *data, plitem_t *messages, void *context); + /** Parse a dictionary object into a hash table. For each key in the dictionary, the element object is used to determine diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 4b7e34e7a..6bee78c3f 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -1211,10 +1211,7 @@ PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data, return 0; } - if (!(l = list = Hash_GetList ((hashtab_t *) dict->data))) { - // empty struct: leave as default - return 1; - } + l = list = Hash_GetList ((hashtab_t *) dict->data); while ((current = (dictkey_t *) *l++)) { const plfield_t *f; @@ -1299,6 +1296,64 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, return result; } +VISIBLE int +PL_ParseLabeledArray (const plfield_t *field, const plitem_t *dict, + void *data, plitem_t *messages, void *context) +{ + void **list, **l; + dictkey_t *current; + int result = 1; + plparser_t parser; + plelement_t *element = (plelement_t *) field->data; + typedef struct arr_s DARRAY_TYPE(byte) arr_t; + arr_t *arr; + plfield_t f = { 0, 0, element->type, element->parser, element->data }; + + if (dict->type != QFDictionary) { + PL_Message (messages, dict, "error: not a dictionary object"); + return 0; + } + if (f.parser) { + parser = f.parser; + } else { + parser = pl_default_parser; + } + + list = Hash_GetList ((hashtab_t *) dict->data); + + int numvals = 0; + for (l = list; *l; l++) { + numvals++; + } + + arr = DARRAY_ALLOCFIXED_OBJ (arr_t, numvals * element->stride, + element->alloc, context); + memset (arr->a, 0, arr->size); + // the array is allocated using bytes, but need the actual number of + // elements in the array + arr->size = arr->maxSize = numvals; + + for (int i = 0; i < numvals; i++) { + current = list[i]; + plitem_t *item = current->value; + void *eledata = &arr->a[i * element->stride]; + + if (!PL_CheckType (element->type, item->type)) { + char index[16]; + snprintf (index, sizeof(index) - 1, "%d", i); + index[15] = 0; + PL_TypeMismatch (messages, item, index, element->type, item->type); + result = 0; + } else { + if (!parser (&f, item, eledata, messages, context)) { + result = 0; + } + } + } + *(arr_t **) data = arr; + return result; +} + VISIBLE int PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, plitem_t *messages, void *context) From 5535d1f8e6f32cc7817dce3c2b624ea90ff8eeb1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Feb 2021 16:53:21 +0900 Subject: [PATCH 347/435] [util] Keep track of plist dictionary key order The order in which keys are added to the dictionary object is maintained. Adding a key after removing an old key adds the new key to the end of the list rather than reusing the old key's spot. --- include/QF/qfplist.h | 16 +++- libs/util/qfplist.c | 169 ++++++++++++++++++++++++------------------- 2 files changed, 109 insertions(+), 76 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index 3e1086be0..f1cc95b8a 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -197,12 +197,24 @@ plitem_t *PL_ObjectForKey (const plitem_t *dict, const char *key); */ plitem_t *PL_RemoveObjectForKey (const plitem_t *dict, const char *key); +/** Retrieve a key from a dictionary object. + + \param dict The dictionary to get the key from + \param index The index of the key + \return the key at the specified index, or NULL if index is out of range or + dict is not a dictionaly + isn't an array. + \note You are NOT responsible for freeing the returned object. It will + be destroyed when its container is. +*/ +const char *PL_KeyAtIndex (const plitem_t *array, int index) __attribute__((pure)); + /** Retrieve a value from an array object. \param array The array to get the value from \param index The index within the array to retrieve - \return the value associated with the key, or NULL if not found or array - isn't an array. + \return the value at the specified index, or NULL if index is out of range + or array is not an array. \note You are NOT responsible for freeing the returned object. It will be destroyed when its container is. */ diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 6bee78c3f..6e4726c95 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -64,6 +64,12 @@ struct dictkey_s { }; typedef struct dictkey_s dictkey_t; +struct pldict_s { + hashtab_t *tab; + struct DARRAY_TYPE (dictkey_t *) keys; +}; +typedef struct pldict_s pldict_t; + /* Arrays */ @@ -161,8 +167,9 @@ VISIBLE plitem_t * PL_NewDictionary (hashlink_t **hashlinks) { plitem_t *item = PL_NewItem (QFDictionary); - hashtab_t *dict = Hash_NewTable (1021, dict_get_key, dict_free, NULL, - hashlinks); + pldict_t *dict = malloc (sizeof (pldict_t)); + dict->tab = Hash_NewTable (1021, dict_get_key, dict_free, NULL, hashlinks); + DARRAY_INIT (&dict->keys, 8); item->data = dict; return item; } @@ -205,18 +212,25 @@ PL_NewString (const char *str) VISIBLE void PL_Free (plitem_t *item) { + pldict_t *dict; + plarray_t *array; + switch (item->type) { case QFDictionary: - Hash_DelTable (item->data); + dict = item->data; + Hash_DelTable (dict->tab); + DARRAY_CLEAR (&dict->keys); break; - case QFArray: { - int i = ((plarray_t *) item->data)->numvals; + case QFArray: + { + array = item->data; + int i = array->numvals; while (i-- > 0) { - PL_Free (((plarray_t *) item->data)->values[i]); + PL_Free (array->values[i]); } - free (((plarray_t *) item->data)->values); + free (array->values); free (item->data); } break; @@ -264,67 +278,85 @@ PL_String (const plitem_t *string) } VISIBLE plitem_t * -PL_ObjectForKey (const plitem_t *dict, const char *key) +PL_ObjectForKey (const plitem_t *item, const char *key) { - hashtab_t *table = (hashtab_t *) dict->data; + pldict_t *dict = (pldict_t *) item->data; dictkey_t *k; - if (dict->type != QFDictionary) + if (item->type != QFDictionary) return NULL; - k = (dictkey_t *) Hash_Find (table, key); + k = (dictkey_t *) Hash_Find (dict->tab, key); return k ? k->value : NULL; } -VISIBLE plitem_t * -PL_RemoveObjectForKey (const plitem_t *dict, const char *key) +VISIBLE const char * +PL_KeyAtIndex (const plitem_t *item, int index) { - hashtab_t *table = (hashtab_t *) dict->data; + pldict_t *dict = (pldict_t *) item->data; + + if (item->type != QFDictionary) + return NULL; + if (index < 0 || (size_t) index >= dict->keys.size) { + return NULL; + } + + return dict->keys.a[index]->key; +} + +VISIBLE plitem_t * +PL_RemoveObjectForKey (const plitem_t *item, const char *key) +{ + pldict_t *dict = (pldict_t *) item->data; dictkey_t *k; plitem_t *value; - if (dict->type != QFDictionary) + if (item->type != QFDictionary) return NULL; - k = (dictkey_t *) Hash_Del (table, key); + k = (dictkey_t *) Hash_Del (dict->tab, key); if (!k) return NULL; value = k->value; k->value = 0; + for (size_t i = 0; i < dict->keys.size; i++) { + if (dict->keys.a[i] == k) { + DARRAY_REMOVE_AT (&dict->keys, i); + break; + } + } dict_free (k, 0); return value; } VISIBLE plitem_t * -PL_D_AllKeys (plitem_t *dict) +PL_D_AllKeys (plitem_t *item) { - void **list, **l; - dictkey_t *current; - plitem_t *array; + pldict_t *dict = (pldict_t *) item->data; + dictkey_t *current; + plitem_t *array; - if (dict->type != QFDictionary) - return NULL; - - if (!(l = list = Hash_GetList ((hashtab_t *) dict->data))) + if (item->type != QFDictionary) return NULL; if (!(array = PL_NewArray ())) return NULL; - while ((current = (dictkey_t *) *l++)) { + for (size_t i = 0; i < dict->keys.size; i++) { + current = dict->keys.a[i]; PL_A_AddObject (array, PL_NewString (current->key)); } - free (list); return array; } VISIBLE int -PL_D_NumKeys (const plitem_t *dict) +PL_D_NumKeys (const plitem_t *item) { - if (dict->type != QFDictionary) + pldict_t *dict = (pldict_t *) item->data; + if (item->type != QFDictionary) return 0; - return Hash_NumElements ((hashtab_t *) dict->data); + return Hash_NumElements (dict->tab); } VISIBLE plitem_t * @@ -339,14 +371,15 @@ PL_ObjectAtIndex (const plitem_t *array, int index) } VISIBLE qboolean -PL_D_AddObject (plitem_t *dict, const char *key, plitem_t *value) +PL_D_AddObject (plitem_t *item, const char *key, plitem_t *value) { + pldict_t *dict = (pldict_t *) item->data; dictkey_t *k; - if (dict->type != QFDictionary) + if (item->type != QFDictionary) return false; - if ((k = Hash_Find ((hashtab_t *)dict->data, key))) { + if ((k = Hash_Find (dict->tab, key))) { PL_Free ((plitem_t *) k->value); k->value = value; } else { @@ -358,7 +391,8 @@ PL_D_AddObject (plitem_t *dict, const char *key, plitem_t *value) k->key = strdup (key); k->value = value; - Hash_Add ((hashtab_t *)dict->data, k); + Hash_Add (dict->tab, k); + DARRAY_APPEND (&dict->keys, k); } return true; } @@ -1024,24 +1058,24 @@ write_string (dstring_t *dstr, const char *str) static void write_item (dstring_t *dstr, plitem_t *item, int level) { - void **list, **l; dictkey_t *current; plarray_t *array; + pldict_t *dict; plbinary_t *binary; int i; switch (item->type) { case QFDictionary: write_string_len (dstr, "{\n", 2); - l = list = Hash_GetList ((hashtab_t *) item->data); - while ((current = (dictkey_t *) *l++)) { + dict = (pldict_t *) item->data; + for (size_t i = 0; i < dict->keys.size; i++) { + current = dict->keys.a[i]; write_tabs (dstr, level + 1); write_string (dstr, current->key); write_string_len (dstr, " = ", 3); write_item (dstr, current->value, level + 1); write_string_len (dstr, ";\n", 2); } - free (list); write_tabs (dstr, level); write_string_len (dstr, "}", 1); break; @@ -1128,7 +1162,7 @@ pl_default_parser (const plfield_t *field, const plitem_t *item, void *data, switch (field->type) { case QFDictionary: { - *(hashtab_t **)data = (hashtab_t *)item->data; + *(hashtab_t **)data = ((pldict_t *)item->data)->tab; } return 1; case QFArray: @@ -1198,23 +1232,23 @@ PL_TypeMismatch (plitem_t *messages, const plitem_t *item, const char *name, } VISIBLE int -PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data, +PL_ParseStruct (const plfield_t *fields, const plitem_t *item, void *data, plitem_t *messages, void *context) { - void **list, **l; + pldict_t *dict = item->data; dictkey_t *current; int result = 1; plparser_t parser; - if (dict->type != QFDictionary) { - PL_Message (messages, dict, "error: not a dictionary object"); + if (item->type != QFDictionary) { + PL_Message (messages, item, "error: not a dictionary object"); return 0; } - l = list = Hash_GetList ((hashtab_t *) dict->data); - while ((current = (dictkey_t *) *l++)) { + for (size_t i = 0; i < dict->keys.size; i++) { const plfield_t *f; + current = dict->keys.a[i]; for (f = fields; f->name; f++) { if (strcmp (f->name, current->key) == 0) { plitem_t *item = current->value; @@ -1238,12 +1272,11 @@ PL_ParseStruct (const plfield_t *fields, const plitem_t *dict, void *data, } } if (!f->name) { - PL_Message (messages, dict, "error: unknown field %s", + PL_Message (messages, item, "error: unknown field %s", current->key); result = 0; } } - free (list); return result; } @@ -1297,10 +1330,10 @@ PL_ParseArray (const plfield_t *field, const plitem_t *array, void *data, } VISIBLE int -PL_ParseLabeledArray (const plfield_t *field, const plitem_t *dict, +PL_ParseLabeledArray (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context) { - void **list, **l; + pldict_t *dict = item->data; dictkey_t *current; int result = 1; plparser_t parser; @@ -1309,8 +1342,8 @@ PL_ParseLabeledArray (const plfield_t *field, const plitem_t *dict, arr_t *arr; plfield_t f = { 0, 0, element->type, element->parser, element->data }; - if (dict->type != QFDictionary) { - PL_Message (messages, dict, "error: not a dictionary object"); + if (item->type != QFDictionary) { + PL_Message (messages, item, "error: not a dictionary object"); return 0; } if (f.parser) { @@ -1319,28 +1352,21 @@ PL_ParseLabeledArray (const plfield_t *field, const plitem_t *dict, parser = pl_default_parser; } - list = Hash_GetList ((hashtab_t *) dict->data); - - int numvals = 0; - for (l = list; *l; l++) { - numvals++; - } - - arr = DARRAY_ALLOCFIXED_OBJ (arr_t, numvals * element->stride, + arr = DARRAY_ALLOCFIXED_OBJ (arr_t, dict->keys.size * element->stride, element->alloc, context); memset (arr->a, 0, arr->size); // the array is allocated using bytes, but need the actual number of // elements in the array - arr->size = arr->maxSize = numvals; + arr->size = arr->maxSize = dict->keys.size; - for (int i = 0; i < numvals; i++) { - current = list[i]; + for (size_t i = 0; i < dict->keys.size; i++) { + current = dict->keys.a[i]; plitem_t *item = current->value; void *eledata = &arr->a[i * element->stride]; if (!PL_CheckType (element->type, item->type)) { char index[16]; - snprintf (index, sizeof(index) - 1, "%d", i); + snprintf (index, sizeof(index) - 1, "%zd", i); index[15] = 0; PL_TypeMismatch (messages, item, index, element->type, item->type); result = 0; @@ -1355,10 +1381,10 @@ PL_ParseLabeledArray (const plfield_t *field, const plitem_t *dict, } VISIBLE int -PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, +PL_ParseSymtab (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context) { - void **list, **l; + pldict_t *dict = item->data; dictkey_t *current; int result = 1; plparser_t parser; @@ -1367,26 +1393,22 @@ PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, plelement_t *element = (plelement_t *) field->data; plfield_t f = { 0, 0, element->type, element->parser, element->data }; - if (dict->type != QFDictionary) { - PL_Message (messages, dict, "error: not a dictionary object"); + if (item->type != QFDictionary) { + PL_Message (messages, item, "error: not a dictionary object"); return 0; } if (f.parser) { parser = f.parser; } else { - PL_Message (messages, dict, "no parser set"); + PL_Message (messages, item, "no parser set"); return 0; } - if (!(l = list = Hash_GetList ((hashtab_t *) dict->data))) { - // empty struct: leave as default - return 1; - } - void *obj = element->alloc (context, element->stride); memset (obj, 0, element->stride); - while ((current = (dictkey_t *) *l++)) { + for (size_t i = 0; i < dict->keys.size; i++) { + current = dict->keys.a[i]; const char *key = current->key; plitem_t *item = current->value; @@ -1410,6 +1432,5 @@ PL_ParseSymtab (const plfield_t *field, const plitem_t *dict, void *data, } } Hash_Free (tab, obj); - free (list); return result; } From 35f12c36ff631b3d9ef31c0f373e83a11c3d1508 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Feb 2021 19:29:48 +0900 Subject: [PATCH 348/435] [util] Catch some more cexpr errors --- libs/util/cexpr-parse.y | 5 ++++- libs/util/cexpr-type.c | 10 +++++----- libs/util/cexpr-vars.c | 2 ++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y index 599955afd..8ccf0b20b 100644 --- a/libs/util/cexpr-parse.y +++ b/libs/util/cexpr-parse.y @@ -129,7 +129,7 @@ uexpr | '(' expr ')' { $$ = $2; } | NAME '(' opt_arg_list ')' { $$ = function_expr ($1, $3, context); } | uexpr '.' field { $$ = field_expr ($1, $3, context); } - | uexpr '[' field ']' { $$ = index_expr ($1, $3, context); } + | uexpr '[' expr ']' { $$ = index_expr ($1, $3, context); } | '+' uexpr %prec UNARY { $$ = $2; } | '-' uexpr %prec UNARY { $$ = unary_expr ('-', $2, context); } | '!' uexpr %prec UNARY { $$ = unary_expr ('!', $2, context); } @@ -268,6 +268,9 @@ index_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context) binop_t *binop; exprval_t *result = 0; + if (!a || !b) { + return 0; + } for (binop = a->type->binops; binop->op; binop++) { if (binop->op == '[' && binop->other == b->type) { break; diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index 1ba3b3f0f..2aff20006 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -646,14 +646,14 @@ static void plitem_index (const exprval_t *a, int index, exprval_t *c, exprctx_t *ctx) { - __auto_type array = *(plitem_t **) a->type->data; + __auto_type array = *(plitem_t **) a->value; if (PL_Type (array) != QFArray) { cexpr_error(ctx, "not an array object"); return; } plitem_t *item = PL_ObjectAtIndex (array, index); - exprval_t *val = 0; + exprval_t *val = 0; if (!item) { cexpr_error (ctx, "invalid index: %d", index); } else { @@ -667,7 +667,7 @@ static void plitem_int (const exprval_t *a, const exprval_t *b, exprval_t *c, exprctx_t *ctx) { - int index = *(int *) a->value; + int index = *(int *) b->value; plitem_index (a, index, c, ctx); } @@ -675,7 +675,7 @@ static void plitem_uint (const exprval_t *a, const exprval_t *b, exprval_t *c, exprctx_t *ctx) { - int index = *(int *) a->value; + int index = *(unsigned *) b->value; plitem_index (a, index, c, ctx); } @@ -683,7 +683,7 @@ static void plitem_size_t (const exprval_t *a, const exprval_t *b, exprval_t *c, exprctx_t *ctx) { - int index = *(int *) a->value; + int index = *(size_t *) b->value; plitem_index (a, index, c, ctx); } diff --git a/libs/util/cexpr-vars.c b/libs/util/cexpr-vars.c index 04c6871ad..9b390b523 100644 --- a/libs/util/cexpr-vars.c +++ b/libs/util/cexpr-vars.c @@ -49,6 +49,8 @@ cexpr_struct_getfield (const exprval_t *a, const exprval_t *b, exprval_t *c, val = cmemalloc (ctx->memsuper, sizeof (exprval_t)); val->type = field->type; val->value = a->value + (ptrdiff_t) field->value; + } else { + cexpr_error (ctx, "%s has no field %s", a->type->name, name); } *(exprval_t **) c->value = val; } From 55104ac430bed00caf6b5a9fb9c0861ca2eecb68 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Feb 2021 19:30:30 +0900 Subject: [PATCH 349/435] [util] Allow "any type" results for cexpr Setting the result type cexpr_exprval tells cexpr to simply return whoe exprval object rather than the referenced value, thus allowing the caller to check the type when the expression is context sensitive. --- libs/util/cexpr-parse.y | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y index 8ccf0b20b..ad734def7 100644 --- a/libs/util/cexpr-parse.y +++ b/libs/util/cexpr-parse.y @@ -191,6 +191,10 @@ assign_expr (exprval_t *dst, const exprval_t *src, exprctx_t *context) if (!src) { return; } + if (dst->type == &cexpr_exprval) { + *(exprval_t **) dst->value = (exprval_t *) src; + return; + } binop = cexpr_find_cast (dst->type, src->type); if (binop && binop->op) { binop->func (dst, src, dst, context); From cffd48434ca28b86ba0131ec872b6715a88a064e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Feb 2021 17:43:11 +0900 Subject: [PATCH 350/435] [vulkan] Move the shaders into their own directory --- libs/video/renderer/Makemodule.am | 34 ++++++++++--------- libs/video/renderer/vulkan/shader.c | 16 ++++----- .../renderer/vulkan/{ => shader}/alias.frag | 0 .../renderer/vulkan/{ => shader}/alias.vert | 0 .../vulkan/{ => shader}/passthrough.vert | 0 .../vulkan/{ => shader}/pushcolor.frag | 0 .../vulkan/{ => shader}/quakebsp.frag | 0 .../vulkan/{ => shader}/quakebsp.vert | 0 .../renderer/vulkan/{ => shader}/twod.frag | 0 .../renderer/vulkan/{ => shader}/twod.vert | 0 10 files changed, 26 insertions(+), 24 deletions(-) rename libs/video/renderer/vulkan/{ => shader}/alias.frag (100%) rename libs/video/renderer/vulkan/{ => shader}/alias.vert (100%) rename libs/video/renderer/vulkan/{ => shader}/passthrough.vert (100%) rename libs/video/renderer/vulkan/{ => shader}/pushcolor.frag (100%) rename libs/video/renderer/vulkan/{ => shader}/quakebsp.frag (100%) rename libs/video/renderer/vulkan/{ => shader}/quakebsp.vert (100%) rename libs/video/renderer/vulkan/{ => shader}/twod.frag (100%) rename libs/video/renderer/vulkan/{ => shader}/twod.vert (100%) diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index b322a7ca4..cb0eec6d1 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -262,22 +262,24 @@ vkparse_src = \ vkparse_plist = \ $(srcdir)/libs/video/renderer/vulkan/vkparse.plist -twodv_src = libs/video/renderer/vulkan/twod.vert -twodv_c = libs/video/renderer/vulkan/twod.vert.spvc -twodf_src = libs/video/renderer/vulkan/twod.frag -twodf_c = libs/video/renderer/vulkan/twod.frag.spvc -quakebspv_src = libs/video/renderer/vulkan/quakebsp.vert -quakebspv_c = libs/video/renderer/vulkan/quakebsp.vert.spvc -quakebspf_src = libs/video/renderer/vulkan/quakebsp.frag -quakebspf_c = libs/video/renderer/vulkan/quakebsp.frag.spvc -aliasv_src = libs/video/renderer/vulkan/alias.vert -aliasv_c = libs/video/renderer/vulkan/alias.vert.spvc -aliasf_src = libs/video/renderer/vulkan/alias.frag -aliasf_c = libs/video/renderer/vulkan/alias.frag.spvc -passthrough_src = libs/video/renderer/vulkan/passthrough.vert -passthrough_c = libs/video/renderer/vulkan/passthrough.vert.spvc -pushcolor_src = libs/video/renderer/vulkan/pushcolor.frag -pushcolor_c = libs/video/renderer/vulkan/pushcolor.frag.spvc +vkshaderpath = libs/video/renderer/vulkan/shader + +twodv_src = $(vkshaderpath)/twod.vert +twodv_c = $(vkshaderpath)/twod.vert.spvc +twodf_src = $(vkshaderpath)/twod.frag +twodf_c = $(vkshaderpath)/twod.frag.spvc +quakebspv_src = $(vkshaderpath)/quakebsp.vert +quakebspv_c = $(vkshaderpath)/quakebsp.vert.spvc +quakebspf_src = $(vkshaderpath)/quakebsp.frag +quakebspf_c = $(vkshaderpath)/quakebsp.frag.spvc +aliasv_src = $(vkshaderpath)/alias.vert +aliasv_c = $(vkshaderpath)/alias.vert.spvc +aliasf_src = $(vkshaderpath)/alias.frag +aliasf_c = $(vkshaderpath)/alias.frag.spvc +passthrough_src = $(vkshaderpath)/passthrough.vert +passthrough_c = $(vkshaderpath)/passthrough.vert.spvc +pushcolor_src = $(vkshaderpath)/pushcolor.frag +pushcolor_c = $(vkshaderpath)/pushcolor.frag.spvc $(twodv_c): $(twodv_src) diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index a3cc9e3f0..90a93684b 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -55,21 +55,21 @@ #include "vid_vulkan.h" static -#include "libs/video/renderer/vulkan/twod.vert.spvc" +#include "libs/video/renderer/vulkan/shader/twod.vert.spvc" static -#include "libs/video/renderer/vulkan/twod.frag.spvc" +#include "libs/video/renderer/vulkan/shader/twod.frag.spvc" static -#include "libs/video/renderer/vulkan/quakebsp.vert.spvc" +#include "libs/video/renderer/vulkan/shader/quakebsp.vert.spvc" static -#include "libs/video/renderer/vulkan/quakebsp.frag.spvc" +#include "libs/video/renderer/vulkan/shader/quakebsp.frag.spvc" static -#include "libs/video/renderer/vulkan/alias.vert.spvc" +#include "libs/video/renderer/vulkan/shader/alias.vert.spvc" static -#include "libs/video/renderer/vulkan/alias.frag.spvc" +#include "libs/video/renderer/vulkan/shader/alias.frag.spvc" static -#include "libs/video/renderer/vulkan/passthrough.vert.spvc" +#include "libs/video/renderer/vulkan/shader/passthrough.vert.spvc" static -#include "libs/video/renderer/vulkan/pushcolor.frag.spvc" +#include "libs/video/renderer/vulkan/shader/pushcolor.frag.spvc" typedef struct shaderdata_s { const char *name; diff --git a/libs/video/renderer/vulkan/alias.frag b/libs/video/renderer/vulkan/shader/alias.frag similarity index 100% rename from libs/video/renderer/vulkan/alias.frag rename to libs/video/renderer/vulkan/shader/alias.frag diff --git a/libs/video/renderer/vulkan/alias.vert b/libs/video/renderer/vulkan/shader/alias.vert similarity index 100% rename from libs/video/renderer/vulkan/alias.vert rename to libs/video/renderer/vulkan/shader/alias.vert diff --git a/libs/video/renderer/vulkan/passthrough.vert b/libs/video/renderer/vulkan/shader/passthrough.vert similarity index 100% rename from libs/video/renderer/vulkan/passthrough.vert rename to libs/video/renderer/vulkan/shader/passthrough.vert diff --git a/libs/video/renderer/vulkan/pushcolor.frag b/libs/video/renderer/vulkan/shader/pushcolor.frag similarity index 100% rename from libs/video/renderer/vulkan/pushcolor.frag rename to libs/video/renderer/vulkan/shader/pushcolor.frag diff --git a/libs/video/renderer/vulkan/quakebsp.frag b/libs/video/renderer/vulkan/shader/quakebsp.frag similarity index 100% rename from libs/video/renderer/vulkan/quakebsp.frag rename to libs/video/renderer/vulkan/shader/quakebsp.frag diff --git a/libs/video/renderer/vulkan/quakebsp.vert b/libs/video/renderer/vulkan/shader/quakebsp.vert similarity index 100% rename from libs/video/renderer/vulkan/quakebsp.vert rename to libs/video/renderer/vulkan/shader/quakebsp.vert diff --git a/libs/video/renderer/vulkan/twod.frag b/libs/video/renderer/vulkan/shader/twod.frag similarity index 100% rename from libs/video/renderer/vulkan/twod.frag rename to libs/video/renderer/vulkan/shader/twod.frag diff --git a/libs/video/renderer/vulkan/twod.vert b/libs/video/renderer/vulkan/shader/twod.vert similarity index 100% rename from libs/video/renderer/vulkan/twod.vert rename to libs/video/renderer/vulkan/shader/twod.vert From 121425a75bba7056a931c3b9494e438f20e558de Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 14 Feb 2021 11:20:54 +0900 Subject: [PATCH 351/435] [vulkan] Allow all struct objects to be referenced --- libs/video/renderer/vulkan/vkgen/vkstruct.r | 8 +++-- libs/video/renderer/vulkan/vkparse.c | 35 +++++++++++++++++---- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/libs/video/renderer/vulkan/vkgen/vkstruct.r b/libs/video/renderer/vulkan/vkgen/vkstruct.r index 108af71ef..77b11fad5 100644 --- a/libs/video/renderer/vulkan/vkgen/vkstruct.r +++ b/libs/video/renderer/vulkan/vkgen/vkstruct.r @@ -139,9 +139,13 @@ fprintf (output_file, " = %s;\n", [self sTypeName]); } fprintf (output_file, + "\tif (PL_Type (item) == QFString\n" + "\t\t&& !(item = parse_reference (item, \"%s\", messages, context))) {\n" + "\t\treturn 0;\n" + "\t}\n" "\treturn PL_ParseStruct (%s_fields, item, data, messages," " context);\n", - [self outname]); + [self outname], [self outname]); fprintf (output_file, "}\n"); fprintf (output_file, "static exprsym_t %s_symbols[] = {\n", [self outname]); @@ -214,7 +218,7 @@ -(string) parseType { - return "QFDictionary"; + return "QFMultiType | (1 << QFString) | (1 << QFDictionary)"; } -(string) parseFunc diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 3f02b8022..ad2696c8f 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -232,6 +232,24 @@ parse_enum (const plfield_t *field, const plitem_t *item, return ret; } +static const plitem_t * +parse_reference (const plitem_t *item, const char *type, plitem_t *messages, + parsectx_t *pctx) +{ + exprctx_t ectx = *pctx->ectx; + vulkan_ctx_t *ctx = pctx->vctx; + plitem_t *refItem = 0; + exprval_t result = { &cexpr_plitem, &refItem }; + ectx.symtab = 0; + ectx.result = &result; + const char *name = PL_String (item); + if (cexpr_eval_string (name, &ectx)) { + PL_Message (messages, item, va (ctx->va_ctx, "not a %s reference", type)); + return 0; + } + return refItem; +} + static int parse_single (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context) @@ -420,12 +438,15 @@ parse_VkDescriptorSetLayout (const plfield_t *field, const plitem_t *item, { __auto_type handle = (VkDescriptorSetLayout *) data; int ret = 1; - exprctx_t ectx = *((parsectx_t *) context)->ectx; - vulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx; + parsectx_t *pctx = context; + exprctx_t ectx = *pctx->ectx; + vulkan_ctx_t *ctx = pctx->vctx; const char *name = PL_String (item); Sys_Printf ("parse_VkDescriptorSetLayout: %s\n", name); - name = va (ctx->va_ctx, "$"QFV_PROPERTIES".setLayouts.%s", name); + if (name[0] != '$') { + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".setLayouts.%s", name); + } *handle = (VkDescriptorSetLayout) QFV_GetHandle (ctx->setLayouts, name); if (*handle) { @@ -453,12 +474,14 @@ parse_VkPipelineLayout (const plitem_t *item, void **data, { __auto_type handle = (VkPipelineLayout *) data[0]; int ret = 1; - exprctx_t ectx = *((parsectx_t *) context)->ectx; - vulkan_ctx_t *ctx = ((parsectx_t *) context)->vctx; + exprctx_t ectx = *context->ectx; + vulkan_ctx_t *ctx = context->vctx; const char *name = PL_String (item); Sys_Printf ("parse_VkPipelineLayout: %s\n", name); - name = va (ctx->va_ctx, "$"QFV_PROPERTIES".pipelineLayouts.%s", name); + if (name[0] != '$') { + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".pipelineLayouts.%s", name); + } *handle = (VkPipelineLayout) QFV_GetHandle (ctx->pipelineLayouts, name); if (*handle) { From a94949c00928a9be998bf226412558dbb25b9932 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 14 Feb 2021 11:35:06 +0900 Subject: [PATCH 352/435] [vulkan] Start moving towards a deferred renderer After getting lights even vaguely working for alias models, I realized that it just wasn't going to be feasible to do nice lighting with forward rendering. This gets the bulk of the work done for deferred rendering, but still need to sort out the shaders before any real testing can be done. --- include/QF/Vulkan/image.h | 13 +- include/QF/Vulkan/qf_alias.h | 36 +- include/QF/Vulkan/qf_bsp.h | 13 +- include/QF/Vulkan/qf_vid.h | 15 +- include/QF/Vulkan/renderpass.h | 6 + include/vid_vulkan.h | 23 +- libs/video/renderer/Makemodule.am | 4 +- libs/video/renderer/vid_render_vulkan.c | 40 +- libs/video/renderer/vulkan/deferred.plist | 342 ++++++++++++++ libs/video/renderer/vulkan/qfpipeline.plist | 163 +++---- libs/video/renderer/vulkan/vkparse.c | 424 ++++++++++++++++-- libs/video/renderer/vulkan/vkparse.h | 31 +- libs/video/renderer/vulkan/vkparse.plist | 45 ++ libs/video/renderer/vulkan/vulkan_alias.c | 231 +++++----- libs/video/renderer/vulkan/vulkan_bsp.c | 256 ++++++----- libs/video/renderer/vulkan/vulkan_draw.c | 5 +- .../video/renderer/vulkan/vulkan_vid_common.c | 251 +++++------ 17 files changed, 1347 insertions(+), 551 deletions(-) create mode 100644 libs/video/renderer/vulkan/deferred.plist diff --git a/include/QF/Vulkan/image.h b/include/QF/Vulkan/image.h index 9942562b2..5e5623137 100644 --- a/include/QF/Vulkan/image.h +++ b/include/QF/Vulkan/image.h @@ -3,8 +3,17 @@ #include "QF/darray.h" -typedef struct qfv_imageset_s DARRAY_TYPE (VkImage) qfv_imageset_t; -typedef struct qfv_imageviewset_s DARRAY_TYPE (VkImageView) qfv_imageviewset_t; +typedef struct qfv_imageset_s + DARRAY_TYPE (VkImage) qfv_imageset_t; + +#define QFV_AllocImages(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_imageset_t, num, allocator) + +typedef struct qfv_imageviewset_s + DARRAY_TYPE (VkImageView) qfv_imageviewset_t; + +#define QFV_AllocImageViews(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_imageviewset_t, num, allocator) typedef struct qfv_imageresource_s { struct qfv_device_s *device; diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index 714cb06b3..597888a4d 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -36,6 +36,7 @@ #include "QF/model.h" #include "QF/modelgen.h" #include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/command.h" typedef struct aliasvrt_s { float vertex[4]; @@ -61,32 +62,22 @@ typedef struct qfv_alias_skin_s { byte colorb[4]; } qfv_alias_skin_t; -typedef struct qfv_light_s { - vec3_t color; - float dist; - vec3_t position; - int type; - vec3_t direction; - float cone; -} qfv_light_t; - -#define ALIAS_LIGHTS 8 - -typedef struct qfv_light_buffer_s { - int light_count; - qfv_light_t lights[ALIAS_LIGHTS] __attribute__((aligned(16))); -} qfv_light_buffer_t; - -#define ALIAS_BUFFER_INFOS 2 +#define ALIAS_BUFFER_INFOS 1 #define ALIAS_IMAGE_INFOS 1 +enum { + QFV_aliasDepth, + QFV_aliasGBuffer, + //QFV_aliasTranslucent, + + QFV_aliasNumPasses +}; + typedef struct aliasframe_s { - VkCommandBuffer cmd; + qfv_cmdbufferset_t cmdSet; VkDescriptorBufferInfo bufferInfo[ALIAS_BUFFER_INFOS]; VkDescriptorImageInfo imageInfo[ALIAS_IMAGE_INFOS]; VkWriteDescriptorSet descriptors[ALIAS_BUFFER_INFOS + ALIAS_IMAGE_INFOS]; - qfv_light_buffer_t *lights; - VkBuffer light_buffer; } aliasframe_t; typedef struct aliasframeset_s @@ -94,11 +85,10 @@ typedef struct aliasframeset_s typedef struct aliasctx_s { aliasframeset_t frames; - VkPipeline pipeline; + VkPipeline depth; + VkPipeline gbuf; VkPipelineLayout layout; VkSampler sampler; - - VkDeviceMemory light_memory; } aliasctx_t; struct vulkan_ctx_s; diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index 151e6e7be..b78aaf643 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -35,6 +35,7 @@ #include "QF/darray.h" #include "QF/model.h" #include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/command.h" typedef struct bspvert_s { quat_t vertex; @@ -69,13 +70,19 @@ typedef enum { // Texture, GlowMap, LightMap, SkySheet, SkyCube #define BSP_IMAGE_INFOS 5 +enum { + QFV_bspDepth, + QFV_bspGBuffer, + QFV_bspTranslucent, + + QFV_bspNumPasses +}; + typedef struct bspframe_s { uint32_t *index_data; // pointer into mega-buffer for this frame (c) uint32_t index_offset; // offset of index_data within mega-buffer (c) uint32_t index_count; // number if indices queued (d) - VkCommandBuffer bsp_cmd; - VkCommandBuffer turb_cmd; - VkCommandBuffer sky_cmd; + qfv_cmdbufferset_t cmdSet; VkDescriptorBufferInfo bufferInfo[BSP_BUFFER_INFOS]; VkDescriptorImageInfo imageInfo[BSP_IMAGE_INFOS]; VkWriteDescriptorSet descriptors[BSP_BUFFER_INFOS + BSP_IMAGE_INFOS]; diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index 1102845b5..f81e934a1 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -35,9 +35,22 @@ #endif #include +//FIXME location +enum { + QFV_passDepth, // geometry + QFV_passGBuffer, // geometry + QFV_passTranslucent, // geometry + QFV_passLighting, // single quad + QFV_passCompose, // single quad + + QFV_NumPasses +}; + struct vulkan_ctx_s; -void Vulkan_DestroyFramebuffers (struct vulkan_ctx_s *ctx); +void Vulkan_DestroyFrames (struct vulkan_ctx_s *ctx); +void Vulkan_CreateFrames (struct vulkan_ctx_s *ctx); void Vulkan_CreateFramebuffers (struct vulkan_ctx_s *ctx); +void Vulkan_DestroyFramebuffers (struct vulkan_ctx_s *ctx); void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx); void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx); void Vulkan_CreateMatrices (struct vulkan_ctx_s *ctx); diff --git a/include/QF/Vulkan/renderpass.h b/include/QF/Vulkan/renderpass.h index 49134c730..a584d476d 100644 --- a/include/QF/Vulkan/renderpass.h +++ b/include/QF/Vulkan/renderpass.h @@ -27,6 +27,12 @@ typedef struct qfv_subpassdependency_s #define QFV_AllocSubpassDependencies(num, allocator) \ DARRAY_ALLOCFIXED (qfv_subpassdependency_t, num, allocator) +typedef struct qfv_framebufferset_s + DARRAY_TYPE (VkFramebuffer) qfv_framebufferset_t; + +#define QFV_AllocFrameBuffers(num, allocator) \ + DARRAY_ALLOCFIXED (qfv_framebufferset_t, num, allocator) + struct qfv_device_s; struct qfv_imageviewset_s; VkRenderPass diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 4ddab99e3..dcf4f624b 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -8,20 +8,15 @@ #include "QF/darray.h" -typedef struct vulkan_renderpass_s { - VkRenderPass renderpass; - struct qfv_imageresource_s *colorImage; - struct qfv_imageresource_s *depthImage; -} vulkan_renderpass_t; - -typedef struct vulkan_framebuffer_s { +typedef struct vulkan_frame_s { VkFramebuffer framebuffer; VkFence fence; VkSemaphore imageAvailableSemaphore; VkSemaphore renderDoneSemaphore; VkCommandBuffer cmdBuffer; - struct qfv_cmdbufferset_s *subCommand; + int cmdSetCount; + struct qfv_cmdbufferset_s *cmdSets; } vulkan_frame_t; typedef struct vulkan_matrices_s { @@ -59,11 +54,22 @@ typedef struct vulkan_ctx_s { VkSurfaceKHR surface; //FIXME surface = window, so "contains" swapchain struct plitem_s *pipelineDef; + struct plitem_s *renderpassDef; + VkRenderPass renderpass; + struct qfv_imageset_s *attachment_images; + struct qfv_imageviewset_s *attachment_views; + VkDeviceMemory attachmentMemory; + + uint32_t swapImageIndex; + struct qfv_framebufferset_s *framebuffers; + struct hashtab_s *shaderModules; struct hashtab_s *setLayouts; struct hashtab_s *pipelineLayouts; struct hashtab_s *descriptorPools; struct hashtab_s *samplers; + struct hashtab_s *images; + struct hashtab_s *imageViews; struct aliasctx_s *alias_context; struct bspctx_s *bsp_context; @@ -72,7 +78,6 @@ typedef struct vulkan_ctx_s { VkCommandPool cmdpool; VkCommandBuffer cmdbuffer; VkFence fence; // for ctx->cmdbuffer only - vulkan_renderpass_t renderpass; struct qfv_stagebuf_s *staging; VkPipeline pipeline; size_t curFrame; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index cb0eec6d1..66db70d11 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -209,6 +209,8 @@ libs_video_renderer_vid_render_sw32_la_SOURCES=\ pipeline_src = libs/video/renderer/vulkan/qfpipeline.plist pipeline_gen = libs/video/renderer/vulkan/qfpipeline.plc +renderpass_src = libs/video/renderer/vulkan/deferred.plist +renderpass_gen = libs/video/renderer/vulkan/deferred.plc video_renderer_vulkan_libs = \ libs/models/libmodels_vulkan.la @@ -250,7 +252,7 @@ libs/video/renderer/vulkan/vkparse.lo: libs/video/renderer/vulkan/vkparse.c $(vk libs/video/renderer/vulkan/shader.lo: libs/video/renderer/vulkan/shader.c $(vkshader_c) -libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c $(vkparse_src) $(pipeline_gen) +libs/video/renderer/vulkan/vulkan_vid_common.lo: libs/video/renderer/vulkan/vulkan_vid_common.c $(vkparse_src) $(pipeline_gen) ${renderpass_gen} qwaq_curses = ruamoko/qwaq/qwaq-curses$(EXEEXT) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index a41a1d960..b8f9dc718 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -87,8 +87,9 @@ vulkan_R_Init (void) Vulkan_CreateStagingBuffers (vulkan_ctx); Vulkan_CreateMatrices (vulkan_ctx); Vulkan_CreateSwapchain (vulkan_ctx); - Vulkan_CreateFramebuffers (vulkan_ctx); + Vulkan_CreateFrames (vulkan_ctx); Vulkan_CreateRenderPass (vulkan_ctx); + Vulkan_CreateFramebuffers (vulkan_ctx); // FIXME this should be staged so screen updates can begin while pipelines // are being built vulkan_ctx->pipeline = Vulkan_CreatePipeline (vulkan_ctx, "pipeline"); @@ -111,6 +112,8 @@ vulkan_R_Init (void) static void vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) { + const VkSubpassContents subpassContents + = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS; static int count = 0; static double startTime; uint32_t imageIndex = 0; @@ -128,20 +131,9 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) QFV_AcquireNextImage (vulkan_ctx->swapchain, frame->imageAvailableSemaphore, 0, &imageIndex); + vulkan_ctx->swapImageIndex = imageIndex; - int attachCount = vulkan_ctx->msaaSamples > 1 ? 3 : 2; - __auto_type attachments = DARRAY_ALLOCFIXED (qfv_imageviewset_t, - attachCount, alloca); - qfv_swapchain_t *sc = vulkan_ctx->swapchain; - attachments->a[0] = sc->imageViews->a[imageIndex]; - attachments->a[1] = vulkan_ctx->renderpass.depthImage->view; - if (attachCount > 2) { - attachments->a[2] = vulkan_ctx->renderpass.colorImage->view; - } - - VkRenderPass renderpass = vulkan_ctx->renderpass.renderpass; - frame->framebuffer = QFV_CreateFramebuffer (device, renderpass, - attachments, sc->extent, 1); + frame->framebuffer = vulkan_ctx->framebuffers->a[imageIndex]; scr_3dfunc (); while (*scr_funcs) { @@ -160,20 +152,26 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) }; VkRenderPassBeginInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 0, - vulkan_ctx->renderpass.renderpass, 0, - { {0, 0}, sc->extent }, + vulkan_ctx->renderpass, 0, + { {0, 0}, vulkan_ctx->swapchain->extent }, 3, clearValues }; dfunc->vkBeginCommandBuffer (frame->cmdBuffer, &beginInfo); renderPassInfo.framebuffer = frame->framebuffer; dfunc->vkCmdBeginRenderPass (frame->cmdBuffer, &renderPassInfo, - VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + subpassContents); - dfunc->vkCmdExecuteCommands (frame->cmdBuffer, frame->subCommand->size, - frame->subCommand->a); - // reset for next time around - frame->subCommand->size = 0; + for (int i = 0; i < frame->cmdSetCount; i++) { + dfunc->vkCmdExecuteCommands (frame->cmdBuffer, frame->cmdSets[i].size, + frame->cmdSets[i].a); + // reset for next time around + frame->cmdSets[i].size = 0; + + if (i < frame->cmdSetCount) { + dfunc->vkCmdNextSubpass (frame->cmdBuffer, subpassContents); + } + } dfunc->vkCmdEndRenderPass (frame->cmdBuffer); dfunc->vkEndCommandBuffer (frame->cmdBuffer); diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist new file mode 100644 index 000000000..e7e7e1f12 --- /dev/null +++ b/libs/video/renderer/vulkan/deferred.plist @@ -0,0 +1,342 @@ +{ + images = { + depth = { + imageType = VK_IMAGE_TYPE_2D; //FIXME short form is 2d... + format = x8_d24_unorm_pack32; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = depth_stencil_attachment|input_attachment; + }; + color = { + imageType = VK_IMAGE_TYPE_2D; + format = r8g8b8a8_unorm; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment; + }; + normals = { + imageType = VK_IMAGE_TYPE_2D; + format = r16g16b16a16_sfloat; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment; + }; + opaque = { + imageType = VK_IMAGE_TYPE_2D; + format = r8g8b8a8_unorm; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment; + }; + translucent = { + imageType = VK_IMAGE_TYPE_2D; + format = r8g8b8a8_unorm; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment; + }; + }; + imageViews = { + depth = { + image = depth; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.depth.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = depth; + levelCount = 1; + layerCount = 1; + }; + }; + color = { + image = color; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.color.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + normals = { + image = normals; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.normals.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + opaque = { + image = opaque; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.opaque.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + translucent = { + image = translucent; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.translucent.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + }; + framebuffer = { + renderPass = renderpass; + attachments = (depth, color, normals, opaque, translucent, + "$swapchain.views[$swapImageIndex]"); + width = $swapchain.extent.width; + height = $swapchain.extent.height; + }; + renderpass = { + attachments = ( + { + format = $properties.images.depth.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = depth_stencil_attachment_optimal; + }, + { + format = $properties.images.color.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, + { + format = $properties.images.normals.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, + { + format = $properties.images.opaque.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, + { + format = $properties.images.translucent.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, + { + format = $swapchain.format; + samples = 1; + loadOp = clear; + storeOp = store; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = present_src_khr; + }, + ); + subpasses = ( + { // depth + pipelineBindPoint = graphics; + depthStencilAttachment = { + attachment = 0; + layout = depth_stencil_attachment_optimal; + }; + }, + { // g-buffer generation + pipelineBindPoint = graphics; + colorAttachments = ( + { // color + attachment = 1; + layout = color_attachment_optimal; + }, + { // normals + attachment = 2; + layout = color_attachment_optimal; + }, + ); + depthStencilAttachment = { + attachment = 0; + layout = depth_stencil_attachment_optimal; + }; + }, + { // lighting + pipelineBindPoint = graphics; + inputAttachments = ( + { // depth + attachment = 0; + layout = shader_read_only_optimal; + }, + { // color + attachment = 1; + layout = shader_read_only_optimal; + }, + { // normals + attachment = 2; + layout = shader_read_only_optimal; + }, + ); + colorAttachments = ( + { // opaque + attachment = 3; + layout = color_attachment_optimal; + }, + ); + }, + { // translucent + pipelineBindPoint = graphics; + colorAttachments = ( + { // translucent + attachment = 4; + layout = color_attachment_optimal; + }, + ); + }, + { // compose + pipelineBindPoint = graphics; + inputAttachments = ( + { // opaque + attachment = 3; + layout = shader_read_only_optimal; + }, + { // translucent + attachment = 4; + layout = shader_read_only_optimal; + }, + ); + colorAttachments = ( + { // swapchain + attachment = 5; + layout = color_attachment_optimal; + }, + ); + }, + ); + dependencies = ( + { + srcSubpass = 0; + dstSubpass = 1; + srcStageMask = color_attachment_output; + dstStageMask = fragment_shader; + srcAccessMask = color_attachment_write; + dstAccessMask = shader_read; + dependencyFlags = by_region; + }, + { + srcSubpass = 1; + dstSubpass = 2; + srcStageMask = color_attachment_output; + dstStageMask = fragment_shader; + srcAccessMask = color_attachment_write; + dstAccessMask = shader_read; + dependencyFlags = by_region; + }, + { + srcSubpass = 2; + dstSubpass = 4; + srcStageMask = color_attachment_output; + dstStageMask = fragment_shader; + srcAccessMask = color_attachment_write; + dstAccessMask = shader_read; + dependencyFlags = by_region; + }, + { + srcSubpass = 3; + dstSubpass = 4; + srcStageMask = color_attachment_output; + dstStageMask = fragment_shader; + srcAccessMask = color_attachment_write; + dstAccessMask = shader_read; + dependencyFlags = by_region; + }, + ); + }; +} diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 324e08e7c..2cd110385 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -273,7 +273,45 @@ }; }; pipelines = { - alias = { + alias_depth = { + stages = ( + { + stage = vertex; + name = main; + module = $builtin/alias.vert; + }, + ); + vertexInput = { + bindings = ( + "$properties.pipelines.alias_gbuf.vertexInput.bindings[0]", + "$properties.pipelines.alias_gbuf.vertexInput.bindings[1]", + ); + attributes = ( + "$properties.pipelines.alias_gbuf.vertexInput.attributes[0]", + "$properties.pipelines.alias_gbuf.vertexInput.attributes[1]", + "$properties.pipelines.alias_gbuf.vertexInput.attributes[2]", + "$properties.pipelines.alias_gbuf.vertexInput.attributes[3]", + ); + }; + inputAssembly = $properties.pipelines.alias_gbuf.inputAssembly; + viewport = $properties.pipelines.alias_gbuf.viewport; + rasterization = $properties.pipelines.alias_gbuf.rasterization; + multisample = $properties.pipelines.alias_gbuf.multisample; + depthStencil = { + depthTestEnable = true; + depthWriteEnable = true; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + colorBlend = $properties.pipelines.alias_gbuf.colorBlend; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = alias_layout; + //renderPass = renderpass; + }; + alias_gbuf = { stages = ( { stage = vertex; @@ -404,7 +442,41 @@ layout = alias_layout; //renderPass = renderpass; }; - quakebsp_main = { + bsp_depth = { + stages = ( + { + stage = vertex; + name = main; + module = $builtin/quakebsp.vert; + }, + ); + vertexInput = { + bindings = ( + "$properties.pipelines.bsp_gbuf.vertexInput.bindings[0]", + ); + attributes = ( + "$properties.pipelines.bsp_gbuf.vertexInput.attributes[0]", + ); + }; + inputAssembly = $properties.pipelines.bsp_main.inputAssembly; + viewport = $properties.pipelines.bsp_main.viewport; + rasterization = $properties.pipelines.bsp_main.rasterization; + multisample = $properties.pipelines.bsp_main.multisample; + depthStencil = { + depthTestEnable = true; + depthWriteEnable = true; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + colorBlend = $properties.pipelines.bsp_gbuf.colorBlend; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = quakebsp_layout; + //renderPass = renderpass; + }; + bsp_gbuf = { stages = ( { stage = vertex; @@ -523,86 +595,15 @@ }; }, ); - vertexInput = { - bindings = ( - { - binding = 0; - stride = "2 * 4 * 4"; - inputRate = vertex; - }, - ); - attributes = ( - { - location = 0; - binding = 0; - format = r32g32b32a32_sfloat; - offset = 0; - }, - { - location = 1; - binding = 0; - format = r32g32b32a32_sfloat; - offset = 16; - }, - ); - }; - inputAssembly = { - topology = triangle_fan; - primitiveRestartEnable = true; - }; - viewport = { - viewports = ( - { - x = 0; y = 0; - width = 640; height = 480; - minDepth = 0; maxDepth = 1; - } - ); - scissors = ( - { - offset = { x = 0; y = 0 }; - extent = { width = 640; height = 480; }; - }, - ); - }; - rasterization = { - depthClampEnable = false; - rasterizerDiscardEnable = false; - polygonMode = fill; - cullMode = back; - frontFace = clockwise; - depthBiasEnable = false; - lineWidth = 1; - }; - multisample = { - rasterizationSamples = $msaaSamples; - sampleShadingEnable = false; - minSampleShading = 0.5f; - alphaToCoverageEnable = false; - alphaToOneEnable = false; - }; - depthStencil = { - depthTestEnable = true; - depthWriteEnable = true; - depthCompareOp = less_or_equal; - depthBoundsTestEnable = false; - stencilTestEnable = false; - }; - colorBlend = { - logicOpEnable = false; - attachments = ({ - blendEnable = true; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }); - }; + vertexInput = $properties.pipelines.bsp_gbuf.vertexInput; + inputAssembly = $properties.pipelines.bsp_gbuf.inputAssembly; + viewport = $properties.pipelines.bsp_gbuf.viewport; + rasterization = $properties.pipelines.bsp_gbuf.rasterization; + multisample = $properties.pipelines.bsp_gbuf.multisample; + depthStencil = $properties.pipelines.bsp_gbuf.depthStencil; + colorBlend = $properties.pipelines.bsp_gbuf.colorBlend; dynamic = { - dynamicState = ( viewport, scissor, blend_constants ); + dynamicState = ( viewport, scissor ); }; layout = quakebsp_layout; //renderPass = renderpass; diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index ad2696c8f..2d9b3c806 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -460,7 +460,8 @@ parse_VkDescriptorSetLayout (const plfield_t *field, const plitem_t *item, ret = !cexpr_eval_string (name, &ectx); if (ret) { VkDescriptorSetLayout setLayout; - setLayout = QFV_ParseDescriptorSetLayout (ctx, setItem); + setLayout = QFV_ParseDescriptorSetLayout (ctx, setItem, + pctx->properties); *handle = (VkDescriptorSetLayout) setLayout; QFV_AddHandle (ctx->setLayouts, name, (uint64_t) setLayout); @@ -495,7 +496,7 @@ parse_VkPipelineLayout (const plitem_t *item, void **data, ret = !cexpr_eval_string (name, &ectx); if (ret) { VkPipelineLayout layout; - layout = QFV_ParsePipelineLayout (ctx, setItem); + layout = QFV_ParsePipelineLayout (ctx, setItem, context->properties); *handle = (VkPipelineLayout) layout; QFV_AddHandle (ctx->pipelineLayouts, name, (uint64_t) layout); @@ -503,6 +504,92 @@ parse_VkPipelineLayout (const plitem_t *item, void **data, return ret; } +static int +parse_VkImage (const plitem_t *item, void **data, plitem_t *messages, + parsectx_t *context) +{ + __auto_type handle = (VkImage *) data[0]; + int ret = 1; + exprctx_t ectx = *context->ectx; + vulkan_ctx_t *ctx = context->vctx; + + const char *name = PL_String (item); + Sys_Printf ("parse_VkImage: %s\n", name); + if (name[0] != '$') { + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".images.%s", name); + } + + *handle = (VkImage) QFV_GetHandle (ctx->images, name); + if (*handle) { + return 1; + } + + plitem_t *imageItem = 0; + exprval_t result = { &cexpr_plitem, &imageItem }; + ectx.symtab = 0; + ectx.result = &result; + ret = !cexpr_eval_string (name, &ectx); + if (ret) { + VkImage image; + image = QFV_ParseImage (ctx, imageItem, context->properties); + *handle = (VkImage) image; + + QFV_AddHandle (ctx->images, name, (uint64_t) image); + } + return ret; +} + +static exprtype_t imageview_type = { + "VkImageView", + sizeof (VkImageView), + 0, 0, 0 +}; + +static int +parse_VkImageView (const plfield_t *field, const plitem_t *item, void *data, + plitem_t *messages, void *_context) +{ + parsectx_t *context = _context; + __auto_type handle = (VkImageView *) data; + int ret = 1; + exprctx_t ectx = *context->ectx; + vulkan_ctx_t *ctx = context->vctx; + + const char *name = PL_String (item); + Sys_Printf ("parse_VkImageView: %s\n", name); + if (name[0] != '$') { + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".imageViews.%s", name); + } + + *handle = (VkImageView) QFV_GetHandle (ctx->imageViews, name); + if (*handle) { + return 1; + } + + exprval_t *value = 0; + exprval_t result = { &cexpr_exprval, &value }; + ectx.symtab = 0; + ectx.result = &result; + ret = !cexpr_eval_string (name, &ectx); + + plitem_t *imageViewItem = 0; + if (ret) { + VkImageView imageView; + if (value->type == &imageview_type) { + imageView = *(VkImageView *) value->value; + } else if (value->type == &cexpr_plitem) { + imageView = QFV_ParseImageView (ctx, imageViewItem, + context->properties); + QFV_AddHandle (ctx->imageViews, name, (uint64_t) imageView); + } else { + PL_Message (messages, item, "not a VkImageView"); + return 0; + } + *handle = (VkImageView) imageView; + } + return ret; +} + static const char * handleref_getkey (const void *hr, void *unused) { @@ -592,6 +679,36 @@ sampler_free (void *hr, void *_ctx) handleref_free (handleref, ctx); } +static void +image_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type image = (VkImage) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (image) { + dfunc->vkDestroyImage (device->dev, image, 0); + }; + handleref_free (handleref, ctx); +} + +static void +imageView_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type imageView = (VkImageView) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (imageView) { + dfunc->vkDestroyImageView (device->dev, imageView, 0); + }; + handleref_free (handleref, ctx); +} + static hashtab_t *enum_symtab; static int @@ -605,23 +722,71 @@ parse_BasePipeline (const plitem_t *item, void **data, #include "libs/video/renderer/vulkan/vkparse.cinc" -static exprsym_t imageset_symbols[] = { - {"size", &cexpr_size_t, (void *)field_offset (qfv_imageset_t, size)}, +static void +imageviewset_index (const exprval_t *a, size_t index, exprval_t *c, + exprctx_t *ctx) +{ + __auto_type set = *(qfv_imageviewset_t **) a->value; + exprval_t *val = 0; + if (index >= set->size) { + cexpr_error (ctx, "invalid index: %zd", index); + } else { + val = cexpr_value (&imageview_type, ctx); + *(VkImageView *) val->value = set->a[index]; + } + *(exprval_t **) c->value = val; +} + +static void +imageviewset_int (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + size_t index = *(int *) b->value; + imageviewset_index (a, index, c, ctx); +} + +static void +imageviewset_uint (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + size_t index = *(unsigned *) b->value; + imageviewset_index (a, index, c, ctx); +} + +static void +imageviewset_size_t (const exprval_t *a, const exprval_t *b, exprval_t *c, + exprctx_t *ctx) +{ + size_t index = *(size_t *) b->value; + imageviewset_index (a, index, c, ctx); +} + +binop_t imageviewset_binops[] = { + { '.', &cexpr_field, &cexpr_exprval, cexpr_struct_pointer_getfield }, + { '[', &cexpr_int, &imageview_type, imageviewset_int }, + { '[', &cexpr_uint, &imageview_type, imageviewset_uint }, + { '[', &cexpr_size_t, &imageview_type, imageviewset_size_t }, + {} +}; + +static exprsym_t imageviewset_symbols[] = { + {"size", &cexpr_size_t, (void *)field_offset (qfv_imageviewset_t, size)}, { } }; -static exprtab_t imageset_symtab = { - imageset_symbols, +static exprtab_t imageviewset_symtab = { + imageviewset_symbols, }; -exprtype_t imageset_type = { - "imageset", - sizeof (qfv_imageset_t *), - cexpr_struct_pointer_binops, +exprtype_t imageviewset_type = { + "imageviewset", + sizeof (qfv_imageviewset_t *), + imageviewset_binops, 0, - &imageset_symtab, + &imageviewset_symtab, }; static exprsym_t qfv_swapchain_t_symbols[] = { {"format", &VkFormat_type, (void *)field_offset (qfv_swapchain_t, format)}, - {"images", &imageset_type, (void *)field_offset (qfv_swapchain_t, images)}, + {"extent", &VkExtent2D_type, (void *)field_offset (qfv_swapchain_t, extent)}, + {"views", &imageviewset_type, (void *)field_offset (qfv_swapchain_t, imageViews)}, { } }; static exprtab_t qfv_swapchain_t_symtab = { @@ -714,7 +879,7 @@ QFV_InitParse (vulkan_ctx_t *ctx) vkgen_init_symtabs (&context); cexpr_init_symtab (&qfv_swapchain_t_symtab, &context); cexpr_init_symtab (&vulkan_frameset_t_symtab, &context); - cexpr_init_symtab (&imageset_symtab, &context); + cexpr_init_symtab (&imageviewset_symtab, &context); if (!ctx->setLayouts) { ctx->shaderModules = handlref_symtab (shaderModule_free, ctx); @@ -722,6 +887,8 @@ QFV_InitParse (vulkan_ctx_t *ctx) ctx->pipelineLayouts = handlref_symtab (pipelineLayout_free, ctx); ctx->descriptorPools = handlref_symtab (descriptorPool_free, ctx); ctx->samplers = handlref_symtab (sampler_free, ctx); + ctx->images = handlref_symtab (image_free, ctx); + ctx->imageViews = handlref_symtab (imageView_free, ctx); } } @@ -733,16 +900,17 @@ QFV_GetEnum (const char *name) static int parse_object (vulkan_ctx_t *ctx, plitem_t *plist, - plparser_t parser, void *object) + plparser_t parser, void *object, plitem_t *properties) { plitem_t *messages = PL_NewArray (); exprctx_t exprctx = {}; - parsectx_t parsectx = { &exprctx, ctx }; + parsectx_t parsectx = { &exprctx, ctx, properties }; exprsym_t var_syms[] = { {"swapchain", &qfv_swapchain_t_type, ctx->swapchain}, {"frames", &vulkan_frameset_t_type, &ctx->frames}, {"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples}, - {QFV_PROPERTIES, &cexpr_plitem, &ctx->pipelineDef}, + {"swapImageIndex", &cexpr_uint, &ctx->swapImageIndex}, + {QFV_PROPERTIES, &cexpr_plitem, &parsectx.properties}, {} }; exprtab_t vars_tab = { var_syms, 0 }; @@ -775,13 +943,14 @@ parse_qfv_renderpass (const plfield_t *field, const plitem_t *item, void *data, } VkRenderPass -QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) +QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) { qfv_device_t *device = ctx->device; qfv_renderpass_t renderpass_data = {}; - if (!parse_object (ctx, plist, parse_qfv_renderpass, &renderpass_data)) { + if (!parse_object (ctx, plist, parse_qfv_renderpass, &renderpass_data, + properties)) { return 0; } @@ -805,7 +974,7 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist) } VkPipeline -QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist) +QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) { qfv_device_t *device = ctx->device; @@ -813,11 +982,11 @@ QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist) memset (&cInfo->a[0], 0, sizeof (cInfo->a[0])); if (!parse_object (ctx, plist, parse_VkGraphicsPipelineCreateInfo, - &cInfo->a[0])) { + &cInfo->a[0], properties)) { return 0; } - cInfo->a[0].renderPass = ctx->renderpass.renderpass; + cInfo->a[0].renderPass = ctx->renderpass; __auto_type plSet = QFV_CreateGraphicsPipelines (device, 0, cInfo); VkPipeline pipeline = plSet->a[0]; free (plSet); @@ -825,14 +994,16 @@ QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist) } VkDescriptorPool -QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist) +QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; VkDescriptorPoolCreateInfo cInfo = {}; - if (!parse_object (ctx, plist, parse_VkDescriptorPoolCreateInfo, &cInfo)) { + if (!parse_object (ctx, plist, parse_VkDescriptorPoolCreateInfo, &cInfo, + properties)) { return 0; } @@ -843,7 +1014,8 @@ QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist) } VkDescriptorSetLayout -QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, plitem_t *plist) +QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; @@ -851,7 +1023,7 @@ QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, plitem_t *plist) VkDescriptorSetLayoutCreateInfo cInfo = {}; if (!parse_object (ctx, plist, parse_VkDescriptorSetLayoutCreateInfo, - &cInfo)) { + &cInfo, properties)) { return 0; } @@ -862,7 +1034,8 @@ QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, plitem_t *plist) } VkPipelineLayout -QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist) +QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; @@ -870,7 +1043,7 @@ QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist) VkPipelineLayoutCreateInfo cInfo = {}; if (!parse_object (ctx, plist, parse_VkPipelineLayoutCreateInfo, - &cInfo)) { + &cInfo, properties)) { return 0; } @@ -881,14 +1054,15 @@ QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist) } VkSampler -QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist) +QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; VkSamplerCreateInfo cInfo = {}; - if (!parse_object (ctx, plist, parse_VkSamplerCreateInfo, &cInfo)) { + if (!parse_object (ctx, plist, parse_VkSamplerCreateInfo, &cInfo, + properties)) { return 0; } @@ -897,3 +1071,195 @@ QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist) return sampler; } + +VkImage +QFV_ParseImage (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + VkImageCreateInfo cInfo = {}; + + if (!parse_object (ctx, plist, parse_VkImageCreateInfo, &cInfo, + properties)) { + return 0; + } + + VkImage image; + dfunc->vkCreateImage (device->dev, &cInfo, 0, &image); + + return image; +} + +VkImageView +QFV_ParseImageView (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + VkImageViewCreateInfo cInfo = {}; + + if (!parse_object (ctx, plist, parse_VkImageViewCreateInfo, &cInfo, + properties)) { + return 0; + } + + VkImageView imageView; + dfunc->vkCreateImageView (device->dev, &cInfo, 0, &imageView); + + return imageView; +} + +typedef struct { + uint32_t count; + VkImageCreateInfo *info; +} imagecreate_t; + +typedef struct { + uint32_t count; + VkImageViewCreateInfo *info; +} imageviewcreate_t; + +static plelement_t qfv_imagecreate_dict = { + QFDictionary, + sizeof (VkImageCreateInfo), + array_alloc, + parse_VkImageCreateInfo, +}; + +static plelement_t qfv_imageviewcreate_dict = { + QFDictionary, + sizeof (VkImageViewCreateInfo), + array_alloc, + parse_VkImageViewCreateInfo, +}; + +static int +parse_imagecreate_dict (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + plfield_t f = { "images", 0, QFArray, parse_array, + &qfv_imagecreate_dict }; + typedef struct arr_s DARRAY_TYPE(byte) arr_t; + arr_t *arr = 0; + int ret; + + if ((ret = PL_ParseLabeledArray (&f, item, &arr, messages, context))) { + imagecreate_t *imagecreate = data; + imagecreate->count = arr->size; + imagecreate->info = (VkImageCreateInfo *) arr->a; + } else { + //FIXME leaky boat when succeeds + if (arr) { + free (arr); + } + } + return ret; +} + +static int +parse_imageviewcreate_dict (const plfield_t *field, const plitem_t *item, + void *data, plitem_t *messages, void *context) +{ + plfield_t f = { "images", 0, QFArray, parse_array, + &qfv_imageviewcreate_dict }; + typedef struct arr_s DARRAY_TYPE(byte) arr_t; + arr_t *arr = 0; + int ret; + + if ((ret = PL_ParseLabeledArray (&f, item, &arr, messages, context))) { + imageviewcreate_t *imageviewcreate = data; + imageviewcreate->count = arr->size; + imageviewcreate->info = (VkImageViewCreateInfo *) arr->a; + } else { + //FIXME leaky boat when succeeds + if (arr) { + free (arr); + } + } + return ret; +} + +qfv_imageset_t * +QFV_ParseImageSet (vulkan_ctx_t *ctx, plitem_t *item, plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + imagecreate_t create = {}; + + pltype_t type = PL_Type (item); + + if (type == QFDictionary) { + if (!parse_object (ctx, item, parse_imagecreate_dict, &create, + properties)) { + return 0; + } + } else { + Sys_Printf ("Neither array nor dictionary: %d\n", PL_Line (item)); + return 0; + } + + __auto_type set = QFV_AllocImages (create.count, malloc); + for (uint32_t i = 0; i < create.count; i++) { + dfunc->vkCreateImage (device->dev, &create.info[i], 0, &set->a[i]); + + const char *name = PL_KeyAtIndex (item, i); + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".images.%s", name); + QFV_AddHandle (ctx->images, name, (uint64_t) set->a[i]); + } + + return set; +} + +qfv_imageviewset_t * +QFV_ParseImageViewSet (vulkan_ctx_t *ctx, plitem_t *item, + plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + imageviewcreate_t create = {}; + + pltype_t type = PL_Type (item); + + if (type == QFDictionary) { + if (!parse_object (ctx, item, parse_imageviewcreate_dict, &create, + properties)) { + return 0; + } + } else { + Sys_Printf ("Neither array nor dictionary: %d\n", PL_Line (item)); + return 0; + } + + __auto_type set = QFV_AllocImageViews (create.count, malloc); + for (uint32_t i = 0; i < create.count; i++) { + dfunc->vkCreateImageView (device->dev, &create.info[i], 0, &set->a[i]); + + const char *name = PL_KeyAtIndex (item, i); + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".imageViews.%s", name); + QFV_AddHandle (ctx->imageViews, name, (uint64_t) set->a[i]); + } + + return set; +} + +VkFramebuffer +QFV_ParseFramebuffer (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + VkFramebufferCreateInfo cInfo = {}; + + if (!parse_object (ctx, plist, parse_VkFramebufferCreateInfo, &cInfo, + properties)) { + return 0; + } + + VkFramebuffer framebuffer; + dfunc->vkCreateFramebuffer (device->dev, &cInfo, 0, &framebuffer); + + return framebuffer; +} diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index c443e98e3..f8aea8a7f 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -4,6 +4,8 @@ typedef struct parsectx_s { struct exprctx_s *ectx; struct vulkan_ctx_s *vctx; + struct plitem_s *properties; + void *data; } parsectx_t; #include "QF/cexpr.h" @@ -32,12 +34,29 @@ exprenum_t *QFV_GetEnum (const char *name); uint64_t QFV_GetHandle (struct hashtab_s *tab, const char *name); void QFV_AddHandle (struct hashtab_s *tab, const char *name, uint64_t handle); -VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist); -VkPipeline QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist); -VkDescriptorPool QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist); +VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +VkPipeline QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +VkDescriptorPool QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); VkDescriptorSetLayout QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, - plitem_t *plist); -VkPipelineLayout QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist); -VkSampler QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist); + plitem_t *plist, + plitem_t *properties); +VkPipelineLayout QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +VkSampler QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +VkImage QFV_ParseImage (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +VkImageView QFV_ParseImageView (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +struct qfv_imageset_s *QFV_ParseImageSet (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); +struct qfv_imageviewset_s *QFV_ParseImageViewSet (vulkan_ctx_t *ctx, + plitem_t *plist, + plitem_t *properties); +VkFramebuffer QFV_ParseFramebuffer (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); #endif//__vkparse_h diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index c3a0bfdd9..ced50835a 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -20,6 +20,9 @@ VkGraphicsPipelineCreateInfo, VkDescriptorPoolCreateInfo, VkSamplerCreateInfo, + VkImageCreateInfo, + VkImageViewCreateInfo, + VkFramebufferCreateInfo, ); parse = { VkSubpassDescription = { @@ -282,6 +285,48 @@ fields = (basePipelineHandle); }; basePipelineIndex = auto; + }; + VkImageCreateInfo = { + flags = auto; + imageType = auto; + format = auto; + extent = auto; + mipLevels = auto; + arrayLayers = auto; + samples = auto; + tiling = auto; + usage = auto; + sharingMode = skip; // FIXME for now + queueFamilyIndexCount = skip; // FIXME for now + pQueueFamilyIndices = skip; // FIXME for now + initialLayout = auto; + }; + VkImageViewCreateInfo = { + flags = auto; + image = { + type = (custom, (QFDictionary, QFString), + parse_VkImage); + fields = (image); + }; + viewType = auto; + format = auto; + components = auto; + subresourceRange = auto; + }; + VkFramebufferCreateInfo = { + //flags = auto; reserved for future use (Bits enum does not exist) + renderPass = { + type = (custom, QFString, parse_VkShaderModule); + fields = (renderPass); + }; + attachments = { + type = (array, VkImageView); + size = attachmentCount; + values = pAttachments; + }; + width = auto; + height = auto; + layers = auto; } } } diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 67598dc96..973e5445b 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -64,16 +64,65 @@ #include "r_internal.h" #include "vid_vulkan.h" -void -Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx) +static const char *alias_pass_names[] = { + "depth", + "g-buffer", + "translucent", +}; + +static void +emit_commands (VkCommandBuffer cmd, int pose1, int pose2, + qfv_alias_skin_t *skin, + void *vert_constants, int vert_size, + void *frag_constants, int frag_size, + aliashdr_t *hdr, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; aliasctx_t *actx = ctx->alias_context; aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + + __auto_type mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands); + + VkDeviceSize offsets[] = { + pose1 * hdr->poseverts * sizeof (aliasvrt_t), + pose2 * hdr->poseverts * sizeof (aliasvrt_t), + 0, + }; + VkBuffer buffers[] = { + mesh->vertex_buffer, + mesh->vertex_buffer, + mesh->uv_buffer, + }; + int bindingCount = skin ? 3 : 2; + + dfunc->vkCmdBindVertexBuffers (cmd, 0, bindingCount, buffers, offsets); + dfunc->vkCmdBindIndexBuffer (cmd, mesh->index_buffer, 0, + VK_INDEX_TYPE_UINT32); + dfunc->vkCmdPushConstants (cmd, actx->layout, VK_SHADER_STAGE_VERTEX_BIT, + 0, vert_size, vert_constants); + if (skin) { + dfunc->vkCmdPushConstants (cmd, actx->layout, + VK_SHADER_STAGE_FRAGMENT_BIT, + 68, frag_size, frag_constants); + aframe->imageInfo[0].imageView = skin->view; + dfunc->vkCmdPushDescriptorSetKHR (cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, + actx->layout, + 0, ALIAS_IMAGE_INFOS, + aframe->descriptors + + ALIAS_BUFFER_INFOS); + } + dfunc->vkCmdDrawIndexed (cmd, 3 * hdr->mdl.numtris, 1, 0, 0, 0); +} + +void +Vulkan_DrawAlias (entity_t *ent, vulkan_ctx_t *ctx) +{ + aliasctx_t *actx = ctx->alias_context; + aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; model_t *model = ent->model; aliashdr_t *hdr; - qfv_alias_mesh_t *mesh; qfv_alias_skin_t *skin; float vertex_constants[17]; byte fragment_constants[3][4]; @@ -81,7 +130,6 @@ Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx) if (!(hdr = model->aliashdr)) { hdr = Cache_Get (&model->cache); } - mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands); memcpy (vertex_constants, ent->transform, sizeof (ent->transform)); vertex_constants[16] = R_AliasGetLerpedFrames (ent, hdr); @@ -97,90 +145,26 @@ Vulkan_DrawAlias (entity_t *ent, struct vulkan_ctx_s *ctx) QuatCopy (skin->colora, fragment_constants[1]); QuatCopy (skin->colorb, fragment_constants[2]); - VkDeviceSize offsets[] = { - ent->pose1 * hdr->poseverts * sizeof (aliasvrt_t), - ent->pose2 * hdr->poseverts * sizeof (aliasvrt_t), - 0, - }; - VkBuffer buffers[] = { - mesh->vertex_buffer, - mesh->vertex_buffer, - mesh->uv_buffer, - }; - dfunc->vkCmdBindVertexBuffers (aframe->cmd, 0, 3, buffers, offsets); - dfunc->vkCmdBindIndexBuffer (aframe->cmd, mesh->index_buffer, 0, - VK_INDEX_TYPE_UINT32); - dfunc->vkCmdPushConstants (aframe->cmd, actx->layout, - VK_SHADER_STAGE_VERTEX_BIT, - 0, sizeof (vertex_constants), vertex_constants); - dfunc->vkCmdPushConstants (aframe->cmd, actx->layout, - VK_SHADER_STAGE_FRAGMENT_BIT, - 68, sizeof (fragment_constants), - fragment_constants); - aframe->imageInfo[0].imageView = skin->view; - dfunc->vkCmdPushDescriptorSetKHR (aframe->cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, - actx->layout, - 0, ALIAS_IMAGE_INFOS, - aframe->descriptors - + ALIAS_BUFFER_INFOS); - dfunc->vkCmdDrawIndexed (aframe->cmd, 3 * hdr->mdl.numtris, 1, 0, 0, 0); + emit_commands (aframe->cmdSet.a[QFV_aliasDepth], ent->pose1, ent->pose2, + 0, vertex_constants, sizeof (vertex_constants), + fragment_constants, sizeof (fragment_constants), + hdr, ctx); } static void -calc_lighting (qfv_light_t *light, entity_t *ent) -{ - vec3_t ambient_color; - //FIXME should be ent->position - float l = R_LightPoint (&r_worldentity.model->brush, r_origin) / 128.0; - - //XXX l = max (light, max (ent->model->min_light, ent->min_light)); - light->type = 2; - VectorSet (1, 1, 1, ambient_color); //FIXME - // position doubles as ambient light - VectorScale (ambient_color, l, light->position); - VectorSet (-1, 0, 0, light->direction); //FIXME - VectorCopy (light->position, light->color); -} - -void -Vulkan_AliasBegin (vulkan_ctx_t *ctx) +alias_begin_subpass (VkCommandBuffer cmd, VkPipeline pipeline, + vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; aliasctx_t *actx = ctx->alias_context; - - dlight_t *lights[ALIAS_LIGHTS]; - //XXX quat_t fog; - __auto_type cframe = &ctx->frames.a[ctx->curFrame]; aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; - VkCommandBuffer cmd = aframe->cmd; - DARRAY_APPEND (cframe->subCommand, cmd); - - //FIXME ambient needs to be per entity - aframe->lights->light_count = 1; - calc_lighting (&aframe->lights->lights[0], 0); - R_FindNearLights (r_origin, ALIAS_LIGHTS - 1, lights); - for (int i = 0; i < ALIAS_LIGHTS - 1; i++) { - if (!lights[i]) { - break; - } - aframe->lights->light_count++; - VectorCopy (lights[i]->color, aframe->lights->lights[i + 1].color); - VectorCopy (lights[i]->origin, aframe->lights->lights[i + 1].position); - aframe->lights->lights[i + 1].dist = lights[i]->radius; - aframe->lights->lights[i + 1].type = 0; - } - - //FIXME need per frame matrices - aframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; - aframe->bufferInfo[1].buffer = aframe->light_buffer; dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, - ctx->renderpass.renderpass, 0, + ctx->renderpass, 0, cframe->framebuffer, 0, 0, 0, }; @@ -192,7 +176,7 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx) dfunc->vkBeginCommandBuffer (cmd, &beginInfo); dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - actx->pipeline); + pipeline); //VkDescriptorSet sets[] = { // aframe->descriptors[0].dstSet, // aframe->descriptors[1].dstSet, @@ -213,15 +197,43 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx) //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; } -void -Vulkan_AliasEnd (vulkan_ctx_t *ctx) +static void +alias_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - aliasctx_t *actx = ctx->alias_context; + dfunc->vkEndCommandBuffer (cmd); +} + +void +Vulkan_AliasBegin (vulkan_ctx_t *ctx) +{ + aliasctx_t *actx = ctx->alias_context; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; - dfunc->vkEndCommandBuffer (aframe->cmd); + + //XXX quat_t fog; + DARRAY_APPEND (&cframe->cmdSets[QFV_passDepth], + aframe->cmdSet.a[QFV_aliasDepth]); + DARRAY_APPEND (&cframe->cmdSets[QFV_passGBuffer], + aframe->cmdSet.a[QFV_aliasGBuffer]); + + //FIXME need per frame matrices + aframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; + + alias_begin_subpass (aframe->cmdSet.a[QFV_aliasDepth], actx->depth, ctx); + alias_begin_subpass (aframe->cmdSet.a[QFV_aliasGBuffer], actx->gbuf, ctx); +} + +void +Vulkan_AliasEnd (vulkan_ctx_t *ctx) +{ + aliasctx_t *actx = ctx->alias_context; + aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + + alias_end_subpass (aframe->cmdSet.a[QFV_aliasDepth], ctx); + alias_end_subpass (aframe->cmdSet.a[QFV_aliasGBuffer], ctx); } static VkDescriptorBufferInfo base_buffer_info = { @@ -247,7 +259,6 @@ void Vulkan_Alias_Init (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; aliasctx_t *actx = calloc (1, sizeof (aliasctx_t)); ctx->alias_context = actx; @@ -257,7 +268,8 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) DARRAY_RESIZE (&actx->frames, frames); actx->frames.grow = 0; - actx->pipeline = Vulkan_CreatePipeline (ctx, "alias"); + actx->depth = Vulkan_CreatePipeline (ctx, "alias_depth"); + actx->gbuf = Vulkan_CreatePipeline (ctx, "alias_gbuf"); actx->layout = Vulkan_CreatePipelineLayout (ctx, "alias_layout"); actx->sampler = Vulkan_CreateSampler (ctx, "alias_sampler"); @@ -276,43 +288,22 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) }*/ //__auto_type pool = QFV_GetDescriptorPool (ctx, "alias.pool"); - __auto_type cmdBuffers = QFV_AllocCommandBufferSet (frames, alloca); - QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); - - __auto_type lbuffers = QFV_AllocBufferSet (frames, alloca); - for (size_t i = 0; i < frames; i++) { - lbuffers->a[i] = QFV_CreateBuffer (device, sizeof (qfv_light_buffer_t), - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, - lbuffers->a[i], - va (ctx->va_ctx, "buffer:alias:%s:%zd", - "lights", i)); - } - VkMemoryRequirements requirements; - dfunc->vkGetBufferMemoryRequirements (device->dev, lbuffers->a[0], - &requirements); - actx->light_memory = QFV_AllocBufferMemory (device, lbuffers->a[0], - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - frames * requirements.size, 0); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, - actx->light_memory, va (ctx->va_ctx, - "memory:alias:%s", "lights")); - byte *light_data; - dfunc->vkMapMemory (device->dev, actx->light_memory, 0, - frames * requirements.size, 0, (void **) &light_data); - //__auto_type sets = QFV_AllocateDescriptorSet (device, pool, layouts); for (size_t i = 0; i < frames; i++) { __auto_type aframe = &actx->frames.a[i]; - aframe->cmd = cmdBuffers->a[i]; - QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, - aframe->cmd, - va (ctx->va_ctx, "cmd:alias:%zd", i)); - aframe->light_buffer = lbuffers->a[i]; - aframe->lights = (qfv_light_buffer_t *) (light_data + i * requirements.size); - QFV_BindBufferMemory (device, lbuffers->a[i], actx->light_memory, - i * requirements.size); + DARRAY_INIT (&aframe->cmdSet, QFV_aliasNumPasses); + DARRAY_RESIZE (&aframe->cmdSet, QFV_aliasNumPasses); + aframe->cmdSet.grow = 0; + + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, &aframe->cmdSet); + + for (int j = 0; j < QFV_aliasNumPasses; j++) { + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + aframe->cmdSet.a[j], + va (ctx->va_ctx, "cmd:alias:%zd:%s", i, + alias_pass_names[j])); + } for (int j = 0; j < ALIAS_BUFFER_INFOS; j++) { aframe->bufferInfo[j] = base_buffer_info; aframe->descriptors[j] = base_buffer_write; @@ -333,7 +324,7 @@ Vulkan_Alias_Init (vulkan_ctx_t *ctx) } void -Vulkan_Alias_Shutdown (struct vulkan_ctx_s *ctx) +Vulkan_Alias_Shutdown (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; @@ -341,11 +332,11 @@ Vulkan_Alias_Shutdown (struct vulkan_ctx_s *ctx) for (size_t i = 0; i < actx->frames.size; i++) { __auto_type aframe = &actx->frames.a[i]; - dfunc->vkDestroyBuffer (device->dev, aframe->light_buffer, 0); + free (aframe->cmdSet.a); } - dfunc->vkFreeMemory (device->dev, actx->light_memory, 0); - dfunc->vkDestroyPipeline (device->dev, actx->pipeline, 0); - DARRAY_CLEAR (&actx->frames); + dfunc->vkDestroyPipeline (device->dev, actx->depth, 0); + dfunc->vkDestroyPipeline (device->dev, actx->gbuf, 0); + free (actx->frames.a); free (actx); } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 7028aa754..895caed49 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -69,6 +69,12 @@ #include "r_internal.h" #include "vid_vulkan.h" +static const char *bsp_pass_names[] = { + "depth", + "g-buffer", + "translucent", +}; + static float identity[] = { 1, 0, 0, 0, 0, 1, 0, 0, @@ -779,33 +785,44 @@ bind_view (qfv_bsp_tex tex, VkImageView view, bspframe_t *bframe, + BSP_BUFFER_INFOS); } +static void +push_transform (vec_t *transform, VkPipelineLayout layout, + qfv_devfuncs_t *dfunc, VkCommandBuffer cmd) +{ + dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_VERTEX_BIT, + 0, 16 * sizeof (float), transform); +} + +static void +push_fragconst (fragconst_t *fragconst, VkPipelineLayout layout, + qfv_devfuncs_t *dfunc, VkCommandBuffer cmd) +{ + dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_FRAGMENT_BIT, + 0, sizeof (fragconst_t), fragconst); +} + +static void +push_descriptors (int count, VkWriteDescriptorSet *descriptors, + VkPipelineLayout layout, qfv_devfuncs_t *dfunc, + VkCommandBuffer cmd) +{ + dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + layout, 0, count, descriptors); +} + static void draw_elechain (elechain_t *ec, VkPipelineLayout layout, qfv_devfuncs_t *dfunc, VkCommandBuffer cmd) { elements_t *el; - /*if (colloc >= 0) { - float *color; - color = ec->color; - if (!color) - color = bctx->default_color; - if (!QuatCompare (color, bctx->last_color)) { - QuatCopy (color, bctx->last_color); - qfeglVertexAttrib4fv (quake_bsp.color.location, color); - } - }*/ if (ec->transform) { - dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_VERTEX_BIT, - 0, 16 * sizeof (float), ec->transform); + push_transform (ec->transform, layout, dfunc, cmd); } else { //FIXME should cache current transform - dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_VERTEX_BIT, - 0, 16 * sizeof (float), identity); + push_transform (identity, layout, dfunc, cmd); } for (el = ec->elements; el; el = el->next) { - //FIXME check if these are contiguous and if so merge into one - //command if (!el->index_count) continue; dfunc->vkCmdDrawIndexed (cmd, el->index_count, 1, el->first_index, @@ -828,35 +845,18 @@ get_view (qfv_tex_t *tex, qfv_tex_t *default_tex) } static void -bsp_begin (vulkan_ctx_t *ctx) +bsp_begin_subpass (VkCommandBuffer cmd, VkPipeline pipeline, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; bspctx_t *bctx = ctx->bsp_context; - //XXX quat_t fog; - - bctx->default_color[3] = 1; - QuatCopy (bctx->default_color, bctx->last_color); - __auto_type cframe = &ctx->frames.a[ctx->curFrame]; bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; - VkCommandBuffer cmd = bframe->bsp_cmd; - DARRAY_APPEND (cframe->subCommand, cmd); - - //FIXME need per frame matrices - bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; - bframe->imageInfo[0].imageView = 0; // set by tex chain loop - bframe->imageInfo[1].imageView = 0; // set by tex chain loop - bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap); - bframe->imageInfo[3].imageView = get_view (bctx->skysheet_tex, - bctx->default_skysheet); - bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, - bctx->default_skybox); dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, - ctx->renderpass.renderpass, 0, + ctx->renderpass, 0, cframe->framebuffer, 0, 0, 0, }; @@ -868,7 +868,7 @@ bsp_begin (vulkan_ctx_t *ctx) dfunc->vkBeginCommandBuffer (cmd, &beginInfo); dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - bctx->main); + pipeline); VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); @@ -893,14 +893,54 @@ bsp_begin (vulkan_ctx_t *ctx) } static void -bsp_end (vulkan_ctx_t *ctx) +bsp_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; - bspctx_t *bctx = ctx->bsp_context; + dfunc->vkEndCommandBuffer (cmd); +} + +static void +bsp_begin (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + //XXX quat_t fog; + + bctx->default_color[3] = 1; + QuatCopy (bctx->default_color, bctx->last_color); + + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; - dfunc->vkEndCommandBuffer (bframe->bsp_cmd); + + DARRAY_APPEND (&cframe->cmdSets[QFV_passDepth], + bframe->cmdSet.a[QFV_bspDepth]); + DARRAY_APPEND (&cframe->cmdSets[QFV_passGBuffer], + bframe->cmdSet.a[QFV_bspGBuffer]); + + //FIXME need per frame matrices + bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; + bframe->imageInfo[0].imageView = 0; // set by tex chain loop + bframe->imageInfo[1].imageView = 0; // set by tex chain loop + bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap); + bframe->imageInfo[3].imageView = get_view (bctx->skysheet_tex, + bctx->default_skysheet); + bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, + bctx->default_skybox); + + //FIXME pipeline + bsp_begin_subpass (bframe->cmdSet.a[QFV_bspDepth], bctx->main, ctx); + bsp_begin_subpass (bframe->cmdSet.a[QFV_bspGBuffer], bctx->main, ctx); +} + +static void +bsp_end (vulkan_ctx_t *ctx) +{ + bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + + bsp_end_subpass (bframe->cmdSet.a[QFV_bspDepth], ctx); + bsp_end_subpass (bframe->cmdSet.a[QFV_bspGBuffer], ctx); } /*static void @@ -982,8 +1022,6 @@ spin (mat4_t mat, bspctx_t *bctx) static void sky_begin (vulkan_ctx_t *ctx) { - qfv_device_t *device = ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; bspctx_t *bctx = ctx->bsp_context; bctx->default_color[3] = 1; @@ -993,8 +1031,10 @@ sky_begin (vulkan_ctx_t *ctx) __auto_type cframe = &ctx->frames.a[ctx->curFrame]; bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; - VkCommandBuffer cmd = bframe->sky_cmd; - DARRAY_APPEND (cframe->subCommand, cmd); + + //FIXME where should skys go? g-buffer is overkill. Translucent pre-pass? + DARRAY_APPEND (&cframe->cmdSets[QFV_passTranslucent], + bframe->cmdSet.a[QFV_bspTranslucent]); //FIXME need per frame matrices bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; @@ -1006,54 +1046,18 @@ sky_begin (vulkan_ctx_t *ctx) bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, bctx->default_skybox); - dfunc->vkResetCommandBuffer (cmd, 0); - VkCommandBufferInheritanceInfo inherit = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, - ctx->renderpass.renderpass, 0, - cframe->framebuffer, - 0, 0, 0, - }; - VkCommandBufferBeginInfo beginInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT - | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, - }; - dfunc->vkBeginCommandBuffer (cmd, &beginInfo); - - dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - bctx->sky); - VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; - VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; - dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); - dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); - - VkDeviceSize offsets[] = { 0 }; - dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &bctx->vertex_buffer, offsets); - dfunc->vkCmdBindIndexBuffer (cmd, bctx->index_buffer, bframe->index_offset, - VK_INDEX_TYPE_UINT32); - - // push VP matrices - dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - bctx->layout, - 0, 1, bframe->descriptors + 0); - // push static images - dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - bctx->layout, - 0, 5, bframe->descriptors + 1); - - //XXX glsl_Fog_GetColor (fog); - //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; + //FIXME sky pass + bsp_begin_subpass (bframe->cmdSet.a[QFV_bspTranslucent], bctx->sky, ctx); } static void sky_end (vulkan_ctx_t *ctx) { - qfv_device_t *device = ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; bspctx_t *bctx = ctx->bsp_context; - bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; - dfunc->vkEndCommandBuffer (bframe->sky_cmd); + + //FIXME sky pass + bsp_end_subpass (bframe->cmdSet.a[QFV_bspTranslucent], ctx); } static inline void @@ -1133,13 +1137,13 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) Vulkan_FlushLightmaps (ctx); bsp_begin (ctx); - dfunc->vkCmdPushConstants (bframe->bsp_cmd, bctx->layout, - VK_SHADER_STAGE_VERTEX_BIT, - 0, 16 * sizeof (float), identity); + push_transform (identity, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspDepth]); + push_transform (identity, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspGBuffer]); fragconst_t frag_constants = { time: vr_data.realtime }; - dfunc->vkCmdPushConstants (bframe->bsp_cmd, bctx->layout, - VK_SHADER_STAGE_FRAGMENT_BIT, - 64, sizeof (fragconst_t), &frag_constants); + push_fragconst (&frag_constants, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspGBuffer]); //XXX qfeglActiveTexture (GL_TEXTURE0 + 0); for (size_t i = 0; i < bctx->texture_chains.size; i++) { vulktex_t *tex; @@ -1153,13 +1157,15 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) ctx->default_white); bframe->imageInfo[1].imageView = get_view (tex->glow, ctx->default_black); - dfunc->vkCmdPushDescriptorSetKHR (bframe->bsp_cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, - bctx->layout, - 0, 2, bframe->descriptors + 1); + + push_descriptors (2, bframe->descriptors + 1, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspGBuffer]); for (ec = tex->elechain; ec; ec = ec->next) { - draw_elechain (ec, bctx->layout, dfunc, bframe->bsp_cmd); + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspDepth]); + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspGBuffer]); } tex->elechain = 0; tex->elechain_tail = &tex->elechain; @@ -1246,22 +1252,24 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) return; sky_begin (ctx); - dfunc->vkCmdPushConstants (bframe->sky_cmd, bctx->layout, - VK_SHADER_STAGE_VERTEX_BIT, - 0, 16 * sizeof (float), identity); + //FIXME sky pass + push_transform (identity, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspTranslucent]); fragconst_t frag_constants = { time: vr_data.realtime }; - dfunc->vkCmdPushConstants (bframe->sky_cmd, bctx->layout, - VK_SHADER_STAGE_FRAGMENT_BIT, - 64, sizeof (fragconst_t), &frag_constants); + push_fragconst (&frag_constants, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspTranslucent]); for (is = bctx->sky_chain; is; is = is->tex_chain) { surf = is->surface; if (tex != surf->texinfo->texture->render) { if (tex) { bind_view (qfv_bsp_skysheet, get_view (tex->tex, ctx->default_black), - bframe, bframe->sky_cmd, bctx->layout, dfunc); + bframe, + bframe->cmdSet.a[QFV_bspTranslucent],//FIXME + bctx->layout, dfunc); for (ec = tex->elechain; ec; ec = ec->next) { - draw_elechain (ec, bctx->layout, dfunc, bframe->sky_cmd); + draw_elechain (ec, bctx->layout, dfunc,//FIXME + bframe->cmdSet.a[QFV_bspTranslucent]); } tex->elechain = 0; tex->elechain_tail = &tex->elechain; @@ -1271,11 +1279,12 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) add_surf_elements (tex, is, &ec, &el, bctx, bframe); } if (tex) { - bind_view (qfv_bsp_skysheet, - get_view (tex->tex, ctx->default_black), - bframe, bframe->sky_cmd, bctx->layout, dfunc); + bind_view (qfv_bsp_skysheet, get_view (tex->tex, ctx->default_black), + bframe, bframe->cmdSet.a[QFV_bspTranslucent],//FIXME + bctx->layout, dfunc); for (ec = tex->elechain; ec; ec = ec->next) { - draw_elechain (ec, bctx->layout, dfunc, bframe->sky_cmd); + draw_elechain (ec, bctx->layout, dfunc,//FIXME + bframe->cmdSet.a[QFV_bspTranslucent]); } tex->elechain = 0; tex->elechain_tail = &tex->elechain; @@ -1453,23 +1462,21 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bctx->layout = Vulkan_CreatePipelineLayout (ctx, "quakebsp_layout"); bctx->sampler = Vulkan_CreateSampler (ctx, "quakebsp_sampler"); - __auto_type cmdBuffers = QFV_AllocCommandBufferSet (3 * frames, alloca); - QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdBuffers); - for (size_t i = 0; i < frames; i++) { __auto_type bframe = &bctx->frames.a[i]; - bframe->bsp_cmd = cmdBuffers->a[i * 3 + 0]; - bframe->turb_cmd = cmdBuffers->a[i * 3 + 1]; - bframe->sky_cmd = cmdBuffers->a[i * 3 + 2]; - QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, - bframe->bsp_cmd, - va (ctx->va_ctx, "cmd:bsp:%zd", i)); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, - bframe->turb_cmd, - va (ctx->va_ctx, "cmd:turb:%zd", i)); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, - bframe->sky_cmd, - va (ctx->va_ctx, "cmd:sky:%zd", i)); + + DARRAY_INIT (&bframe->cmdSet, QFV_bspNumPasses); + DARRAY_RESIZE (&bframe->cmdSet, QFV_bspNumPasses); + bframe->cmdSet.grow = 0; + + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, &bframe->cmdSet); + + for (int j = 0; j < QFV_bspNumPasses; j++) { + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + bframe->cmdSet.a[i], + va (ctx->va_ctx, "cmd:bsp:%zd:%s", i, + bsp_pass_names[j])); + } for (int j = 0; j < BSP_BUFFER_INFOS; j++) { bframe->bufferInfo[j] = base_buffer_info; @@ -1495,6 +1502,11 @@ Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx) qfv_devfuncs_t *dfunc = device->funcs; bspctx_t *bctx = ctx->bsp_context; + for (size_t i = 0; i < bctx->frames.size; i++) { + __auto_type bframe = &bctx->frames.a[i]; + free (bframe->cmdSet.a); + } + dfunc->vkDestroyPipeline (device->dev, bctx->main, 0); dfunc->vkDestroyPipeline (device->dev, bctx->sky, 0); DARRAY_CLEAR (&bctx->texture_chains); diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 93b73d7b3..43b246273 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -696,7 +696,8 @@ Vulkan_FlushText (vulkan_ctx_t *ctx) drawframe_t *dframe = &dctx->frames.a[ctx->curFrame]; VkCommandBuffer cmd = dframe->cmd; - DARRAY_APPEND (cframe->subCommand, cmd); + //FIXME which pass? + DARRAY_APPEND (&cframe->cmdSets[QFV_passTranslucent], cmd); VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, @@ -708,7 +709,7 @@ Vulkan_FlushText (vulkan_ctx_t *ctx) dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, - ctx->renderpass.renderpass, 0, + ctx->renderpass, 0, cframe->framebuffer, 0, 0, 0 }; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 0132bf6d0..a6f444798 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -78,6 +78,10 @@ static const char quakeforge_pipeline[] = #include "libs/video/renderer/vulkan/qfpipeline.plc" ; +static const char quakeforge_renderpass[] = +#include "libs/video/renderer/vulkan/deferred.plc" +; + cvar_t *vulkan_frame_count; cvar_t *vulkan_presentation_mode; cvar_t *msaaSamples; @@ -163,6 +167,7 @@ void Vulkan_Init_Common (vulkan_ctx_t *ctx) { Sys_Printf ("Vulkan_Init_Common\n"); + QFV_InitParse (ctx); Vulkan_Init_Cvars (); ctx->instance = QFV_CreateInstance (ctx, PACKAGE_STRING, 0x000702ff, 0, instance_extensions);//FIXME version @@ -185,9 +190,9 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) QFV_DestroyPipeline (ctx->device, ctx->pipeline); } if (ctx->frames.size) { - Vulkan_DestroyFramebuffers (ctx); + Vulkan_DestroyFrames (ctx); } - if (ctx->renderpass.colorImage) { + if (ctx->renderpass) { Vulkan_DestroyRenderPass (ctx); } if (ctx->swapchain) { @@ -216,6 +221,15 @@ void Vulkan_CreateDevice (vulkan_ctx_t *ctx) { ctx->device = QFV_CreateDevice (ctx, device_extensions); + + //FIXME msaa and deferred rendering... + //also, location + ctx->msaaSamples = 1; + /*ctx->msaaSamples = min ((VkSampleCountFlagBits) msaaSamples->int_val, + QFV_GetMaxSampleCount (device->physDev)); + if (ctx->msaaSamples > 1) { + name = "renderpass_msaa"; + }*/ } void @@ -257,138 +271,54 @@ qfv_load_pipeline (vulkan_ctx_t *ctx, const char *name) return item; } +static plitem_t * +qfv_load_renderpass (vulkan_ctx_t *ctx, const char *name) +{ + if (!ctx->renderpassDef) { + ctx->renderpassDef = PL_GetPropertyList (quakeforge_renderpass, + &ctx->hashlinks); + } + + plitem_t *item = ctx->renderpassDef; + if (!item || !(item = PL_ObjectForKey (item, name))) { + Sys_Printf ("error loading %s\n", name); + } else { + Sys_Printf ("Found %s def\n", name); + } + return item; +} + +static size_t +get_image_size (VkImage image, qfv_device_t *device) +{ + qfv_devfuncs_t *dfunc = device->funcs; + size_t size; + size_t align; + + VkMemoryRequirements requirements; + dfunc->vkGetImageMemoryRequirements (device->dev, image, &requirements); + size = requirements.size; + align = requirements.alignment - 1; + size = (size + align) & ~(align); + return size; +} + void Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) { const char *name = "renderpass";//FIXME - qfv_device_t *device = ctx->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *df = device->funcs; - VkCommandBuffer cmd = ctx->cmdbuffer; - qfv_swapchain_t *sc = ctx->swapchain; - ctx->msaaSamples = min ((VkSampleCountFlagBits) msaaSamples->int_val, - QFV_GetMaxSampleCount (device->physDev)); - if (ctx->msaaSamples > 1) { - name = "renderpass_msaa"; - } + plitem_t *item = qfv_load_renderpass (ctx, name); - //FIXME a tad inconsistent - plitem_t *item = qfv_load_pipeline (ctx, name); - if (!item) { - return; - } - - qfv_imageresource_t *colorImage = malloc (sizeof (*colorImage)); - qfv_imageresource_t *depthImage = malloc (sizeof (*depthImage)); - - VkExtent3D extent = {sc->extent.width, sc->extent.height, 1}; - - Sys_MaskPrintf (SYS_VULKAN, "color resource\n"); - colorImage->image - = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, - sc->format, extent, 1, 1, ctx->msaaSamples, - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT - | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); - colorImage->object - = QFV_AllocImageMemory (device, colorImage->image, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); - QFV_BindImageMemory (device, colorImage->image, colorImage->object, 0); - colorImage->view - = QFV_CreateImageView (device, colorImage->image, - VK_IMAGE_VIEW_TYPE_2D, - sc->format, VK_IMAGE_ASPECT_COLOR_BIT); - Sys_MaskPrintf (SYS_VULKAN, " image: %p object: %p view:%p\n", - colorImage->image, colorImage->object, colorImage->view); - - Sys_MaskPrintf (SYS_VULKAN, "depth resource\n"); - VkFormat depthFormat = VK_FORMAT_D32_SFLOAT; - depthImage->image - = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D, - depthFormat, extent, 1, 1, ctx->msaaSamples, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); - depthImage->object - = QFV_AllocImageMemory (device, depthImage->image, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0, 0); - QFV_BindImageMemory (device, depthImage->image, depthImage->object, 0); - depthImage->view - = QFV_CreateImageView (device, depthImage->image, - VK_IMAGE_VIEW_TYPE_2D, - depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT); - Sys_MaskPrintf (SYS_VULKAN, " image: %p object: %p view:%p\n", - depthImage->image, depthImage->object, depthImage->view); - - VkImageMemoryBarrier barrier; - qfv_pipelinestagepair_t stages; - - df->vkWaitForFences (dev, 1, &ctx->fence, VK_TRUE, ~0ull); - df->vkResetCommandBuffer (cmd, 0); - VkCommandBufferBeginInfo beginInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0, - }; - df->vkBeginCommandBuffer (cmd, &beginInfo); - - stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_Color]; - barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_Color]; - barrier.image = colorImage->image; - - df->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, - 0, 0, - 0, 0, - 1, &barrier); - - stages = imageLayoutTransitionStages[qfv_LT_Undefined_to_DepthStencil]; - barrier = imageLayoutTransitionBarriers[qfv_LT_Undefined_to_DepthStencil]; - barrier.image = depthImage->image; - if (depthFormat == VK_FORMAT_D32_SFLOAT_S8_UINT - || depthFormat == VK_FORMAT_D24_UNORM_S8_UINT) { - barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - - df->vkCmdPipelineBarrier (cmd, stages.src, stages.dst, 0, - 0, 0, - 0, 0, - 1, &barrier); - df->vkEndCommandBuffer (cmd); - - VkSubmitInfo submitInfo = { - VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, - 0, 0, 0, - 1, &cmd, - 0, 0 - }; - df->vkResetFences (dev, 1, &ctx->fence); - df->vkQueueSubmit (device->queue.queue, 1, &submitInfo, ctx->fence); - - ctx->renderpass.colorImage = colorImage; - ctx->renderpass.depthImage = depthImage; - ctx->renderpass.renderpass = QFV_ParseRenderPass (ctx, item); + ctx->renderpass = QFV_ParseRenderPass (ctx, item, ctx->renderpassDef); QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_RENDER_PASS, - ctx->renderpass.renderpass, - va (ctx->va_ctx, "pipeline:%s", name)); + ctx->renderpass, va (ctx->va_ctx, "renderpass:%s", + name)); } void Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) { - qfv_device_t *device = ctx->device; - VkDevice dev = device->dev; - qfv_devfuncs_t *df = device->funcs; - - df->vkDestroyRenderPass (dev, ctx->renderpass.renderpass, 0); - - df->vkDestroyImageView (dev, ctx->renderpass.colorImage->view, 0); - df->vkDestroyImage (dev, ctx->renderpass.colorImage->image, 0); - df->vkFreeMemory (dev, ctx->renderpass.colorImage->object, 0); - free (ctx->renderpass.colorImage); - ctx->renderpass.colorImage = 0; - - df->vkDestroyImageView (dev, ctx->renderpass.depthImage->view, 0); - df->vkDestroyImage (dev, ctx->renderpass.depthImage->image, 0); - df->vkFreeMemory (dev, ctx->renderpass.depthImage->object, 0); - free (ctx->renderpass.depthImage); - ctx->renderpass.depthImage = 0; } VkPipeline @@ -401,7 +331,7 @@ Vulkan_CreatePipeline (vulkan_ctx_t *ctx, const char *name) } else { Sys_Printf ("Found pipeline def %s\n", name); } - VkPipeline pipeline = QFV_ParsePipeline (ctx, item); + VkPipeline pipeline = QFV_ParsePipeline (ctx, item, ctx->pipelineDef); QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_PIPELINE, pipeline, va (ctx->va_ctx, "pipeline:%s", name)); return pipeline; @@ -425,7 +355,7 @@ Vulkan_CreateDescriptorPool (vulkan_ctx_t *ctx, const char *name) } else { Sys_Printf ("Found descriptor pool def %s\n", name); } - pool = QFV_ParseDescriptorPool (ctx, item); + pool = QFV_ParseDescriptorPool (ctx, item, ctx->pipelineDef); QFV_AddHandle (tab, path, (uint64_t) pool); QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_DESCRIPTOR_POOL, pool, va (ctx->va_ctx, "descriptor_pool:%s", name)); @@ -450,7 +380,7 @@ Vulkan_CreatePipelineLayout (vulkan_ctx_t *ctx, const char *name) } else { Sys_Printf ("Found pipeline layout def %s\n", name); } - layout = QFV_ParsePipelineLayout (ctx, item); + layout = QFV_ParsePipelineLayout (ctx, item, ctx->pipelineDef); QFV_AddHandle (tab, path, (uint64_t) layout); QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, layout, va (ctx->va_ctx, "pipeline_layout:%s", name)); @@ -475,7 +405,7 @@ Vulkan_CreateSampler (vulkan_ctx_t *ctx, const char *name) } else { Sys_Printf ("Found sampler def %s\n", name); } - sampler = QFV_ParseSampler (ctx, item); + sampler = QFV_ParseSampler (ctx, item, ctx->pipelineDef); QFV_AddHandle (tab, path, (uint64_t) sampler); QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_SAMPLER, sampler, va (ctx->va_ctx, "sampler:%s", name)); @@ -500,7 +430,7 @@ Vulkan_CreateDescriptorSetLayout(vulkan_ctx_t *ctx, const char *name) } else { Sys_Printf ("Found descriptor set def %s\n", name); } - set = QFV_ParseDescriptorSetLayout (ctx, item); + set = QFV_ParseDescriptorSetLayout (ctx, item, ctx->pipelineDef); QFV_AddHandle (tab, path, (uint64_t) set); QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, set, va (ctx->va_ctx, "descriptor_set:%s", name)); @@ -508,7 +438,7 @@ Vulkan_CreateDescriptorSetLayout(vulkan_ctx_t *ctx, const char *name) } void -Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) +Vulkan_CreateFrames (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; VkCommandPool cmdpool = ctx->cmdpool; @@ -531,13 +461,16 @@ Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) frame->renderDoneSemaphore = QFV_CreateSemaphore (device); frame->cmdBuffer = cmdBuffers->a[i]; - frame->subCommand = malloc (sizeof (qfv_cmdbufferset_t)); - DARRAY_INIT (frame->subCommand, 4); + frame->cmdSetCount = QFV_NumPasses; + frame->cmdSets = malloc (QFV_NumPasses * sizeof (qfv_cmdbufferset_t)); + for (int j = 0; j < QFV_NumPasses; j++) { + DARRAY_INIT (&frame->cmdSets[j], 4); + } } } void -Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx) +Vulkan_DestroyFrames (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *df = device->funcs; @@ -553,3 +486,59 @@ Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx) DARRAY_CLEAR (&ctx->frames); } + +void +Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + plitem_t *item = qfv_load_renderpass (ctx, "images"); + if (!item) { + return; + } + + __auto_type images = QFV_ParseImageSet (ctx, item, ctx->renderpassDef); + ctx->attachment_images = images; + size_t memSize = 0; + for (size_t i = 0; i < images->size; i++) { + memSize += get_image_size (images->a[i], device); + } + VkDeviceMemory mem; + mem = QFV_AllocImageMemory (device, images->a[0], + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + memSize, 0); + ctx->attachmentMemory = mem; + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + mem, "memory:framebuffers"); + size_t offset = 0; + for (size_t i = 0; i < images->size; i++) { + QFV_BindImageMemory (device, images->a[i], mem, offset); + offset += get_image_size (images->a[i], device); + } + + item = qfv_load_renderpass (ctx, "imageViews"); + if (!item) { + return; + } + + __auto_type views = QFV_ParseImageViewSet (ctx, item, ctx->renderpassDef); + ctx->attachment_views = views; + + item = qfv_load_renderpass (ctx, "framebuffer"); + if (!item) { + return; + } + + ctx->framebuffers = QFV_AllocFrameBuffers (ctx->swapchain->numImages, + malloc); + for (size_t i = 0; i < ctx->framebuffers->size; i++) { + ctx->swapImageIndex = i; + ctx->framebuffers->a[i] = QFV_ParseFramebuffer (ctx, item, + ctx->renderpassDef); + } +} + +void +Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx) +{ +} From 4bda49d79867d3139093994cb4e20d5085348bbd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 17 Feb 2021 13:29:53 +0900 Subject: [PATCH 353/435] [util] Correct the lex priority for int constants The actual need to specify unsigned int constant is a bit of a pain, but not being able to do so due to lex priority errors is even more of a pain. --- libs/util/cexpr-lex.l | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/util/cexpr-lex.l b/libs/util/cexpr-lex.l index 46fbcdd55..b82724af4 100644 --- a/libs/util/cexpr-lex.l +++ b/libs/util/cexpr-lex.l @@ -120,13 +120,13 @@ STRING \"(\\.|[^"\\])*\" __auto_type context = yyget_extra (yyscanner); %} -{INT}+ { - yylval->value = parse_int (yytext, context); +{INT}+[uU] { + yylval->value = parse_uint (yytext, context); return VALUE; } -{INT}+[uU] { - yylval->value = parse_uint (yytext, context); +{INT}+ { + yylval->value = parse_int (yytext, context); return VALUE; } From b08c3881b9988876e71e722b8d7afe9e953504c0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 17 Feb 2021 13:32:04 +0900 Subject: [PATCH 354/435] [vulkan] Add a comment about using size_t Due to wanting to access array sizes when parsing uint32_t type values, parse_uint32_t needs to handle size_t values even though it throws out any excess bits. --- libs/video/renderer/vulkan/vkparse.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 2d9b3c806..ee8efb8a4 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -182,9 +182,11 @@ parse_uint32_t (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context) { int ret = 1; + // use size_t (and cexpr_size_t) for val so references to array sizes + // can be used size_t val = 0; - exprctx_t ectx = *((parsectx_t *) context)->ectx; exprval_t result = { &cexpr_size_t, &val }; + exprctx_t ectx = *((parsectx_t *) context)->ectx; ectx.symtab = 0; ectx.result = &result; const char *valstr = PL_String (item); From 64740b0f730257255892bb7160761ef60a813a88 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 17 Feb 2021 13:35:19 +0900 Subject: [PATCH 355/435] [vulkan] Create shaders for alias deferred rendering A simple (no uv output) vertex shader that still blends the two frames, and the relevant g-buffer fragment shader. --- libs/video/renderer/Makemodule.am | 10 ++++++ libs/video/renderer/vulkan/qfpipeline.plist | 10 +++--- libs/video/renderer/vulkan/shader.c | 6 ++++ .../renderer/vulkan/shader/alias_depth.vert | 28 ++++++++++++++++ .../renderer/vulkan/shader/alias_gbuf.frag | 32 +++++++++++++++++++ 5 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 libs/video/renderer/vulkan/shader/alias_depth.vert create mode 100644 libs/video/renderer/vulkan/shader/alias_gbuf.frag diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 66db70d11..4194b1f8b 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -278,6 +278,10 @@ aliasv_src = $(vkshaderpath)/alias.vert aliasv_c = $(vkshaderpath)/alias.vert.spvc aliasf_src = $(vkshaderpath)/alias.frag aliasf_c = $(vkshaderpath)/alias.frag.spvc +alias_depth_src = $(vkshaderpath)/alias_depth.vert +alias_depth_c = $(vkshaderpath)/alias_depth.vert.spvc +alias_gbuf_src = $(vkshaderpath)/alias_gbuf.frag +alias_gbuf_c = $(vkshaderpath)/alias_gbuf.frag.spvc passthrough_src = $(vkshaderpath)/passthrough.vert passthrough_c = $(vkshaderpath)/passthrough.vert.spvc pushcolor_src = $(vkshaderpath)/pushcolor.frag @@ -293,8 +297,12 @@ $(quakebspf_c): $(quakebspf_src) $(aliasv_c): $(aliasv_src) +$(alias_depth_c): $(alias_depth_src) + $(aliasf_c): $(aliasf_src) +$(alias_gbuf_c): $(alias_gbuf_src) + $(passthrough_c): $(passthrough_src) $(pushcolor_c): $(pushcolor_src) @@ -305,7 +313,9 @@ vkshader_c = \ $(quakebspv_c) \ $(quakebspf_c) \ $(aliasv_c) \ + $(alias_depth_c) \ $(aliasf_c) \ + $(alias_gbuf_c) \ $(passthrough_c) \ $(pushcolor_c) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 2cd110385..faf35b779 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -278,7 +278,7 @@ { stage = vertex; name = main; - module = $builtin/alias.vert; + module = $builtin/alias_depth.vert; }, ); vertexInput = { @@ -321,7 +321,7 @@ { stage = fragment; name = main; - module = $builtin/alias.frag; + module = $builtin/alias_gbuf.frag; specializationInfo = { mapEntries = ( { size = 4; offset = 0; constantID = 0; }, @@ -447,7 +447,7 @@ { stage = vertex; name = main; - module = $builtin/quakebsp.vert; + module = $builtin/bsp_depth.vert; }, ); vertexInput = { @@ -481,12 +481,12 @@ { stage = vertex; name = main; - module = $builtin/quakebsp.vert; + module = $builtin/bsp_gbuf.vert; }, { stage = fragment; name = main; - module = $builtin/quakebsp.frag; + module = $builtin/bsp_gbuf.frag; }, ); vertexInput = { diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index 90a93684b..857d457d4 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -65,8 +65,12 @@ static static #include "libs/video/renderer/vulkan/shader/alias.vert.spvc" static +#include "libs/video/renderer/vulkan/shader/alias_depth.vert.spvc" +static #include "libs/video/renderer/vulkan/shader/alias.frag.spvc" static +#include "libs/video/renderer/vulkan/shader/alias_gbuf.frag.spvc" +static #include "libs/video/renderer/vulkan/shader/passthrough.vert.spvc" static #include "libs/video/renderer/vulkan/shader/pushcolor.frag.spvc" @@ -83,7 +87,9 @@ static shaderdata_t builtin_shaders[] = { { "quakebsp.vert", quakebsp_vert, sizeof (quakebsp_vert) }, { "quakebsp.frag", quakebsp_frag, sizeof (quakebsp_frag) }, { "alias.vert", alias_vert, sizeof (alias_vert) }, + { "alias_depth.vert", alias_depth_vert, sizeof (alias_depth_vert) }, { "alias.frag", alias_frag, sizeof (alias_frag) }, + { "alias_gbuf.frag", alias_gbuf_frag, sizeof (alias_gbuf_frag) }, { "passthrough.vert", passthrough_vert, sizeof (passthrough_vert) }, { "pushcolor.frag", pushcolor_frag, sizeof (pushcolor_frag) }, {} diff --git a/libs/video/renderer/vulkan/shader/alias_depth.vert b/libs/video/renderer/vulkan/shader/alias_depth.vert new file mode 100644 index 000000000..44437788e --- /dev/null +++ b/libs/video/renderer/vulkan/shader/alias_depth.vert @@ -0,0 +1,28 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + +layout (push_constant) uniform PushConstants { + mat4 Model; + float blend; +}; + +layout (location = 0) in vec4 vertexa; +layout (location = 1) in vec3 normala; +layout (location = 2) in vec4 vertexb; +layout (location = 3) in vec3 normalb; + +void +main (void) +{ + vec4 vertex; + vec4 pos; + + vertex = mix (vertexa, vertexb, blend); + pos = (Model * vertex); + gl_Position = Projection * (View * pos); +} diff --git a/libs/video/renderer/vulkan/shader/alias_gbuf.frag b/libs/video/renderer/vulkan/shader/alias_gbuf.frag new file mode 100644 index 000000000..e8b14a305 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/alias_gbuf.frag @@ -0,0 +1,32 @@ +#version 450 +layout (set = 0, binding = 2) uniform sampler2DArray Skin; + +layout (push_constant) uniform PushConstants { + layout (offset = 68) + uint base_color; + uint colorA; + uint colorB; + vec4 fog; + vec4 color; +}; + +layout (location = 0) in vec2 st; +layout (location = 1) in vec3 position; +layout (location = 2) in vec3 normal; + +layout (location = 0) out vec4 frag_color; +layout (location = 1) out vec4 frag_normal; + +void +main (void) +{ + vec4 c; + int i; + vec3 light = vec3 (0); + c = texture (Skin, vec3 (st, 0)) * unpackUnorm4x8(base_color); + c += texture (Skin, vec3 (st, 1)) * unpackUnorm4x8(colorA); + c += texture (Skin, vec3 (st, 2)) * unpackUnorm4x8(colorB); + + frag_color = c; + frag_normal = vec4(normal, 0); +} From 4245c6ad3bcc0f460dbe34a23df28d3a1dcd5008 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 17 Feb 2021 13:50:36 +0900 Subject: [PATCH 356/435] [vulkan] Specify subpass number in pipeline def This gets the alias model render pass and pipeline passing validation. I don't know why I didn't add the subpass field to the VkGraphicsPipelineCreateInfo parser def, though it could be I simply missed it, or I thought I wouldn't need it at the time. --- libs/video/renderer/vulkan/qfpipeline.plist | 34 +++++++++++++++------ libs/video/renderer/vulkan/vkparse.plist | 1 + 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index faf35b779..2892f5fec 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -274,6 +274,7 @@ }; pipelines = { alias_depth = { + subpass = 0; stages = ( { stage = vertex; @@ -312,6 +313,7 @@ //renderPass = renderpass; }; alias_gbuf = { + subpass = 1; stages = ( { stage = vertex; @@ -425,16 +427,28 @@ }; colorBlend = { logicOpEnable = false; - attachments = ({ - blendEnable = true; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }); + attachments = ( + { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }, + { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }, + ); }; dynamic = { dynamicState = ( viewport, scissor, blend_constants ); diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index ced50835a..9eb5e7e04 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -280,6 +280,7 @@ type = (custom, QFString, parse_VkPipelineLayout); fields = (layout); }; + subpass = auto; basePipelineHandle = { type = (custom, QFString, parse_BasePipeline); fields = (basePipelineHandle); From cbc8ad271ab50e842e18c0aefa021de45b73a674 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 19 Feb 2021 11:14:54 +0900 Subject: [PATCH 357/435] [vulkan] Convert bsp and draw to deferred This has bsp and draw passing muster with the validation layers. --- include/QF/Vulkan/qf_alias.h | 6 +- include/QF/Vulkan/qf_bsp.h | 7 +- include/QF/Vulkan/qf_vid.h | 2 +- libs/video/renderer/Makemodule.am | 21 +++ libs/video/renderer/vulkan/device.c | 4 +- libs/video/renderer/vulkan/qfpipeline.plist | 60 ++++++--- libs/video/renderer/vulkan/shader.c | 12 ++ .../renderer/vulkan/shader/bsp_depth.vert | 19 +++ .../renderer/vulkan/shader/bsp_gbuf.frag | 126 ++++++++++++++++++ .../renderer/vulkan/shader/bsp_gbuf.geom | 29 ++++ .../renderer/vulkan/shader/bsp_gbuf.vert | 25 ++++ libs/video/renderer/vulkan/vulkan_alias.c | 9 +- libs/video/renderer/vulkan/vulkan_bsp.c | 21 +-- libs/video/renderer/vulkan/vulkan_draw.c | 2 +- 14 files changed, 304 insertions(+), 39 deletions(-) create mode 100644 libs/video/renderer/vulkan/shader/bsp_depth.vert create mode 100644 libs/video/renderer/vulkan/shader/bsp_gbuf.frag create mode 100644 libs/video/renderer/vulkan/shader/bsp_gbuf.geom create mode 100644 libs/video/renderer/vulkan/shader/bsp_gbuf.vert diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index 597888a4d..5f3964a2b 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -65,13 +65,13 @@ typedef struct qfv_alias_skin_s { #define ALIAS_BUFFER_INFOS 1 #define ALIAS_IMAGE_INFOS 1 -enum { +typedef enum { QFV_aliasDepth, QFV_aliasGBuffer, - //QFV_aliasTranslucent, + QFV_aliasTranslucent, QFV_aliasNumPasses -}; +} QFV_AliasSubpass; typedef struct aliasframe_s { qfv_cmdbufferset_t cmdSet; diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index b78aaf643..ff3f6612a 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -70,13 +70,13 @@ typedef enum { // Texture, GlowMap, LightMap, SkySheet, SkyCube #define BSP_IMAGE_INFOS 5 -enum { +typedef enum { QFV_bspDepth, QFV_bspGBuffer, QFV_bspTranslucent, QFV_bspNumPasses -}; +} QFV_BspSubpass; typedef struct bspframe_s { uint32_t *index_data; // pointer into mega-buffer for this frame (c) @@ -143,7 +143,8 @@ typedef struct bspctx_s { VkSampler sampler; VkDeviceMemory texture_memory; - VkPipeline main; + VkPipeline depth; + VkPipeline gbuf; VkPipeline sky; VkPipelineLayout layout; size_t vertex_buffer_size; diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index f81e934a1..db423d014 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -39,8 +39,8 @@ enum { QFV_passDepth, // geometry QFV_passGBuffer, // geometry - QFV_passTranslucent, // geometry QFV_passLighting, // single quad + QFV_passTranslucent, // geometry QFV_passCompose, // single quad QFV_NumPasses diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 4194b1f8b..a5c3fc1a0 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -274,6 +274,15 @@ quakebspv_src = $(vkshaderpath)/quakebsp.vert quakebspv_c = $(vkshaderpath)/quakebsp.vert.spvc quakebspf_src = $(vkshaderpath)/quakebsp.frag quakebspf_c = $(vkshaderpath)/quakebsp.frag.spvc + +bsp_depth_src = $(vkshaderpath)/bsp_depth.vert +bsp_depth_c = $(vkshaderpath)/bsp_depth.vert.spvc +bsp_gbufv_src = $(vkshaderpath)/bsp_gbuf.vert +bsp_gbufv_c = $(vkshaderpath)/bsp_gbuf.vert.spvc +bsp_gbufg_src = $(vkshaderpath)/bsp_gbuf.geom +bsp_gbufg_c = $(vkshaderpath)/bsp_gbuf.geom.spvc +bsp_gbuff_src = $(vkshaderpath)/bsp_gbuf.frag +bsp_gbuff_c = $(vkshaderpath)/bsp_gbuf.frag.spvc aliasv_src = $(vkshaderpath)/alias.vert aliasv_c = $(vkshaderpath)/alias.vert.spvc aliasf_src = $(vkshaderpath)/alias.frag @@ -295,6 +304,14 @@ $(quakebspv_c): $(quakebspv_src) $(quakebspf_c): $(quakebspf_src) +$(bsp_depth_c): $(bsp_depth_src) + +$(bsp_gbufv_c): $(bsp_gbufv_src) + +$(bsp_gbufg_c): $(bsp_gbufg_src) + +$(bsp_gbuff_c): $(bsp_gbuff_src) + $(aliasv_c): $(aliasv_src) $(alias_depth_c): $(alias_depth_src) @@ -312,6 +329,10 @@ vkshader_c = \ $(twodf_c) \ $(quakebspv_c) \ $(quakebspf_c) \ + $(bsp_depth_c) \ + $(bsp_gbufv_c) \ + $(bsp_gbufg_c) \ + $(bsp_gbuff_c) \ $(aliasv_c) \ $(alias_depth_c) \ $(aliasf_c) \ diff --git a/libs/video/renderer/vulkan/device.c b/libs/video/renderer/vulkan/device.c index 4cfceb999..58e04c110 100644 --- a/libs/video/renderer/vulkan/device.c +++ b/libs/video/renderer/vulkan/device.c @@ -167,7 +167,9 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions) VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0, family, 1, &priority }; - VkPhysicalDeviceFeatures features = {}; + VkPhysicalDeviceFeatures features = { + .geometryShader = 1, + }; VkDeviceCreateInfo dCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0, 1, &qCreateInfo, diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 2892f5fec..d71ce6037 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -457,6 +457,7 @@ //renderPass = renderpass; }; bsp_depth = { + subpass = 0; stages = ( { stage = vertex; @@ -472,10 +473,10 @@ "$properties.pipelines.bsp_gbuf.vertexInput.attributes[0]", ); }; - inputAssembly = $properties.pipelines.bsp_main.inputAssembly; - viewport = $properties.pipelines.bsp_main.viewport; - rasterization = $properties.pipelines.bsp_main.rasterization; - multisample = $properties.pipelines.bsp_main.multisample; + inputAssembly = $properties.pipelines.bsp_gbuf.inputAssembly; + viewport = $properties.pipelines.bsp_gbuf.viewport; + rasterization = $properties.pipelines.bsp_gbuf.rasterization; + multisample = $properties.pipelines.bsp_gbuf.multisample; depthStencil = { depthTestEnable = true; depthWriteEnable = true; @@ -491,12 +492,18 @@ //renderPass = renderpass; }; bsp_gbuf = { + subpass = 1; stages = ( { stage = vertex; name = main; module = $builtin/bsp_gbuf.vert; }, + { + stage = geometry; + name = main; + module = $builtin/bsp_gbuf.geom; + }, { stage = fragment; name = main; @@ -570,16 +577,28 @@ }; colorBlend = { logicOpEnable = false; - attachments = ({ - blendEnable = true; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }); + attachments = ( + { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }, + { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + } + ); }; dynamic = { dynamicState = ( viewport, scissor, blend_constants ); @@ -587,17 +606,23 @@ layout = quakebsp_layout; //renderPass = renderpass; }; - quakebsp_skysheet = { + bsp_skysheet = { + subpass = 1; stages = ( { stage = vertex; name = main; - module = $builtin/quakebsp.vert; + module = $builtin/bsp_gbuf.vert; + }, + { + stage = geometry; + name = main; + module = $builtin/bsp_gbuf.geom; }, { stage = fragment; name = main; - module = $builtin/quakebsp.frag; + module = $builtin/bsp_gbuf.frag; specializationInfo = { mapEntries = ( { size = 4; offset = 0; constantID = 0; }, @@ -623,6 +648,7 @@ //renderPass = renderpass; }; twod = { + subpass = 3; stages = ( { stage = vertex; diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index 857d457d4..64c0954cb 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -63,6 +63,14 @@ static static #include "libs/video/renderer/vulkan/shader/quakebsp.frag.spvc" static +#include "libs/video/renderer/vulkan/shader/bsp_depth.vert.spvc" +static +#include "libs/video/renderer/vulkan/shader/bsp_gbuf.vert.spvc" +static +#include "libs/video/renderer/vulkan/shader/bsp_gbuf.geom.spvc" +static +#include "libs/video/renderer/vulkan/shader/bsp_gbuf.frag.spvc" +static #include "libs/video/renderer/vulkan/shader/alias.vert.spvc" static #include "libs/video/renderer/vulkan/shader/alias_depth.vert.spvc" @@ -86,6 +94,10 @@ static shaderdata_t builtin_shaders[] = { { "twod.frag", twod_frag, sizeof (twod_frag) }, { "quakebsp.vert", quakebsp_vert, sizeof (quakebsp_vert) }, { "quakebsp.frag", quakebsp_frag, sizeof (quakebsp_frag) }, + { "bsp_depth.vert", bsp_depth_vert, sizeof (bsp_depth_vert) }, + { "bsp_gbuf.vert", bsp_gbuf_vert, sizeof (bsp_gbuf_vert) }, + { "bsp_gbuf.geom", bsp_gbuf_geom, sizeof (bsp_gbuf_geom) }, + { "bsp_gbuf.frag", bsp_gbuf_frag, sizeof (bsp_gbuf_frag) }, { "alias.vert", alias_vert, sizeof (alias_vert) }, { "alias_depth.vert", alias_depth_vert, sizeof (alias_depth_vert) }, { "alias.frag", alias_frag, sizeof (alias_frag) }, diff --git a/libs/video/renderer/vulkan/shader/bsp_depth.vert b/libs/video/renderer/vulkan/shader/bsp_depth.vert new file mode 100644 index 000000000..02a4fed80 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_depth.vert @@ -0,0 +1,19 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + +layout (push_constant) uniform PushConstants { + mat4 Model; +}; + +layout (location = 0) in vec4 vertex; + +void +main (void) +{ + gl_Position = Projection * (View * (Model * vertex)); +} diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.frag b/libs/video/renderer/vulkan/shader/bsp_gbuf.frag new file mode 100644 index 000000000..272499efa --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.frag @@ -0,0 +1,126 @@ +#version 450 + +layout (set = 0, binding = 1) uniform sampler2D Texture; +layout (set = 0, binding = 2) uniform sampler2D GlowMap; +layout (set = 0, binding = 3) uniform sampler2D LightMap; +layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; +layout (set = 0, binding = 5) uniform samplerCube SkyCube; + +layout (push_constant) uniform PushConstants { + layout (offset = 64) + vec4 fog; + float time; +}; + +layout (location = 0) in vec4 tl_st; +layout (location = 1) in vec3 direction; +layout (location = 2) in vec3 normal; + +layout (location = 0) out vec4 frag_color; +layout (location = 1) out vec4 frag_normal; + +layout (constant_id = 0) const bool doWarp = false; +layout (constant_id = 1) const bool doLight = true; +layout (constant_id = 2) const bool doSkyCube = false; +layout (constant_id = 3) const bool doSkySheet = false; + +const float PI = 3.14159265; +const float SPEED = 20.0; +const float CYCLE = 128.0; +const float FACTOR = PI * 2.0 / CYCLE; +const vec2 BIAS = vec2 (1.0, 1.0); +const float SCALE = 8.0; + +vec2 +warp_st (vec2 st, float time) +{ + vec2 angle = st.ts * CYCLE / 2.0; + vec2 phase = vec2 (time, time) * SPEED; + return st + (sin ((angle + phase) * FACTOR) + BIAS) / SCALE; +} + +vec4 +fogBlend (vec4 color) +{ + float az = fog.a * gl_FragCoord.z / gl_FragCoord.w; + vec3 fog_color = fog.rgb; + float fog_factor = exp (-az * az); + + return vec4 (mix (fog_color.rgb, color.rgb, fog_factor), color.a); +} + +vec4 +sky_sheet (vec3 dir, float time) +{ + float len; + vec2 flow = vec2 (1.0, 1.0); + vec2 base; + vec3 st1, st2; + vec4 c1, c2, c; + + dir.z *= 3.0; + len = dot (dir, dir); + len = SCALE * inversesqrt (len); + base = dir.yx * vec2(1.0, -1.0) * len; + + st1 = vec3 (base + flow * time / 8.0, 0); + st2 = vec3 (base + flow * time / 16.0, 1); + + c1 = texture (SkySheet, st1); + c2 = texture (SkySheet, st2); + + c = vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + + return c; +} + +vec4 +sky_cube (vec3 dir, float time) +{ + // NOTE: quake's world is right-handed with Z up and X forward, but + // Vulkan's cube maps are left-handed with Y up and Z forward. The + // rotation to X foward is done by the Sky matrix so all that's left + // to do here is swizzle the Y and Z coordinates + return texture (SkyCube, dir.xzy); +} + +vec4 +sky_color (vec3 dir, float time) +{ + if (!doSkySheet) { + return vec4 (1, 0, 1, 1); + //return sky_cube (dir, time); + } if (!doSkyCube) { + return sky_sheet (dir, time); + } else { + // can see through the sheet (may look funny when looking down) + // maybe have 4 sheet layers instead of 2? + vec4 c1 = sky_sheet (dir, time); + vec4 c2 = sky_cube (dir, time); + return vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + return vec4 (1, 0, 1, 1); + } +} + +void +main (void) +{ + vec4 c; + vec2 t_st = tl_st.xy; + vec2 l_st = tl_st.zw; + + if (doWarp) { + t_st = warp_st (t_st, time); + } + if (doSkyCube || doSkySheet) { + c = sky_color (direction, time); + } else { + c = texture (Texture, t_st); + if (doLight) { + c *= vec4 (texture (LightMap, l_st).xyz, 1); + } + c += texture (GlowMap, t_st); + } + frag_color = c;//fogBlend (c); + frag_normal = vec4 (normal, 0); +} diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.geom b/libs/video/renderer/vulkan/shader/bsp_gbuf.geom new file mode 100644 index 000000000..f1107f759 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.geom @@ -0,0 +1,29 @@ +#version 450 + +layout (triangles) in; +layout (triangle_strip, max_vertices = 3) out; +layout (location = 0) in vec4 v_tl_st[]; +layout (location = 1) in vec3 v_direction[]; + +layout (location = 0) out vec4 tl_st; +layout (location = 1) out vec3 direction; +layout (location = 2) out vec3 normal; + +void +main() +{ + vec3 a = gl_in[0].gl_Position.xyz; + vec3 b = gl_in[1].gl_Position.xyz; + vec3 c = gl_in[2].gl_Position.xyz; + + vec3 n = normalize (cross (b - a, c - a)); + + for (int vert = 0; vert < 3; vert++) { + gl_Position = gl_in[vert].gl_Position; + tl_st = v_tl_st[vert]; + direction = v_direction[vert]; + normal = n; + EmitVertex (); + } + EndPrimitive (); +} diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.vert b/libs/video/renderer/vulkan/shader/bsp_gbuf.vert new file mode 100644 index 000000000..bb9e87e4a --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.vert @@ -0,0 +1,25 @@ +#version 450 + +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + +layout (push_constant) uniform PushConstants { + mat4 Model; +}; + +layout (location = 0) in vec4 vertex; +layout (location = 1) in vec4 tl_uv; + +layout (location = 0) out vec4 tl_st; +layout (location = 1) out vec3 direction; + +void +main (void) +{ + gl_Position = Projection * (View * (Model * vertex)); + direction = (Sky * vertex).xyz; + tl_st = tl_uv; +} diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 973e5445b..f7d9b2f0b 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -152,7 +152,7 @@ Vulkan_DrawAlias (entity_t *ent, vulkan_ctx_t *ctx) } static void -alias_begin_subpass (VkCommandBuffer cmd, VkPipeline pipeline, +alias_begin_subpass (QFV_AliasSubpass subpass, VkPipeline pipeline, vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; @@ -160,11 +160,12 @@ alias_begin_subpass (VkCommandBuffer cmd, VkPipeline pipeline, aliasctx_t *actx = ctx->alias_context; __auto_type cframe = &ctx->frames.a[ctx->curFrame]; aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; + VkCommandBuffer cmd = aframe->cmdSet.a[subpass]; dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, - ctx->renderpass, 0, + ctx->renderpass, subpass, cframe->framebuffer, 0, 0, 0, }; @@ -222,8 +223,8 @@ Vulkan_AliasBegin (vulkan_ctx_t *ctx) //FIXME need per frame matrices aframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; - alias_begin_subpass (aframe->cmdSet.a[QFV_aliasDepth], actx->depth, ctx); - alias_begin_subpass (aframe->cmdSet.a[QFV_aliasGBuffer], actx->gbuf, ctx); + alias_begin_subpass (QFV_aliasDepth, actx->depth, ctx); + alias_begin_subpass (QFV_aliasGBuffer, actx->gbuf, ctx); } void diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 895caed49..dfd58b1f5 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -845,18 +845,20 @@ get_view (qfv_tex_t *tex, qfv_tex_t *default_tex) } static void -bsp_begin_subpass (VkCommandBuffer cmd, VkPipeline pipeline, vulkan_ctx_t *ctx) +bsp_begin_subpass (QFV_BspSubpass subpass, VkPipeline pipeline, + vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; bspctx_t *bctx = ctx->bsp_context; __auto_type cframe = &ctx->frames.a[ctx->curFrame]; bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + VkCommandBuffer cmd = bframe->cmdSet.a[subpass]; dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, - ctx->renderpass, 0, + ctx->renderpass, subpass, cframe->framebuffer, 0, 0, 0, }; @@ -928,9 +930,8 @@ bsp_begin (vulkan_ctx_t *ctx) bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, bctx->default_skybox); - //FIXME pipeline - bsp_begin_subpass (bframe->cmdSet.a[QFV_bspDepth], bctx->main, ctx); - bsp_begin_subpass (bframe->cmdSet.a[QFV_bspGBuffer], bctx->main, ctx); + bsp_begin_subpass (QFV_bspDepth, bctx->depth, ctx); + bsp_begin_subpass (QFV_bspGBuffer, bctx->gbuf, ctx); } static void @@ -1047,7 +1048,7 @@ sky_begin (vulkan_ctx_t *ctx) bctx->default_skybox); //FIXME sky pass - bsp_begin_subpass (bframe->cmdSet.a[QFV_bspTranslucent], bctx->sky, ctx); + bsp_begin_subpass (QFV_bspTranslucent, bctx->sky, ctx); } static void @@ -1457,8 +1458,9 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) DARRAY_RESIZE (&bctx->frames, frames); bctx->frames.grow = 0; - bctx->main = Vulkan_CreatePipeline (ctx, "quakebsp_main"); - bctx->sky = Vulkan_CreatePipeline (ctx, "quakebsp_skysheet"); + bctx->depth = Vulkan_CreatePipeline (ctx, "bsp_depth"); + bctx->gbuf = Vulkan_CreatePipeline (ctx, "bsp_gbuf"); + bctx->sky = Vulkan_CreatePipeline (ctx, "bsp_skysheet"); bctx->layout = Vulkan_CreatePipelineLayout (ctx, "quakebsp_layout"); bctx->sampler = Vulkan_CreateSampler (ctx, "quakebsp_sampler"); @@ -1507,7 +1509,8 @@ Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx) free (bframe->cmdSet.a); } - dfunc->vkDestroyPipeline (device->dev, bctx->main, 0); + dfunc->vkDestroyPipeline (device->dev, bctx->depth, 0); + dfunc->vkDestroyPipeline (device->dev, bctx->gbuf, 0); dfunc->vkDestroyPipeline (device->dev, bctx->sky, 0); DARRAY_CLEAR (&bctx->texture_chains); DARRAY_CLEAR (&bctx->frames); diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 43b246273..4b962edd6 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -709,7 +709,7 @@ Vulkan_FlushText (vulkan_ctx_t *ctx) dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, - ctx->renderpass, 0, + ctx->renderpass, QFV_passTranslucent, cframe->framebuffer, 0, 0, 0 }; From 0cd2ece38e4ae951e3d61512437ccf953971eab3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Feb 2021 14:37:13 +0900 Subject: [PATCH 358/435] [util] Correct element order for vector expressions --- libs/util/cexpr-parse.y | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y index ad734def7..4c57c98c0 100644 --- a/libs/util/cexpr-parse.y +++ b/libs/util/cexpr-parse.y @@ -321,9 +321,22 @@ vector_expr (exprlist_t *list, exprctx_t *context) { exprlist_t *l; exprval_t *val = cexpr_value (&cexpr_vector, context); + float *vector = val->value; int i; + exprlist_t *rlist = 0; + + // list is built in reverse order, so need to reverse it to make converting + // to an array easier + while (list) { + exprlist_t *t = list->next; + list->next = rlist; + rlist = list; + list = t; + } + list = rlist; + for (i = 0; i < 4 && list; i++, list = l) { - exprval_t dst = { &cexpr_float, ((float *) val->value) + i }; + exprval_t dst = { &cexpr_float, &vector[i] }; exprval_t *src = list->value; binop_t *cast = cexpr_find_cast (&cexpr_float, src->type); if (cast) { @@ -335,12 +348,12 @@ vector_expr (exprlist_t *list, exprctx_t *context) l = list->next; cmemfree (context->memsuper, list); } - for ( ; i < 4; i++) { - ((float *) val->value)[i] = 0; - } if (i == 4 && list) { cexpr_error (context, "excess elements in vector expression"); } + for ( ; i < 4; i++) { + vector[i] = 0; + } return val; } From 82eabb5ca2acf4053fa3ed08ff2a2fbc84c2a9f3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Feb 2021 14:37:48 +0900 Subject: [PATCH 359/435] [vulkan] Parse clear values And get the render pass working in general. Note that this is only the render pass and frame buffers: actual commands still have problems. --- include/vid_vulkan.h | 5 ++ libs/video/renderer/vid_render_vulkan.c | 19 ++--- libs/video/renderer/vulkan/deferred.plist | 16 +++- libs/video/renderer/vulkan/vkparse.c | 85 +++++++++++++++++++ libs/video/renderer/vulkan/vkparse.h | 3 + libs/video/renderer/vulkan/vkparse.plist | 13 ++- libs/video/renderer/vulkan/vulkan_draw.c | 1 + .../video/renderer/vulkan/vulkan_vid_common.c | 13 +++ 8 files changed, 140 insertions(+), 15 deletions(-) diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index dcf4f624b..a672f02d1 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -32,6 +32,9 @@ typedef struct vulkan_matrices_s { typedef struct vulkan_frameset_s DARRAY_TYPE (vulkan_frame_t) vulkan_frameset_t; +typedef struct clearvalueset_s + DARRAY_TYPE (VkClearValue) clearvalueset_t; + typedef struct vulkan_ctx_s { void (*load_vulkan) (struct vulkan_ctx_s *ctx); void (*unload_vulkan) (struct vulkan_ctx_s *ctx); @@ -56,6 +59,7 @@ typedef struct vulkan_ctx_s { struct plitem_s *renderpassDef; VkRenderPass renderpass; + clearvalueset_t *clearValues; struct qfv_imageset_s *attachment_images; struct qfv_imageviewset_s *attachment_views; VkDeviceMemory attachmentMemory; @@ -70,6 +74,7 @@ typedef struct vulkan_ctx_s { struct hashtab_s *samplers; struct hashtab_s *images; struct hashtab_s *imageViews; + struct hashtab_s *renderpasses; struct aliasctx_s *alias_context; struct bspctx_s *bsp_context; diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index b8f9dc718..84f7b41f9 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -125,9 +125,6 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) __auto_type frame = &vulkan_ctx->frames.a[vulkan_ctx->curFrame]; dfunc->vkWaitForFences (dev, 1, &frame->fence, VK_TRUE, 2000000000); - if (frame->framebuffer) { - dfunc->vkDestroyFramebuffer (dev, frame->framebuffer, 0); - } QFV_AcquireNextImage (vulkan_ctx->swapchain, frame->imageAvailableSemaphore, 0, &imageIndex); @@ -145,16 +142,11 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - VkClearValue clearValues[3] = { - { { {0.0, 0.0, 0.0, 1.0} } }, - { { {1.0, 0.0} } }, - { { {0.0, 0.0, 0.0, 1.0} } }, - }; VkRenderPassBeginInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 0, vulkan_ctx->renderpass, 0, { {0, 0}, vulkan_ctx->swapchain->extent }, - 3, clearValues + vulkan_ctx->clearValues->size, vulkan_ctx->clearValues->a }; dfunc->vkBeginCommandBuffer (frame->cmdBuffer, &beginInfo); @@ -163,12 +155,15 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) subpassContents); for (int i = 0; i < frame->cmdSetCount; i++) { - dfunc->vkCmdExecuteCommands (frame->cmdBuffer, frame->cmdSets[i].size, - frame->cmdSets[i].a); + if (frame->cmdSets[i].size) { + dfunc->vkCmdExecuteCommands (frame->cmdBuffer, + frame->cmdSets[i].size, + frame->cmdSets[i].a); + } // reset for next time around frame->cmdSets[i].size = 0; - if (i < frame->cmdSetCount) { + if (i < frame->cmdSetCount - 1) { dfunc->vkCmdNextSubpass (frame->cmdBuffer, subpassContents); } } diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index e7e7e1f12..c03c30625 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -13,6 +13,7 @@ arrayLayers = 1; tiling = optimal; usage = depth_stencil_attachment|input_attachment; + initialLayout = undefined; }; color = { imageType = VK_IMAGE_TYPE_2D; @@ -27,6 +28,7 @@ arrayLayers = 1; tiling = optimal; usage = color_attachment|input_attachment; + initialLayout = undefined; }; normals = { imageType = VK_IMAGE_TYPE_2D; @@ -41,6 +43,7 @@ arrayLayers = 1; tiling = optimal; usage = color_attachment|input_attachment; + initialLayout = undefined; }; opaque = { imageType = VK_IMAGE_TYPE_2D; @@ -55,6 +58,7 @@ arrayLayers = 1; tiling = optimal; usage = color_attachment|input_attachment; + initialLayout = undefined; }; translucent = { imageType = VK_IMAGE_TYPE_2D; @@ -69,6 +73,7 @@ arrayLayers = 1; tiling = optimal; usage = color_attachment|input_attachment; + initialLayout = undefined; }; }; imageViews = { @@ -154,12 +159,21 @@ }; }; framebuffer = { - renderPass = renderpass; + renderPass = $properties.renderpass; attachments = (depth, color, normals, opaque, translucent, "$swapchain.views[$swapImageIndex]"); width = $swapchain.extent.width; height = $swapchain.extent.height; + layers = 1; }; + clearValues = ( + { depthStencil = { depth = 1; stencil = 0; }; }, + { color = "[0, 0, 0, 1]"; }, // color + { color = "[0, 0, 0, 1]"; }, // normals + { color = "[0, 0, 0, 1]"; }, // opaque + { color = "[0, 0, 0, 0]"; }, // translucent + { color = "[0, 0, 0, 1]"; }, // swapchain + ); renderpass = { attachments = ( { diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index ee8efb8a4..72ec5abbb 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -413,6 +413,42 @@ QFV_AddHandle (hashtab_t *tab, const char *name, uint64_t handle) Hash_Add (tab, hr); } +static int +parse_VkRenderPass (const plitem_t *item, void **data, + plitem_t *messages, parsectx_t *context) +{ + __auto_type handle = (VkRenderPass *) data[0]; + int ret = 1; + parsectx_t *pctx = context; + exprctx_t ectx = *pctx->ectx; + vulkan_ctx_t *ctx = pctx->vctx; + + const char *name = PL_String (item); + Sys_Printf ("parse_VkRenderPass: %s\n", name); + if (name[0] != '$') { + name = va (ctx->va_ctx, "$"QFV_PROPERTIES".%s", name); + } + + *handle = (VkRenderPass) QFV_GetHandle (ctx->renderpasses, name); + if (*handle) { + return 1; + } + + plitem_t *setItem = 0; + exprval_t result = { &cexpr_plitem, &setItem }; + ectx.symtab = 0; + ectx.result = &result; + ret = !cexpr_eval_string (name, &ectx); + if (ret) { + VkRenderPass setLayout; + setLayout = QFV_ParseRenderPass (ctx, setItem, pctx->properties); + *handle = (VkRenderPass) setLayout; + + QFV_AddHandle (ctx->setLayouts, name, (uint64_t) setLayout); + } + return ret; +} + static int parse_VkShaderModule (const plitem_t *item, void **data, plitem_t *messages, parsectx_t *context) @@ -711,6 +747,21 @@ imageView_free (void *hr, void *_ctx) handleref_free (handleref, ctx); } +static void +renderpass_free (void *hr, void *_ctx) +{ + __auto_type handleref = (handleref_t *) hr; + __auto_type renderpass = (VkRenderPass) handleref->handle; + __auto_type ctx = (vulkan_ctx_t *) _ctx; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + if (renderpass) { + dfunc->vkDestroyRenderPass (device->dev, renderpass, 0); + }; + handleref_free (handleref, ctx); +} + static hashtab_t *enum_symtab; static int @@ -891,6 +942,7 @@ QFV_InitParse (vulkan_ctx_t *ctx) ctx->samplers = handlref_symtab (sampler_free, ctx); ctx->images = handlref_symtab (image_free, ctx); ctx->imageViews = handlref_symtab (imageView_free, ctx); + ctx->renderpasses = handlref_symtab (renderpass_free, ctx); } } @@ -1262,6 +1314,39 @@ QFV_ParseFramebuffer (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) VkFramebuffer framebuffer; dfunc->vkCreateFramebuffer (device->dev, &cInfo, 0, &framebuffer); + printf ("framebuffer, renderPass: %p, %p\n", framebuffer, cInfo.renderPass); return framebuffer; } + +static int +parse_clearvalueset (const plfield_t *field, const plitem_t *item, void *data, + plitem_t *messages, void *context) +{ + parsectx_t *parsectx = context; + vulkan_ctx_t *ctx = parsectx->vctx; + + plelement_t element = { + QFDictionary, + sizeof (VkClearValue), + array_alloc, + parse_VkClearValue, + 0, + }; + plfield_t f = { 0, 0, 0, 0, &element }; + + if (!PL_ParseArray (&f, item, &ctx->clearValues, messages, context)) { + return 0; + } + return 1; +} + +int +QFV_ParseClearValues (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) +{ + if (!parse_object (ctx, plist, parse_clearvalueset, &ctx->clearValues, + properties)) { + return 0; + } + return 1; +} diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index f8aea8a7f..2550e1b17 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -58,5 +58,8 @@ struct qfv_imageviewset_s *QFV_ParseImageViewSet (vulkan_ctx_t *ctx, plitem_t *properties); VkFramebuffer QFV_ParseFramebuffer (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties); +int QFV_ParseClearValues (vulkan_ctx_t *ctx, plitem_t *plist, + plitem_t *properties); + #endif//__vkparse_h diff --git a/libs/video/renderer/vulkan/vkparse.plist b/libs/video/renderer/vulkan/vkparse.plist index 9eb5e7e04..22d9173dc 100644 --- a/libs/video/renderer/vulkan/vkparse.plist +++ b/libs/video/renderer/vulkan/vkparse.plist @@ -23,6 +23,7 @@ VkImageCreateInfo, VkImageViewCreateInfo, VkFramebufferCreateInfo, + VkClearValue, ); parse = { VkSubpassDescription = { @@ -317,7 +318,7 @@ VkFramebufferCreateInfo = { //flags = auto; reserved for future use (Bits enum does not exist) renderPass = { - type = (custom, QFString, parse_VkShaderModule); + type = (custom, QFString, parse_VkRenderPass); fields = (renderPass); }; attachments = { @@ -328,6 +329,14 @@ width = auto; height = auto; layers = auto; - } + }; + VkClearColorValue = skip; + VkClearValue = { + color = { + type = (custom, QFString, parse_RGBA); + fields = (color); + }; + depthStencil = auto; + }; } } diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 4b962edd6..2ab8bd05a 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -718,6 +718,7 @@ Vulkan_FlushText (vulkan_ctx_t *ctx) VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, }; + printf ("Vulkan_FlushText: %p %p\n", inherit.renderPass, inherit.framebuffer); dfunc->vkBeginCommandBuffer (cmd, &beginInfo); dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index a6f444798..903dc8d19 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -308,12 +308,25 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) { const char *name = "renderpass";//FIXME + hashtab_t *tab = ctx->renderpasses; + const char *path; + path = va (ctx->va_ctx, "$"QFV_PROPERTIES".%s", name); + __auto_type renderpass = (VkRenderPass) QFV_GetHandle (tab, path); + if (renderpass) { + ctx->renderpass = renderpass; + return; + } + plitem_t *item = qfv_load_renderpass (ctx, name); ctx->renderpass = QFV_ParseRenderPass (ctx, item, ctx->renderpassDef); + QFV_AddHandle (tab, path, (uint64_t) ctx->renderpass); QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_RENDER_PASS, ctx->renderpass, va (ctx->va_ctx, "renderpass:%s", name)); + item = qfv_load_renderpass (ctx, "clearValues"); + QFV_ParseClearValues (ctx, item, ctx->renderpassDef); + printf ("renderpass: %p\n", ctx->renderpass); } void From e6ecf5e8559b1e99038fe39614522392313332ab Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Feb 2021 15:43:02 +0900 Subject: [PATCH 360/435] [vulkan] Fix up commands for deferred rendering Nothing gets output yet (lighting and composite passes not implemented), but everything passes validation until exit (not destroying everything). --- libs/video/renderer/Makemodule.am | 5 + libs/video/renderer/vulkan/qfpipeline.plist | 29 +++--- libs/video/renderer/vulkan/shader.c | 3 + .../video/renderer/vulkan/shader/bsp_sky.frag | 96 +++++++++++++++++++ libs/video/renderer/vulkan/vulkan_alias.c | 2 +- libs/video/renderer/vulkan/vulkan_bsp.c | 11 ++- 6 files changed, 133 insertions(+), 13 deletions(-) create mode 100644 libs/video/renderer/vulkan/shader/bsp_sky.frag diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index a5c3fc1a0..93f6a51b4 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -283,6 +283,8 @@ bsp_gbufg_src = $(vkshaderpath)/bsp_gbuf.geom bsp_gbufg_c = $(vkshaderpath)/bsp_gbuf.geom.spvc bsp_gbuff_src = $(vkshaderpath)/bsp_gbuf.frag bsp_gbuff_c = $(vkshaderpath)/bsp_gbuf.frag.spvc +bsp_skyf_src = $(vkshaderpath)/bsp_sky.frag +bsp_skyf_c = $(vkshaderpath)/bsp_sky.frag.spvc aliasv_src = $(vkshaderpath)/alias.vert aliasv_c = $(vkshaderpath)/alias.vert.spvc aliasf_src = $(vkshaderpath)/alias.frag @@ -312,6 +314,8 @@ $(bsp_gbufg_c): $(bsp_gbufg_src) $(bsp_gbuff_c): $(bsp_gbuff_src) +$(bsp_skyf_c): $(bsp_skyf_src) + $(aliasv_c): $(aliasv_src) $(alias_depth_c): $(alias_depth_src) @@ -333,6 +337,7 @@ vkshader_c = \ $(bsp_gbufv_c) \ $(bsp_gbufg_c) \ $(bsp_gbuff_c) \ + $(bsp_skyf_c) \ $(aliasv_c) \ $(alias_depth_c) \ $(aliasf_c) \ diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index d71ce6037..03e200fc7 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -607,28 +607,21 @@ //renderPass = renderpass; }; bsp_skysheet = { - subpass = 1; + subpass = 2; stages = ( { stage = vertex; name = main; module = $builtin/bsp_gbuf.vert; }, - { - stage = geometry; - name = main; - module = $builtin/bsp_gbuf.geom; - }, { stage = fragment; name = main; - module = $builtin/bsp_gbuf.frag; + module = $builtin/bsp_sky.frag; specializationInfo = { mapEntries = ( { size = 4; offset = 0; constantID = 0; }, - { size = 4; offset = 0; constantID = 1; }, - { size = 4; offset = 0; constantID = 2; }, - { size = 4; offset = 4; constantID = 3; }, + { size = 4; offset = 4; constantID = 1; }, ); data = <00000000ffffffff>; }; @@ -640,7 +633,21 @@ rasterization = $properties.pipelines.bsp_gbuf.rasterization; multisample = $properties.pipelines.bsp_gbuf.multisample; depthStencil = $properties.pipelines.bsp_gbuf.depthStencil; - colorBlend = $properties.pipelines.bsp_gbuf.colorBlend; + colorBlend = { + logicOpEnable = false; + attachments = ( + { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }, + ); + }; dynamic = { dynamicState = ( viewport, scissor ); }; diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index 64c0954cb..4063e6f33 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -71,6 +71,8 @@ static static #include "libs/video/renderer/vulkan/shader/bsp_gbuf.frag.spvc" static +#include "libs/video/renderer/vulkan/shader/bsp_sky.frag.spvc" +static #include "libs/video/renderer/vulkan/shader/alias.vert.spvc" static #include "libs/video/renderer/vulkan/shader/alias_depth.vert.spvc" @@ -98,6 +100,7 @@ static shaderdata_t builtin_shaders[] = { { "bsp_gbuf.vert", bsp_gbuf_vert, sizeof (bsp_gbuf_vert) }, { "bsp_gbuf.geom", bsp_gbuf_geom, sizeof (bsp_gbuf_geom) }, { "bsp_gbuf.frag", bsp_gbuf_frag, sizeof (bsp_gbuf_frag) }, + { "bsp_sky.frag", bsp_sky_frag, sizeof (bsp_sky_frag) }, { "alias.vert", alias_vert, sizeof (alias_vert) }, { "alias_depth.vert", alias_depth_vert, sizeof (alias_depth_vert) }, { "alias.frag", alias_frag, sizeof (alias_frag) }, diff --git a/libs/video/renderer/vulkan/shader/bsp_sky.frag b/libs/video/renderer/vulkan/shader/bsp_sky.frag new file mode 100644 index 000000000..28ce41421 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_sky.frag @@ -0,0 +1,96 @@ +#version 450 + +layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; +layout (set = 0, binding = 5) uniform samplerCube SkyCube; + +layout (push_constant) uniform PushConstants { + layout (offset = 64) + vec4 fog; + float time; +}; + +layout (location = 0) in vec4 tl_st; +layout (location = 1) in vec3 direction; + +layout (location = 0) out vec4 frag_color; + +layout (constant_id = 0) const bool doSkyCube = false; +layout (constant_id = 1) const bool doSkySheet = false; + +const float SCALE = 8.0; + +vec4 +fogBlend (vec4 color) +{ + float az = fog.a * gl_FragCoord.z / gl_FragCoord.w; + vec3 fog_color = fog.rgb; + float fog_factor = exp (-az * az); + + return vec4 (mix (fog_color.rgb, color.rgb, fog_factor), color.a); +} + +vec4 +sky_sheet (vec3 dir, float time) +{ + float len; + vec2 flow = vec2 (1.0, 1.0); + vec2 base; + vec3 st1, st2; + vec4 c1, c2, c; + + dir.z *= 3.0; + len = dot (dir, dir); + len = SCALE * inversesqrt (len); + base = dir.yx * vec2(1.0, -1.0) * len; + + st1 = vec3 (base + flow * time / 8.0, 0); + st2 = vec3 (base + flow * time / 16.0, 1); + + c1 = texture (SkySheet, st1); + c2 = texture (SkySheet, st2); + + c = vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + + return c; +} + +vec4 +sky_cube (vec3 dir, float time) +{ + // NOTE: quake's world is right-handed with Z up and X forward, but + // Vulkan's cube maps are left-handed with Y up and Z forward. The + // rotation to X foward is done by the Sky matrix so all that's left + // to do here is swizzle the Y and Z coordinates + return texture (SkyCube, dir.xzy); +} + +vec4 +sky_color (vec3 dir, float time) +{ + if (!doSkySheet) { + return vec4 (1, 0, 1, 1); + //return sky_cube (dir, time); + } if (!doSkyCube) { + return sky_sheet (dir, time); + } else { + // can see through the sheet (may look funny when looking down) + // maybe have 4 sheet layers instead of 2? + vec4 c1 = sky_sheet (dir, time); + vec4 c2 = sky_cube (dir, time); + return vec4 (mix (c2.rgb, c1.rgb, c1.a), max (c1.a, c2.a)); + return vec4 (1, 0, 1, 1); + } +} + +void +main (void) +{ + vec4 c; + + if (doSkyCube || doSkySheet) { + c = sky_color (direction, time); + } else { + c = vec4 (0, 0, 0, 1); + } + frag_color = c;//fogBlend (c); +} diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index f7d9b2f0b..8468335c1 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -186,7 +186,7 @@ alias_begin_subpass (QFV_AliasSubpass subpass, VkPipeline pipeline, // actx->layout, 0, 2, sets, 0, 0); dfunc->vkCmdPushDescriptorSetKHR (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, actx->layout, - 0, 2, aframe->descriptors + 0); + 0, 1, aframe->descriptors + 0); VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index dfd58b1f5..8b33cebb3 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -798,7 +798,7 @@ push_fragconst (fragconst_t *fragconst, VkPipelineLayout layout, qfv_devfuncs_t *dfunc, VkCommandBuffer cmd) { dfunc->vkCmdPushConstants (cmd, layout, VK_SHADER_STAGE_FRAGMENT_BIT, - 0, sizeof (fragconst_t), fragconst); + 64, sizeof (fragconst_t), fragconst);//FIXME 64 } static void @@ -1259,6 +1259,15 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) fragconst_t frag_constants = { time: vr_data.realtime }; push_fragconst (&frag_constants, bctx->layout, dfunc, bframe->cmdSet.a[QFV_bspTranslucent]); + bind_view (qfv_bsp_texture, ctx->default_black->view, bframe, + bframe->cmdSet.a[QFV_bspTranslucent],//FIXME + bctx->layout, dfunc); + bind_view (qfv_bsp_glowmap, ctx->default_black->view, bframe, + bframe->cmdSet.a[QFV_bspTranslucent],//FIXME + bctx->layout, dfunc); + bind_view (qfv_bsp_lightmap, ctx->default_black->view, bframe, + bframe->cmdSet.a[QFV_bspTranslucent],//FIXME + bctx->layout, dfunc); for (is = bctx->sky_chain; is; is = is->tex_chain) { surf = is->surface; if (tex != surf->texinfo->texture->render) { From 9229b67633cf2308a78d211c0547f9b926dcbaf4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 24 Feb 2021 16:27:56 +0900 Subject: [PATCH 361/435] [vulkan] Clean up the new render pass and framebuffers --- include/QF/Vulkan/qf_alias.h | 2 +- libs/video/renderer/vid_render_vulkan.c | 2 ++ libs/video/renderer/vulkan/vulkan_draw.c | 1 - libs/video/renderer/vulkan/vulkan_vid_common.c | 17 ++++++++++++++--- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index 5f3964a2b..7cd5b5bad 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -1,7 +1,7 @@ /* qf_alias.h - Vulkan specific brush model stuff + Vulkan specific alias model stuff Copyright (C) 2012 Bill Currie Copyright (C) 2021 Bill Currie diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 84f7b41f9..9893c08da 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -607,6 +607,8 @@ vulkan_vid_render_shutdown (void) Vulkan_Alias_Shutdown (vulkan_ctx); Mod_ClearAll (); Vulkan_Texture_Shutdown (vulkan_ctx); + Vulkan_DestroyFramebuffers (vulkan_ctx); + Vulkan_DestroyRenderPass (vulkan_ctx); Vulkan_Shutdown_Common (vulkan_ctx); } diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 2ab8bd05a..4b962edd6 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -718,7 +718,6 @@ Vulkan_FlushText (vulkan_ctx_t *ctx) VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, }; - printf ("Vulkan_FlushText: %p %p\n", inherit.renderPass, inherit.framebuffer); dfunc->vkBeginCommandBuffer (cmd, &beginInfo); dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 903dc8d19..98fec5945 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -192,9 +192,6 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) if (ctx->frames.size) { Vulkan_DestroyFrames (ctx); } - if (ctx->renderpass) { - Vulkan_DestroyRenderPass (ctx); - } if (ctx->swapchain) { QFV_DestroySwapchain (ctx->swapchain); } @@ -332,6 +329,10 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) void Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) { + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + dfunc->vkDestroyRenderPass (device->dev, ctx->renderpass, 0); } VkPipeline @@ -554,4 +555,14 @@ Vulkan_CreateFramebuffers (vulkan_ctx_t *ctx) void Vulkan_DestroyFramebuffers (vulkan_ctx_t *ctx) { + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + for (size_t i = 0; i < ctx->attachment_views->size; i++) { + dfunc->vkDestroyImageView (device->dev, ctx->attachment_views->a[i], 0); + } + for (size_t i = 0; i < ctx->attachment_images->size; i++) { + dfunc->vkDestroyImage (device->dev, ctx->attachment_images->a[i], 0); + } + dfunc->vkFreeMemory (device->dev, ctx->attachmentMemory, 0); } From 10a1b99a92a9d83caee473e188d16b71a4f8ba9e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 24 Feb 2021 19:58:31 +0900 Subject: [PATCH 362/435] [vulkan] Implement lighting and compose passes Lighting doesn't actually do lights yet, but it's producing pixels. Translucent seems to be working (2d draw uses it), and compose seems to be working. --- include/QF/Vulkan/funclist.h | 1 + include/QF/Vulkan/qf_compose.h | 62 ++++ include/QF/Vulkan/qf_lighting.h | 65 +++++ include/vid_vulkan.h | 5 + libs/video/renderer/Makemodule.am | 12 + libs/video/renderer/vid_render_vulkan.c | 9 + libs/video/renderer/vulkan/deferred.plist | 32 ++- libs/video/renderer/vulkan/qfpipeline.plist | 271 +++++++++++++++++- libs/video/renderer/vulkan/shader.c | 6 + .../video/renderer/vulkan/shader/compose.frag | 19 ++ .../renderer/vulkan/shader/lighting.frag | 33 +++ libs/video/renderer/vulkan/vkparse.c | 2 + libs/video/renderer/vulkan/vulkan_alias.c | 3 +- libs/video/renderer/vulkan/vulkan_bsp.c | 12 + libs/video/renderer/vulkan/vulkan_compose.c | 175 +++++++++++ libs/video/renderer/vulkan/vulkan_lighting.c | 202 +++++++++++++ .../video/renderer/vulkan/vulkan_vid_common.c | 50 ++++ 17 files changed, 930 insertions(+), 29 deletions(-) create mode 100644 include/QF/Vulkan/qf_compose.h create mode 100644 include/QF/Vulkan/qf_lighting.h create mode 100644 libs/video/renderer/vulkan/shader/compose.frag create mode 100644 libs/video/renderer/vulkan/shader/lighting.frag create mode 100644 libs/video/renderer/vulkan/vulkan_compose.c create mode 100644 libs/video/renderer/vulkan/vulkan_lighting.c diff --git a/include/QF/Vulkan/funclist.h b/include/QF/Vulkan/funclist.h index a1601f814..e4a21d52a 100644 --- a/include/QF/Vulkan/funclist.h +++ b/include/QF/Vulkan/funclist.h @@ -179,6 +179,7 @@ DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdSetScissor) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindVertexBuffers) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindIndexBuffer) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdBindDescriptorSets) +DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdDraw) DEVICE_LEVEL_VULKAN_FUNCTION (vkCmdDrawIndexed) #undef DEVICE_LEVEL_VULKAN_FUNCTION diff --git a/include/QF/Vulkan/qf_compose.h b/include/QF/Vulkan/qf_compose.h new file mode 100644 index 000000000..f8fd497a1 --- /dev/null +++ b/include/QF/Vulkan/qf_compose.h @@ -0,0 +1,62 @@ +/* + qf_compose.h + + Vulkan compose pass + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/2/24 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_qf_compose_h +#define __QF_Vulkan_qf_compose_h + +#include "QF/darray.h" +#include "QF/model.h" +#include "QF/modelgen.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/command.h" + +#define COMPOSE_IMAGE_INFOS 2 + +typedef struct composeframe_s { + VkCommandBuffer cmd; + VkDescriptorImageInfo imageInfo[COMPOSE_IMAGE_INFOS]; + VkWriteDescriptorSet descriptors[COMPOSE_IMAGE_INFOS]; +} composeframe_t; + +typedef struct composeframeset_s + DARRAY_TYPE (composeframe_t) composeframeset_t; + +typedef struct composectx_s { + composeframeset_t frames; + VkPipeline pipeline; + VkPipelineLayout layout; +} composectx_t; + +struct vulkan_ctx_s; + +void Vulkan_Compose_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Compose_Shutdown (struct vulkan_ctx_s *ctx); +void Vulkan_Compose_Draw (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_compose_h diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h new file mode 100644 index 000000000..d2cee31ac --- /dev/null +++ b/include/QF/Vulkan/qf_lighting.h @@ -0,0 +1,65 @@ +/* + qf_lighting.h + + Vulkan lighting pass + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/2/23 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __QF_Vulkan_qf_lighting_h +#define __QF_Vulkan_qf_lighting_h + +#include "QF/darray.h" +#include "QF/model.h" +#include "QF/modelgen.h" +#include "QF/Vulkan/qf_vid.h" +#include "QF/Vulkan/command.h" + +#define LIGHTING_BUFFER_INFOS 1 +#define LIGHTING_IMAGE_INFOS 3 + +typedef struct lightingframe_s { + VkCommandBuffer cmd; + VkDescriptorBufferInfo bufferInfo[LIGHTING_BUFFER_INFOS]; + VkDescriptorImageInfo imageInfo[LIGHTING_IMAGE_INFOS]; + VkWriteDescriptorSet descriptors[LIGHTING_BUFFER_INFOS + + LIGHTING_IMAGE_INFOS]; +} lightingframe_t; + +typedef struct lightingframeset_s + DARRAY_TYPE (lightingframe_t) lightingframeset_t; + +typedef struct lightingctx_s { + lightingframeset_t frames; + VkPipeline pipeline; + VkPipelineLayout layout; +} lightingctx_t; + +struct vulkan_ctx_s; + +void Vulkan_Lighting_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Lighting_Shutdown (struct vulkan_ctx_s *ctx); +void Vulkan_Lighting_Draw (struct vulkan_ctx_s *ctx); + +#endif//__QF_Vulkan_qf_lighting_h diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index a672f02d1..080b8079f 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -79,6 +79,11 @@ typedef struct vulkan_ctx_s { struct aliasctx_s *alias_context; struct bspctx_s *bsp_context; struct drawctx_s *draw_context; + struct lightingctx_s *lighting_context; + struct composectx_s *compose_context; + + VkBuffer quad_buffer; + VkDeviceMemory quad_memory; VkCommandPool cmdpool; VkCommandBuffer cmdbuffer; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 93f6a51b4..8789de037 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -240,7 +240,9 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/vkparse.c \ libs/video/renderer/vulkan/vulkan_alias.c \ libs/video/renderer/vulkan/vulkan_bsp.c \ + libs/video/renderer/vulkan/vulkan_compose.c \ libs/video/renderer/vulkan/vulkan_draw.c \ + libs/video/renderer/vulkan/vulkan_lighting.c \ libs/video/renderer/vulkan/vulkan_lightmap.c \ libs/video/renderer/vulkan/vulkan_main.c \ libs/video/renderer/vulkan/vulkan_matrices.c \ @@ -285,6 +287,10 @@ bsp_gbuff_src = $(vkshaderpath)/bsp_gbuf.frag bsp_gbuff_c = $(vkshaderpath)/bsp_gbuf.frag.spvc bsp_skyf_src = $(vkshaderpath)/bsp_sky.frag bsp_skyf_c = $(vkshaderpath)/bsp_sky.frag.spvc +lightingf_src = $(vkshaderpath)/lighting.frag +lightingf_c = $(vkshaderpath)/lighting.frag.spvc +composef_src = $(vkshaderpath)/compose.frag +composef_c = $(vkshaderpath)/compose.frag.spvc aliasv_src = $(vkshaderpath)/alias.vert aliasv_c = $(vkshaderpath)/alias.vert.spvc aliasf_src = $(vkshaderpath)/alias.frag @@ -316,6 +322,10 @@ $(bsp_gbuff_c): $(bsp_gbuff_src) $(bsp_skyf_c): $(bsp_skyf_src) +$(lightingf_c): $(lightingf_src) + +$(composef_c): $(composef_src) + $(aliasv_c): $(aliasv_src) $(alias_depth_c): $(alias_depth_src) @@ -338,6 +348,8 @@ vkshader_c = \ $(bsp_gbufg_c) \ $(bsp_gbuff_c) \ $(bsp_skyf_c) \ + $(lightingf_c) \ + $(composef_c) \ $(aliasv_c) \ $(alias_depth_c) \ $(aliasf_c) \ diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 9893c08da..059250fff 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -38,7 +38,9 @@ #include "QF/Vulkan/qf_alias.h" #include "QF/Vulkan/qf_bsp.h" +#include "QF/Vulkan/qf_compose.h" #include "QF/Vulkan/qf_draw.h" +#include "QF/Vulkan/qf_lighting.h" #include "QF/Vulkan/qf_lightmap.h" #include "QF/Vulkan/qf_main.h" #include "QF/Vulkan/qf_particles.h" @@ -98,6 +100,8 @@ vulkan_R_Init (void) Vulkan_Bsp_Init (vulkan_ctx); Vulkan_Draw_Init (vulkan_ctx); Vulkan_Particles_Init (vulkan_ctx); + Vulkan_Lighting_Init (vulkan_ctx); + Vulkan_Compose_Init (vulkan_ctx); Sys_Printf ("R_Init %p %d", vulkan_ctx->swapchain->swapchain, vulkan_ctx->swapchain->numImages); @@ -140,6 +144,9 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) Vulkan_FlushText (vulkan_ctx); + Vulkan_Lighting_Draw (vulkan_ctx); + Vulkan_Compose_Draw (vulkan_ctx); + VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; VkRenderPassBeginInfo renderPassInfo = { @@ -602,6 +609,8 @@ vulkan_vid_render_shutdown (void) QFV_DeviceWaitIdle (device); df->vkDestroyFence (dev, vulkan_ctx->fence, 0); df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0); + Vulkan_Compose_Shutdown (vulkan_ctx); + Vulkan_Lighting_Shutdown (vulkan_ctx); Vulkan_Draw_Shutdown (vulkan_ctx); Vulkan_Bsp_Shutdown (vulkan_ctx); Vulkan_Alias_Shutdown (vulkan_ctx); diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index c03c30625..0245906da 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -179,7 +179,7 @@ { format = $properties.images.depth.format; samples = 1; - loadOp = dont_care; + loadOp = clear; storeOp = dont_care; stencilLoadOp = dont_care; stencilStoreOp = dont_care; @@ -238,14 +238,14 @@ }, ); subpasses = ( - { // depth + { // 0 depth pipelineBindPoint = graphics; depthStencilAttachment = { attachment = 0; layout = depth_stencil_attachment_optimal; }; }, - { // g-buffer generation + { // 1 g-buffer generation pipelineBindPoint = graphics; colorAttachments = ( { // color @@ -261,8 +261,9 @@ attachment = 0; layout = depth_stencil_attachment_optimal; }; + preserveAttachments = (4); }, - { // lighting + { // 2 lighting pipelineBindPoint = graphics; inputAttachments = ( { // depth @@ -284,8 +285,9 @@ layout = color_attachment_optimal; }, ); + preserveAttachments = (4); }, - { // translucent + { // 3 translucent pipelineBindPoint = graphics; colorAttachments = ( { // translucent @@ -293,8 +295,9 @@ layout = color_attachment_optimal; }, ); + preserveAttachments = (0, 1, 2, 3); }, - { // compose + { // 4 compose pipelineBindPoint = graphics; inputAttachments = ( { // opaque @@ -312,12 +315,13 @@ layout = color_attachment_optimal; }, ); + preserveAttachments = (0, 1, 2); }, ); dependencies = ( { - srcSubpass = 0; - dstSubpass = 1; + srcSubpass = 0; // depth + dstSubpass = 1; // g-buffer srcStageMask = color_attachment_output; dstStageMask = fragment_shader; srcAccessMask = color_attachment_write; @@ -325,8 +329,8 @@ dependencyFlags = by_region; }, { - srcSubpass = 1; - dstSubpass = 2; + srcSubpass = 1; // g-buffer + dstSubpass = 2; // lighting srcStageMask = color_attachment_output; dstStageMask = fragment_shader; srcAccessMask = color_attachment_write; @@ -334,8 +338,8 @@ dependencyFlags = by_region; }, { - srcSubpass = 2; - dstSubpass = 4; + srcSubpass = 2; // lighting + dstSubpass = 4; // compose srcStageMask = color_attachment_output; dstStageMask = fragment_shader; srcAccessMask = color_attachment_write; @@ -343,8 +347,8 @@ dependencyFlags = by_region; }, { - srcSubpass = 3; - dstSubpass = 4; + srcSubpass = 3; // translucent + dstSubpass = 4; // compose srcStageMask = color_attachment_output; dstStageMask = fragment_shader; srcAccessMask = color_attachment_write; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 03e200fc7..825f71a59 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -77,6 +77,36 @@ }, ); }; + lighting_attach_pool = { + flags = 0; + maxSets = $frames.size; + bindings = ( + { + type = input_attachment; + descriptorCount = "3z * $frames.size"; + }, + ); + }; + lighting_lights_pool = { + flags = 0; + maxSets = $frames.size; + bindings = ( + { + type = uniform_buffer; + descriptorCount = $frames.size; + }, + ); + }; + compose_attach_pool = { + flags = 0; + maxSets = $frames.size; + bindings = ( + { + type = input_attachment; + descriptorCount = "2z * $frames.size"; + }, + ); + }; }; setLayouts = { twod_set = { @@ -208,20 +238,51 @@ }, ); }; - something = { - flags = 0; + lighting_attach = { bindings = ( { binding = 0; - descriptorType = sampled_image; + descriptorType = input_attachment; descriptorCount = 1; stageFlags = fragment; }, { binding = 1; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 2; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, + ); + }; + lighting_lights = { + bindings = ( + { + binding = 0; descriptorType = uniform_buffer; descriptorCount = 1; - stageFlags = vertex; + stageFlags = fragment; + }, + ); + }; + compose_attach = { + bindings = ( + { + binding = 0; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, + { + binding = 1; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; }, ); }; @@ -261,15 +322,11 @@ }, ); }; - something = { - setLayouts = (something); - pushConstantRanges = ( - { - stageFlags = fragment; - offset = 0; - size = "4 * 4"; - }, - ); + lighting_layout = { + setLayouts = (lighting_attach, lighting_lights); + }; + compose_layout = { + setLayouts = (compose_attach); }; }; pipelines = { @@ -758,6 +815,194 @@ layout = twod_layout; //renderPass = renderpass; }; + lighting = { + subpass = 2; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/passthrough.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/lighting.frag; + }, + ); + vertexInput = { + bindings = ( + { + binding = 0; + stride = "4 * 4"; + inputRate = vertex; + }, + ); + attributes = ( + { + location = 0; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 0; + }, + ); + }; + inputAssembly = { + topology = triangle_strip; + primitiveRestartEnable = false; + }; + viewport = { + viewports = ( + { + x = 0; y = 0; + width = 640; height = 480; + minDepth = 0; maxDepth = 1; + } + ); + scissors = ( + { + offset = { x = 0; y = 0 }; + extent = { width = 640; height = 480; }; + }, + ); + }; + rasterization = { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = fill; + cullMode = back; + frontFace = counter_clockwise; + depthBiasEnable = false; + lineWidth = 1; + }; + multisample = { + rasterizationSamples = $msaaSamples; + sampleShadingEnable = false; + minSampleShading = 0.5f; + alphaToCoverageEnable = false; + alphaToOneEnable = false; + }; + depthStencil = { + depthTestEnable = false; + depthWriteEnable = false; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + colorBlend = { + logicOpEnable = false; + attachments = ( + { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }, + ); + }; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = lighting_layout; + //renderPass = renderpass; + }; + compose = { + subpass = 4; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/passthrough.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/compose.frag; + }, + ); + vertexInput = { + bindings = ( + { + binding = 0; + stride = "4 * 4"; + inputRate = vertex; + }, + ); + attributes = ( + { + location = 0; + binding = 0; + format = r32g32b32a32_sfloat; + offset = 0; + }, + ); + }; + inputAssembly = { + topology = triangle_strip; + primitiveRestartEnable = false; + }; + viewport = { + viewports = ( + { + x = 0; y = 0; + width = 640; height = 480; + minDepth = 0; maxDepth = 1; + } + ); + scissors = ( + { + offset = { x = 0; y = 0 }; + extent = { width = 640; height = 480; }; + }, + ); + }; + rasterization = { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = fill; + cullMode = back; + frontFace = counter_clockwise; + depthBiasEnable = false; + lineWidth = 1; + }; + multisample = { + rasterizationSamples = $msaaSamples; + sampleShadingEnable = false; + minSampleShading = 0.5f; + alphaToCoverageEnable = false; + alphaToOneEnable = false; + }; + depthStencil = { + depthTestEnable = false; + depthWriteEnable = false; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + colorBlend = { + logicOpEnable = false; + attachments = ( + { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }, + ); + }; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = compose_layout; + //renderPass = renderpass; + }; }; renderpass = { attachments = ( diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index 4063e6f33..4168d9b63 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -73,6 +73,10 @@ static static #include "libs/video/renderer/vulkan/shader/bsp_sky.frag.spvc" static +#include "libs/video/renderer/vulkan/shader/lighting.frag.spvc" +static +#include "libs/video/renderer/vulkan/shader/compose.frag.spvc" +static #include "libs/video/renderer/vulkan/shader/alias.vert.spvc" static #include "libs/video/renderer/vulkan/shader/alias_depth.vert.spvc" @@ -101,6 +105,8 @@ static shaderdata_t builtin_shaders[] = { { "bsp_gbuf.geom", bsp_gbuf_geom, sizeof (bsp_gbuf_geom) }, { "bsp_gbuf.frag", bsp_gbuf_frag, sizeof (bsp_gbuf_frag) }, { "bsp_sky.frag", bsp_sky_frag, sizeof (bsp_sky_frag) }, + { "lighting.frag", lighting_frag, sizeof (lighting_frag) }, + { "compose.frag", compose_frag, sizeof (compose_frag) }, { "alias.vert", alias_vert, sizeof (alias_vert) }, { "alias_depth.vert", alias_depth_vert, sizeof (alias_depth_vert) }, { "alias.frag", alias_frag, sizeof (alias_frag) }, diff --git a/libs/video/renderer/vulkan/shader/compose.frag b/libs/video/renderer/vulkan/shader/compose.frag new file mode 100644 index 000000000..39ac94845 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/compose.frag @@ -0,0 +1,19 @@ +#version 450 + +layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput opaque; +layout (input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput translucent; + +layout (location = 0) out vec4 frag_color; + +void +main (void) +{ + vec3 o; + vec4 t; + vec3 c; + + o = subpassLoad (opaque).rgb; + t = subpassLoad (translucent); + c = mix (o, t.rgb, t.a); + frag_color = vec4 (c, 1); +} diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag new file mode 100644 index 000000000..555682645 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -0,0 +1,33 @@ +#version 450 + +layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput depth; +layout (input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput color; +layout (input_attachment_index = 2, set = 0, binding = 2) uniform subpassInput normal; + +struct LightData { + vec3 color; + float dist; + vec3 position; + int type; + vec3 direction; + float cone; +}; + +layout (constant_id = 0) const int MaxLights = 8; +/*layout (set = 1, binding = 0) uniform Lights { + int lightCount; + LightData lights[MaxLights]; +};*/ + +layout (location = 0) out vec4 frag_color; + +void +main (void) +{ + float d = subpassLoad (depth).r; + vec4 c; + + //c = vec4 (d, d, d, 1); + c = vec4 (subpassLoad (color).rgb, 1); + frag_color = c; +} diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 72ec5abbb..de12d60c0 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -1259,6 +1259,8 @@ QFV_ParseImageSet (vulkan_ctx_t *ctx, plitem_t *item, plitem_t *properties) dfunc->vkCreateImage (device->dev, &create.info[i], 0, &set->a[i]); const char *name = PL_KeyAtIndex (item, i); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, set->a[i], + va (ctx->va_ctx, "image:%s", name)); name = va (ctx->va_ctx, "$"QFV_PROPERTIES".images.%s", name); QFV_AddHandle (ctx->images, name, (uint64_t) set->a[i]); } diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 8468335c1..d3663d0df 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -176,8 +176,7 @@ alias_begin_subpass (QFV_AliasSubpass subpass, VkPipeline pipeline, }; dfunc->vkBeginCommandBuffer (cmd, &beginInfo); - dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - pipeline); + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); //VkDescriptorSet sets[] = { // aframe->descriptors[0].dstSet, // aframe->descriptors[1].dstSet, diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 8b33cebb3..046ba6c0a 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -827,6 +827,15 @@ draw_elechain (elechain_t *ec, VkPipelineLayout layout, qfv_devfuncs_t *dfunc, continue; dfunc->vkCmdDrawIndexed (cmd, el->index_count, 1, el->first_index, 0, 0); + } +} + +static void +reset_elechain (elechain_t *ec) +{ + elements_t *el; + + for (el = ec->elements; el; el = el->next) { el->first_index = 0; el->index_count = 0; } @@ -1167,6 +1176,7 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) bframe->cmdSet.a[QFV_bspDepth]); draw_elechain (ec, bctx->layout, dfunc, bframe->cmdSet.a[QFV_bspGBuffer]); + reset_elechain (ec); } tex->elechain = 0; tex->elechain_tail = &tex->elechain; @@ -1280,6 +1290,7 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) for (ec = tex->elechain; ec; ec = ec->next) { draw_elechain (ec, bctx->layout, dfunc,//FIXME bframe->cmdSet.a[QFV_bspTranslucent]); + reset_elechain (ec); } tex->elechain = 0; tex->elechain_tail = &tex->elechain; @@ -1295,6 +1306,7 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) for (ec = tex->elechain; ec; ec = ec->next) { draw_elechain (ec, bctx->layout, dfunc,//FIXME bframe->cmdSet.a[QFV_bspTranslucent]); + reset_elechain (ec); } tex->elechain = 0; tex->elechain_tail = &tex->elechain; diff --git a/libs/video/renderer/vulkan/vulkan_compose.c b/libs/video/renderer/vulkan/vulkan_compose.c new file mode 100644 index 000000000..e2748dcb3 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_compose.c @@ -0,0 +1,175 @@ +/* + vulkan_compose.c + + Vulkan compose pass pipeline + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/2/23 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "qfalloca.h" + +#include "QF/sys.h" + +#include "QF/Vulkan/qf_compose.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" + +#include "r_internal.h" +#include "vid_vulkan.h" + +void +Vulkan_Compose_Draw (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + composectx_t *cctx = ctx->compose_context; + __auto_type frame = &ctx->frames.a[ctx->curFrame]; + composeframe_t *cframe = &cctx->frames.a[ctx->curFrame]; + VkCommandBuffer cmd = cframe->cmd; + + DARRAY_APPEND (&frame->cmdSets[QFV_passCompose], cmd); + + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + ctx->renderpass, QFV_passCompose, + frame->framebuffer, + 0, 0, 0, + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + cctx->pipeline); + + cframe->imageInfo[0].imageView = ctx->attachment_views->a[3]; + cframe->imageInfo[1].imageView = ctx->attachment_views->a[4]; + dfunc->vkUpdateDescriptorSets (device->dev, 2, cframe->descriptors, 0, 0); + + VkDescriptorSet sets[] = { + cframe->descriptors[0].dstSet, + }; + dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + cctx->layout, 0, 1, sets, 0, 0); + + VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; + VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; + dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); + + VkDeviceSize offset = 0; + dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &ctx->quad_buffer, &offset); + dfunc->vkCmdDraw (cmd, 4, 1, 0, 0); + + dfunc->vkEndCommandBuffer (cmd); +} + +static VkDescriptorImageInfo base_image_info = { + 0, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL +}; +static VkWriteDescriptorSet base_image_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + 0, 0, 0 +}; + +void +Vulkan_Compose_Init (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + composectx_t *cctx = calloc (1, sizeof (composectx_t)); + ctx->compose_context = cctx; + + size_t frames = ctx->frames.size; + DARRAY_INIT (&cctx->frames, frames); + DARRAY_RESIZE (&cctx->frames, frames); + cctx->frames.grow = 0; + + cctx->pipeline = Vulkan_CreatePipeline (ctx, "compose"); + cctx->layout = Vulkan_CreatePipelineLayout (ctx, "compose_layout"); + + __auto_type cmdSet = QFV_AllocCommandBufferSet (1, alloca); + + __auto_type attach = QFV_AllocDescriptorSetLayoutSet (frames, alloca); + for (size_t i = 0; i < frames; i++) { + attach->a[i] = Vulkan_CreateDescriptorSetLayout (ctx, + "compose_attach"); + } + __auto_type attach_pool = Vulkan_CreateDescriptorPool (ctx, + "compose_attach_pool"); + + __auto_type attach_set = QFV_AllocateDescriptorSet (device, attach_pool, + attach); + for (size_t i = 0; i < frames; i++) { + __auto_type cframe = &cctx->frames.a[i]; + + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet); + cframe->cmd = cmdSet->a[0]; + + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + cframe->cmd, "cmd:compose"); + for (int j = 0; j < COMPOSE_IMAGE_INFOS; j++) { + cframe->imageInfo[j] = base_image_info; + cframe->imageInfo[j].sampler = 0; + cframe->descriptors[j] = base_image_write; + cframe->descriptors[j].dstSet = attach_set->a[i]; + cframe->descriptors[j].dstBinding = j; + cframe->descriptors[j].pImageInfo = &cframe->imageInfo[j]; + } + } + free (attach_set); +} + +void +Vulkan_Compose_Shutdown (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + composectx_t *cctx = ctx->compose_context; + + dfunc->vkDestroyPipeline (device->dev, cctx->pipeline, 0); + free (cctx->frames.a); + free (cctx); +} diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c new file mode 100644 index 000000000..604e7ff94 --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -0,0 +1,202 @@ +/* + vulkan_lighting.c + + Vulkan lighting pass pipeline + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/2/23 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "qfalloca.h" + +#include "QF/sys.h" + +#include "QF/Vulkan/qf_lighting.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/image.h" + +#include "r_internal.h" +#include "vid_vulkan.h" + +void +Vulkan_Lighting_Draw (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + lightingctx_t *lctx = ctx->lighting_context; + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; + lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; + VkCommandBuffer cmd = lframe->cmd; + + DARRAY_APPEND (&cframe->cmdSets[QFV_passLighting], cmd); + + dfunc->vkResetCommandBuffer (cmd, 0); + VkCommandBufferInheritanceInfo inherit = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, + ctx->renderpass, QFV_passLighting, + cframe->framebuffer, + 0, 0, 0, + }; + VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT + | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit, + }; + dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + lctx->pipeline); + + lframe->imageInfo[0].imageView = ctx->attachment_views->a[0]; + lframe->imageInfo[1].imageView = ctx->attachment_views->a[1]; + lframe->imageInfo[2].imageView = ctx->attachment_views->a[2]; + dfunc->vkUpdateDescriptorSets (device->dev, 3, lframe->descriptors+1, 0, 0); + + VkDescriptorSet sets[] = { + lframe->descriptors[1].dstSet, + lframe->descriptors[0].dstSet, + }; + dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + lctx->layout, 0, 2, sets, 0, 0); + + VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; + VkRect2D scissor = { {0, 0}, {vid.width, vid.height} }; + dfunc->vkCmdSetViewport (cmd, 0, 1, &viewport); + dfunc->vkCmdSetScissor (cmd, 0, 1, &scissor); + + VkDeviceSize offset = 0; + dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &ctx->quad_buffer, &offset); + dfunc->vkCmdDraw (cmd, 4, 1, 0, 0); + + dfunc->vkEndCommandBuffer (cmd); +} + +static VkDescriptorBufferInfo base_buffer_info = { + 0, 0, VK_WHOLE_SIZE +}; +static VkDescriptorImageInfo base_image_info = { + 0, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL +}; +static VkWriteDescriptorSet base_buffer_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 0, 0, 0 +}; +static VkWriteDescriptorSet base_image_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, + 0, 0, 0 +}; + +void +Vulkan_Lighting_Init (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + + lightingctx_t *lctx = calloc (1, sizeof (lightingctx_t)); + ctx->lighting_context = lctx; + + size_t frames = ctx->frames.size; + DARRAY_INIT (&lctx->frames, frames); + DARRAY_RESIZE (&lctx->frames, frames); + lctx->frames.grow = 0; + + lctx->pipeline = Vulkan_CreatePipeline (ctx, "lighting"); + lctx->layout = Vulkan_CreatePipelineLayout (ctx, "lighting_layout"); + + __auto_type cmdSet = QFV_AllocCommandBufferSet (1, alloca); + + __auto_type attach = QFV_AllocDescriptorSetLayoutSet (frames, alloca); + __auto_type lights = QFV_AllocDescriptorSetLayoutSet (frames, alloca); + for (size_t i = 0; i < frames; i++) { + attach->a[i] = Vulkan_CreateDescriptorSetLayout (ctx, + "lighting_attach"); + lights->a[i] = Vulkan_CreateDescriptorSetLayout (ctx, + "lighting_lights"); + } + __auto_type attach_pool = Vulkan_CreateDescriptorPool (ctx, + "lighting_attach_pool"); + __auto_type lights_pool = Vulkan_CreateDescriptorPool (ctx, + "lighting_lights_pool"); + + __auto_type attach_set = QFV_AllocateDescriptorSet (device, attach_pool, + attach); + __auto_type lights_set = QFV_AllocateDescriptorSet (device, lights_pool, + lights); + for (size_t i = 0; i < frames; i++) { + __auto_type lframe = &lctx->frames.a[i]; + + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet); + lframe->cmd = cmdSet->a[0]; + + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, + lframe->cmd, "cmd:lighting"); + for (int j = 0; j < LIGHTING_BUFFER_INFOS; j++) { + lframe->bufferInfo[j] = base_buffer_info; + lframe->descriptors[j] = base_buffer_write; + lframe->descriptors[j].dstSet = lights_set->a[i]; + lframe->descriptors[j].dstBinding = j; + lframe->descriptors[j].pBufferInfo = &lframe->bufferInfo[j]; + } + for (int j = 0; j < LIGHTING_IMAGE_INFOS; j++) { + lframe->imageInfo[j] = base_image_info; + lframe->imageInfo[j].sampler = 0; + int k = j + LIGHTING_BUFFER_INFOS; + lframe->descriptors[k] = base_image_write; + lframe->descriptors[k].dstSet = attach_set->a[i]; + lframe->descriptors[k].dstBinding = j; + lframe->descriptors[k].pImageInfo = &lframe->imageInfo[j]; + } + } + free (attach_set); + free (lights_set); +} + +void +Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + lightingctx_t *lctx = ctx->lighting_context; + + dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0); + free (lctx->frames.a); + free (lctx); +} diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 98fec5945..909f26236 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -324,6 +324,53 @@ Vulkan_CreateRenderPass (vulkan_ctx_t *ctx) item = qfv_load_renderpass (ctx, "clearValues"); QFV_ParseClearValues (ctx, item, ctx->renderpassDef); printf ("renderpass: %p\n", ctx->renderpass); + + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + static float quad_vertices[] = { + -1, -1, 0, 1, + -1, 1, 0, 1, + 1, -1, 0, 1, + 1, 1, 0, 1, + }; + ctx->quad_buffer = QFV_CreateBuffer (device, sizeof (quad_vertices), + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + ctx->quad_memory = QFV_AllocBufferMemory (device, ctx->quad_buffer, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, 0); + QFV_BindBufferMemory (device, ctx->quad_buffer, ctx->quad_memory, 0); + + qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); + float *verts = QFV_PacketExtend (packet, sizeof (quad_vertices)); + memcpy (verts, quad_vertices, sizeof (quad_vertices)); + + VkBufferMemoryBarrier wr_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + ctx->quad_buffer, 0, sizeof (quad_vertices) }, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 1, wr_barriers, 0, 0); + VkBufferCopy copy_region[] = { + { packet->offset, 0, sizeof (quad_vertices) }, + }; + dfunc->vkCmdCopyBuffer (packet->cmd, ctx->staging->buffer, + ctx->quad_buffer, 1, ©_region[0]); + VkBufferMemoryBarrier rd_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + ctx->quad_buffer, 0, sizeof (quad_vertices) }, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + 0, 0, 0, 1, rd_barriers, 0, 0); + QFV_PacketSubmit (packet); } void @@ -333,6 +380,9 @@ Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx) qfv_devfuncs_t *dfunc = device->funcs; dfunc->vkDestroyRenderPass (device->dev, ctx->renderpass, 0); + + dfunc->vkFreeMemory (device->dev, ctx->quad_memory, 0); + dfunc->vkDestroyBuffer (device->dev, ctx->quad_buffer, 0); } VkPipeline From 6c1d6666b410596212a045284e77047b397bc201 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 24 Feb 2021 20:24:46 +0900 Subject: [PATCH 363/435] [vulkan] Actually write the alias g-buffer commands It seems to help for some reason. --- libs/video/renderer/vulkan/qfpipeline.plist | 6 ------ libs/video/renderer/vulkan/shader/alias_gbuf.frag | 4 ++-- libs/video/renderer/vulkan/vulkan_alias.c | 4 ++++ 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 825f71a59..cb7cf82f9 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -177,12 +177,6 @@ }, { binding = 1; - descriptorType = uniform_buffer; - descriptorCount = 1; - stageFlags = fragment; - }, - { - binding = 2; descriptorType = combined_image_sampler; descriptorCount = 1; stageFlags = fragment; diff --git a/libs/video/renderer/vulkan/shader/alias_gbuf.frag b/libs/video/renderer/vulkan/shader/alias_gbuf.frag index e8b14a305..6ef33dd43 100644 --- a/libs/video/renderer/vulkan/shader/alias_gbuf.frag +++ b/libs/video/renderer/vulkan/shader/alias_gbuf.frag @@ -1,5 +1,5 @@ #version 450 -layout (set = 0, binding = 2) uniform sampler2DArray Skin; +layout (set = 0, binding = 1) uniform sampler2DArray Skin; layout (push_constant) uniform PushConstants { layout (offset = 68) @@ -28,5 +28,5 @@ main (void) c += texture (Skin, vec3 (st, 2)) * unpackUnorm4x8(colorB); frag_color = c; - frag_normal = vec4(normal, 0); + frag_normal = vec4(normal, 1); } diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index d3663d0df..cc1905c4a 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -149,6 +149,10 @@ Vulkan_DrawAlias (entity_t *ent, vulkan_ctx_t *ctx) 0, vertex_constants, sizeof (vertex_constants), fragment_constants, sizeof (fragment_constants), hdr, ctx); + emit_commands (aframe->cmdSet.a[QFV_aliasGBuffer], ent->pose1, ent->pose2, + skin, vertex_constants, sizeof (vertex_constants), + fragment_constants, sizeof (fragment_constants), + hdr, ctx); } static void From f8961e43767128b9d825640aa22e33327a8067be Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 25 Feb 2021 10:12:19 +0900 Subject: [PATCH 364/435] [qflight] Fix some typos in comments --- tools/qflight/include/properties.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/qflight/include/properties.h b/tools/qflight/include/properties.h index d5e73db7f..8d39361b7 100644 --- a/tools/qflight/include/properties.h +++ b/tools/qflight/include/properties.h @@ -76,7 +76,7 @@ void parse_color (const char *str, vec3_t color); \arg HalfLife "R G B i" where R G & B are 0-255 and i is the same as for normal id lights. The RGB values will be scaled by 1/255 such that 255 becomes 1.0. - \arg RGB "R B B" where R G & B are left as-is and the intensity + \arg RGB "R G B" where R G & B are left as-is and the intensity is set to 1.0. \arg id Standard quake single value light intensity. The color is set to white ([1.0 1.0 1.0]). @@ -124,7 +124,7 @@ int parse_noise (const char *arg); The database is loaded via LoadProperties(). - If a set of properties named "worldspawn" is in the database, the it + If a set of properties named "worldspawn" is in the database, then it will be used for default values, otherwise the database will be ignored. @@ -163,7 +163,7 @@ void set_sun_properties (entity_t *ent, struct plitem_s *dict); Supported properties: \arg \c light see \ref parse_light \arg \c style light style: 0-254 - \arg \c angle spotlight con angle in degress. defaults to 20 + \arg \c angle spotlight cone angle in degress. defaults to 20 \arg \c wait light "falloff". defaults to 1.0 \arg \c lightradius size of light. interacts with falloff for distance clipping (?). defaults to 0 From 4eb07220cd7eca8cdd9696cddb10a7515e5d3366 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 25 Feb 2021 11:55:25 +0900 Subject: [PATCH 365/435] [util] Make plists more const-correct --- include/QF/qfplist.h | 6 +++--- libs/gamecode/pr_parse.c | 2 +- libs/util/qfplist.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index f1cc95b8a..cef305086 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -132,7 +132,7 @@ plitem_t *PL_GetPropertyList (const char *string, \return the text representation of the property list \note You are responsible for freeing the returned string. */ -char *PL_WritePropertyList (plitem_t *pl); +char *PL_WritePropertyList (const plitem_t *pl); /** Retrieve the type of an object. @@ -226,7 +226,7 @@ plitem_t *PL_ObjectAtIndex (const plitem_t *array, int index) __attribute__((pur \return an Array containing Strings or NULL if dict isn't a dictionary \note You are responsible for freeing this array. */ -plitem_t *PL_D_AllKeys (plitem_t *dict); +plitem_t *PL_D_AllKeys (const plitem_t *dict); /** Retrieve the number of keys in a dictionary. @@ -265,7 +265,7 @@ qboolean PL_A_AddObject (plitem_t *array, plitem_t *item); \return number of objects in the array */ -int PL_A_NumObjects (plitem_t *array) __attribute__((pure)); +int PL_A_NumObjects (const plitem_t *array) __attribute__((pure)); /** Insert an item into an array before the specified location. diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index 0f0a3dea5..b33d14e6c 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -501,7 +501,7 @@ ED_Parse (progs_t *pr, const char *data) // new style (plist) entity data entity_list = PL_GetPropertyList (data, pr->hashlink_freelist); } else { - // oldstyle entity data + // old style entity data Script_UngetToken (script); entity_list = ED_ConvertToPlist (script, 0, pr->hashlink_freelist); } diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 6e4726c95..56c168168 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -330,7 +330,7 @@ PL_RemoveObjectForKey (const plitem_t *item, const char *key) } VISIBLE plitem_t * -PL_D_AllKeys (plitem_t *item) +PL_D_AllKeys (const plitem_t *item) { pldict_t *dict = (pldict_t *) item->data; dictkey_t *current; @@ -440,7 +440,7 @@ PL_A_AddObject (plitem_t *array, plitem_t *item) } VISIBLE int -PL_A_NumObjects (plitem_t *array) +PL_A_NumObjects (const plitem_t *array) { if (array->type != QFArray) return 0; @@ -1056,7 +1056,7 @@ write_string (dstring_t *dstr, const char *str) } static void -write_item (dstring_t *dstr, plitem_t *item, int level) +write_item (dstring_t *dstr, const plitem_t *item, int level) { dictkey_t *current; plarray_t *array; @@ -1107,7 +1107,7 @@ write_item (dstring_t *dstr, plitem_t *item, int level) } VISIBLE char * -PL_WritePropertyList (plitem_t *pl) +PL_WritePropertyList (const plitem_t *pl) { dstring_t *dstr = dstring_newstr (); From 918c3af095a4e840689f5092d864b5d9ec1c5efd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 25 Feb 2021 13:46:33 +0900 Subject: [PATCH 366/435] [vulkan] Add a position buffer to the g-buffer While I could reconstruct the position from the screen coords and depth, this is easier and good enough for now. Reconstruction is an optimization thing. --- include/QF/Vulkan/qf_lighting.h | 2 +- include/QF/Vulkan/qf_vid.h | 10 ++ libs/video/renderer/vulkan/deferred.plist | 96 ++++++++++++++----- libs/video/renderer/vulkan/qfpipeline.plist | 30 +++++- libs/video/renderer/vulkan/shader/alias.vert | 4 +- .../renderer/vulkan/shader/alias_gbuf.frag | 4 +- .../renderer/vulkan/shader/bsp_gbuf.frag | 3 + .../renderer/vulkan/shader/bsp_gbuf.geom | 13 ++- .../renderer/vulkan/shader/bsp_gbuf.vert | 3 +- .../renderer/vulkan/shader/lighting.frag | 12 ++- libs/video/renderer/vulkan/vulkan_compose.c | 6 +- libs/video/renderer/vulkan/vulkan_lighting.c | 13 ++- 12 files changed, 154 insertions(+), 42 deletions(-) diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h index d2cee31ac..fab2ffc3d 100644 --- a/include/QF/Vulkan/qf_lighting.h +++ b/include/QF/Vulkan/qf_lighting.h @@ -37,7 +37,7 @@ #include "QF/Vulkan/command.h" #define LIGHTING_BUFFER_INFOS 1 -#define LIGHTING_IMAGE_INFOS 3 +#define LIGHTING_IMAGE_INFOS 4 typedef struct lightingframe_s { VkCommandBuffer cmd; diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index db423d014..5ac5dddd4 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -46,6 +46,16 @@ enum { QFV_NumPasses }; +enum { + QFV_attachDepth, + QFV_attachColor, + QFV_attachNormal, + QFV_attachPosition, + QFV_attachOpaque, + QFV_attachTranslucent, + QFV_attachSwapchain, +}; + struct vulkan_ctx_s; void Vulkan_DestroyFrames (struct vulkan_ctx_s *ctx); void Vulkan_CreateFrames (struct vulkan_ctx_s *ctx); diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index 0245906da..6eded7acb 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -12,7 +12,7 @@ mipLevels = 1; arrayLayers = 1; tiling = optimal; - usage = depth_stencil_attachment|input_attachment; + usage = depth_stencil_attachment|input_attachment|transient_attachment; initialLayout = undefined; }; color = { @@ -27,10 +27,10 @@ mipLevels = 1; arrayLayers = 1; tiling = optimal; - usage = color_attachment|input_attachment; + usage = color_attachment|input_attachment|transient_attachment; initialLayout = undefined; }; - normals = { + normal = { imageType = VK_IMAGE_TYPE_2D; format = r16g16b16a16_sfloat; samples = 1; @@ -42,7 +42,22 @@ mipLevels = 1; arrayLayers = 1; tiling = optimal; - usage = color_attachment|input_attachment; + usage = color_attachment|input_attachment|transient_attachment; + initialLayout = undefined; + }; + position = { + imageType = VK_IMAGE_TYPE_2D; + format = r32g32b32a32_sfloat; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment|transient_attachment; initialLayout = undefined; }; opaque = { @@ -57,7 +72,7 @@ mipLevels = 1; arrayLayers = 1; tiling = optimal; - usage = color_attachment|input_attachment; + usage = color_attachment|input_attachment|transient_attachment; initialLayout = undefined; }; translucent = { @@ -72,7 +87,7 @@ mipLevels = 1; arrayLayers = 1; tiling = optimal; - usage = color_attachment|input_attachment; + usage = color_attachment|input_attachment|transient_attachment; initialLayout = undefined; }; }; @@ -109,10 +124,26 @@ layerCount = 1; }; }; - normals = { - image = normals; + normal = { + image = normal; viewType = VK_IMAGE_VIEW_TYPE_2D; - format = $properties.images.normals.format; + format = $properties.images.normal.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; + position = { + image = position; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.position.format; components = { r = identity; g = identity; @@ -160,7 +191,7 @@ }; framebuffer = { renderPass = $properties.renderpass; - attachments = (depth, color, normals, opaque, translucent, + attachments = (depth, color, normal, position, opaque, translucent, "$swapchain.views[$swapImageIndex]"); width = $swapchain.extent.width; height = $swapchain.extent.height; @@ -169,7 +200,8 @@ clearValues = ( { depthStencil = { depth = 1; stencil = 0; }; }, { color = "[0, 0, 0, 1]"; }, // color - { color = "[0, 0, 0, 1]"; }, // normals + { color = "[0, 0, 0, 1]"; }, // normal + { color = "[0, 0, 0, 1]"; }, // position { color = "[0, 0, 0, 1]"; }, // opaque { color = "[0, 0, 0, 0]"; }, // translucent { color = "[0, 0, 0, 1]"; }, // swapchain @@ -197,7 +229,17 @@ finalLayout = color_attachment_optimal; }, { - format = $properties.images.normals.format; + format = $properties.images.normal.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, + { + format = $properties.images.position.format; samples = 1; loadOp = dont_care; storeOp = dont_care; @@ -252,16 +294,20 @@ attachment = 1; layout = color_attachment_optimal; }, - { // normals + { // normal attachment = 2; layout = color_attachment_optimal; }, + { // position + attachment = 3; + layout = color_attachment_optimal; + }, ); depthStencilAttachment = { attachment = 0; layout = depth_stencil_attachment_optimal; }; - preserveAttachments = (4); + preserveAttachments = (5); }, { // 2 lighting pipelineBindPoint = graphics; @@ -274,48 +320,52 @@ attachment = 1; layout = shader_read_only_optimal; }, - { // normals + { // normal attachment = 2; layout = shader_read_only_optimal; }, + { // position + attachment = 3; + layout = shader_read_only_optimal; + }, ); colorAttachments = ( { // opaque - attachment = 3; + attachment = 4; layout = color_attachment_optimal; }, ); - preserveAttachments = (4); + preserveAttachments = (5); }, { // 3 translucent pipelineBindPoint = graphics; colorAttachments = ( { // translucent - attachment = 4; + attachment = 5; layout = color_attachment_optimal; }, ); - preserveAttachments = (0, 1, 2, 3); + preserveAttachments = (0, 1, 2, 3, 4); }, { // 4 compose pipelineBindPoint = graphics; inputAttachments = ( { // opaque - attachment = 3; + attachment = 4; layout = shader_read_only_optimal; }, { // translucent - attachment = 4; + attachment = 5; layout = shader_read_only_optimal; }, ); colorAttachments = ( { // swapchain - attachment = 5; + attachment = 6; layout = color_attachment_optimal; }, ); - preserveAttachments = (0, 1, 2); + preserveAttachments = (0, 1, 2, 3); }, ); dependencies = ( diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index cb7cf82f9..446ed30c6 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -83,7 +83,7 @@ bindings = ( { type = input_attachment; - descriptorCount = "3z * $frames.size"; + descriptorCount = "4z * $frames.size"; }, ); }; @@ -132,7 +132,7 @@ binding = 0; descriptorType = uniform_buffer; descriptorCount = 1; - stageFlags = vertex; + stageFlags = vertex|geometry; }, { binding = 1; @@ -252,6 +252,12 @@ descriptorCount = 1; stageFlags = fragment; }, + { + binding = 3; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, ); }; lighting_lights = { @@ -499,6 +505,16 @@ alphaBlendOp = add; colorWriteMask = r|g|b|a; }, + { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }, ); }; dynamic = { @@ -639,6 +655,16 @@ alphaBlendOp = add; colorWriteMask = r|g|b|a; }, + { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }, { blendEnable = false; srcColorBlendFactor = src_alpha; diff --git a/libs/video/renderer/vulkan/shader/alias.vert b/libs/video/renderer/vulkan/shader/alias.vert index 871c3a0c0..a54b43674 100644 --- a/libs/video/renderer/vulkan/shader/alias.vert +++ b/libs/video/renderer/vulkan/shader/alias.vert @@ -18,7 +18,7 @@ layout (location = 3) in vec3 normalb; layout (location = 4) in vec2 uv; layout (location = 0) out vec2 st; -layout (location = 1) out vec3 position; +layout (location = 1) out vec4 position; layout (location = 2) out vec3 normal; void @@ -32,7 +32,7 @@ main (void) norm = mix (normala, normalb, blend); pos = (Model * vertex); gl_Position = Projection * (View * pos); - position = pos.xyz; + position = pos; normal = mat3 (Model) * norm; st = uv; } diff --git a/libs/video/renderer/vulkan/shader/alias_gbuf.frag b/libs/video/renderer/vulkan/shader/alias_gbuf.frag index 6ef33dd43..0808b87f7 100644 --- a/libs/video/renderer/vulkan/shader/alias_gbuf.frag +++ b/libs/video/renderer/vulkan/shader/alias_gbuf.frag @@ -11,11 +11,12 @@ layout (push_constant) uniform PushConstants { }; layout (location = 0) in vec2 st; -layout (location = 1) in vec3 position; +layout (location = 1) in vec4 position; layout (location = 2) in vec3 normal; layout (location = 0) out vec4 frag_color; layout (location = 1) out vec4 frag_normal; +layout (location = 2) out vec4 frag_position; void main (void) @@ -29,4 +30,5 @@ main (void) frag_color = c; frag_normal = vec4(normal, 1); + frag_position = position; } diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.frag b/libs/video/renderer/vulkan/shader/bsp_gbuf.frag index 272499efa..e4578ce5e 100644 --- a/libs/video/renderer/vulkan/shader/bsp_gbuf.frag +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.frag @@ -15,9 +15,11 @@ layout (push_constant) uniform PushConstants { layout (location = 0) in vec4 tl_st; layout (location = 1) in vec3 direction; layout (location = 2) in vec3 normal; +layout (location = 3) in vec4 position; layout (location = 0) out vec4 frag_color; layout (location = 1) out vec4 frag_normal; +layout (location = 2) out vec4 frag_position; layout (constant_id = 0) const bool doWarp = false; layout (constant_id = 1) const bool doLight = true; @@ -123,4 +125,5 @@ main (void) } frag_color = c;//fogBlend (c); frag_normal = vec4 (normal, 0); + frag_position = position; } diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.geom b/libs/video/renderer/vulkan/shader/bsp_gbuf.geom index f1107f759..bb46ae43a 100644 --- a/libs/video/renderer/vulkan/shader/bsp_gbuf.geom +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.geom @@ -1,5 +1,11 @@ #version 450 +layout (set = 0, binding = 0) uniform Matrices { + mat4 Projection; + mat4 View; + mat4 Sky; +}; + layout (triangles) in; layout (triangle_strip, max_vertices = 3) out; layout (location = 0) in vec4 v_tl_st[]; @@ -8,6 +14,7 @@ layout (location = 1) in vec3 v_direction[]; layout (location = 0) out vec4 tl_st; layout (location = 1) out vec3 direction; layout (location = 2) out vec3 normal; +layout (location = 3) out vec4 position; void main() @@ -16,13 +23,15 @@ main() vec3 b = gl_in[1].gl_Position.xyz; vec3 c = gl_in[2].gl_Position.xyz; - vec3 n = normalize (cross (b - a, c - a)); + vec3 n = normalize (cross (c - a, b - a)); for (int vert = 0; vert < 3; vert++) { - gl_Position = gl_in[vert].gl_Position; + vec4 p = gl_in[vert].gl_Position; + gl_Position = Projection * (View * (p)); tl_st = v_tl_st[vert]; direction = v_direction[vert]; normal = n; + position = p; EmitVertex (); } EndPrimitive (); diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.vert b/libs/video/renderer/vulkan/shader/bsp_gbuf.vert index bb9e87e4a..abfb6c4e6 100644 --- a/libs/video/renderer/vulkan/shader/bsp_gbuf.vert +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.vert @@ -19,7 +19,8 @@ layout (location = 1) out vec3 direction; void main (void) { - gl_Position = Projection * (View * (Model * vertex)); + // geometry shader will take care of Projection and View + gl_Position = Model * vertex; direction = (Sky * vertex).xyz; tl_st = tl_uv; } diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index 555682645..89ea7940d 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -3,6 +3,7 @@ layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput depth; layout (input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput color; layout (input_attachment_index = 2, set = 0, binding = 2) uniform subpassInput normal; +layout (input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput position; struct LightData { vec3 color; @@ -25,9 +26,12 @@ void main (void) { float d = subpassLoad (depth).r; - vec4 c; + vec3 c = subpassLoad (color).rgb; + vec3 n = subpassLoad (normal).rgb; + vec3 p = subpassLoad (position).rgb; - //c = vec4 (d, d, d, 1); - c = vec4 (subpassLoad (color).rgb, 1); - frag_color = c; + c = vec3 (d, d, d); + c = (n + 1)/2; + c = (p / 1024 + 1) / 2; + frag_color = vec4 (c, 1); } diff --git a/libs/video/renderer/vulkan/vulkan_compose.c b/libs/video/renderer/vulkan/vulkan_compose.c index e2748dcb3..fc7316ede 100644 --- a/libs/video/renderer/vulkan/vulkan_compose.c +++ b/libs/video/renderer/vulkan/vulkan_compose.c @@ -82,8 +82,10 @@ Vulkan_Compose_Draw (vulkan_ctx_t *ctx) dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, cctx->pipeline); - cframe->imageInfo[0].imageView = ctx->attachment_views->a[3]; - cframe->imageInfo[1].imageView = ctx->attachment_views->a[4]; + cframe->imageInfo[0].imageView + = ctx->attachment_views->a[QFV_attachOpaque]; + cframe->imageInfo[1].imageView + = ctx->attachment_views->a[QFV_attachTranslucent]; dfunc->vkUpdateDescriptorSets (device->dev, 2, cframe->descriptors, 0, 0); VkDescriptorSet sets[] = { diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 604e7ff94..84c756cdc 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -82,10 +82,15 @@ Vulkan_Lighting_Draw (vulkan_ctx_t *ctx) dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, lctx->pipeline); - lframe->imageInfo[0].imageView = ctx->attachment_views->a[0]; - lframe->imageInfo[1].imageView = ctx->attachment_views->a[1]; - lframe->imageInfo[2].imageView = ctx->attachment_views->a[2]; - dfunc->vkUpdateDescriptorSets (device->dev, 3, lframe->descriptors+1, 0, 0); + lframe->imageInfo[0].imageView = ctx->attachment_views->a[QFV_attachDepth]; + lframe->imageInfo[1].imageView = ctx->attachment_views->a[QFV_attachColor]; + lframe->imageInfo[2].imageView + = ctx->attachment_views->a[QFV_attachNormal]; + lframe->imageInfo[3].imageView + = ctx->attachment_views->a[QFV_attachPosition]; + dfunc->vkUpdateDescriptorSets (device->dev, LIGHTING_IMAGE_INFOS, + lframe->descriptors + LIGHTING_BUFFER_INFOS, + 0, 0); VkDescriptorSet sets[] = { lframe->descriptors[1].dstSet, From 33575f93d59b2d9f3415e6399f8e0c345ebeb4a7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 25 Feb 2021 15:51:54 +0900 Subject: [PATCH 367/435] [vulkan] Implement deferred lighting for dlights Static lights are yet to come (so the screen is black most of the time), but dynamic lights work very nicely (and look very good) despite the falloff being incorrect. --- include/QF/Vulkan/qf_lighting.h | 19 ++++ libs/video/renderer/vulkan/qfpipeline.plist | 9 ++ .../renderer/vulkan/shader/lighting.frag | 38 +++++-- libs/video/renderer/vulkan/vulkan_lighting.c | 99 ++++++++++++++++++- 4 files changed, 152 insertions(+), 13 deletions(-) diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h index fab2ffc3d..8eaa53a6f 100644 --- a/include/QF/Vulkan/qf_lighting.h +++ b/include/QF/Vulkan/qf_lighting.h @@ -36,11 +36,29 @@ #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/command.h" +typedef struct qfv_light_s { + vec3_t color; + float intensity; + vec3_t position; + int radius; + vec3_t direction; + float cone; +} qfv_light_t; + +#define NUM_LIGHTS 128 + +typedef struct qfv_light_buffer_s { + int lightCount; + qfv_light_t lights[NUM_LIGHTS] __attribute__((aligned(16))); +} qfv_light_buffer_t; + + #define LIGHTING_BUFFER_INFOS 1 #define LIGHTING_IMAGE_INFOS 4 typedef struct lightingframe_s { VkCommandBuffer cmd; + VkBuffer light_buffer; VkDescriptorBufferInfo bufferInfo[LIGHTING_BUFFER_INFOS]; VkDescriptorImageInfo imageInfo[LIGHTING_IMAGE_INFOS]; VkWriteDescriptorSet descriptors[LIGHTING_BUFFER_INFOS @@ -54,6 +72,7 @@ typedef struct lightingctx_s { lightingframeset_t frames; VkPipeline pipeline; VkPipelineLayout layout; + VkDeviceMemory light_memory; } lightingctx_t; struct vulkan_ctx_s; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 446ed30c6..536c98a05 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -575,6 +575,15 @@ stage = fragment; name = main; module = $builtin/bsp_gbuf.frag; + specializationInfo = { + mapEntries = ( + { size = 4; offset = 0; constantID = 0; }, + { size = 4; offset = 0; constantID = 1; }, + { size = 4; offset = 0; constantID = 2; }, + { size = 4; offset = 4; constantID = 1; }, + ); + data = <00000000ffffffff>; + }; }, ); vertexInput = { diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index 89ea7940d..9eef7c8bd 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -7,31 +7,49 @@ layout (input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput p struct LightData { vec3 color; - float dist; + float intensity; vec3 position; - int type; + int radius; vec3 direction; float cone; }; -layout (constant_id = 0) const int MaxLights = 8; -/*layout (set = 1, binding = 0) uniform Lights { +layout (constant_id = 0) const int MaxLights = 128; +layout (set = 1, binding = 0) uniform Lights { int lightCount; LightData lights[MaxLights]; -};*/ +}; layout (location = 0) out vec4 frag_color; +vec3 +calc_light (LightData light, vec3 position, vec3 normal) +{ + vec3 dist = light.position - position; + vec3 incoming = normalize (dist); + float spotdot = -dot (incoming, light.direction); + float lightdot = dot (incoming, normal); + float d = dot (dist, dist); + float r = light.radius; + + float intensity = light.intensity * step (d, r * r); + intensity *= step (spotdot, light.cone) * clamp (lightdot, 0, 1); + return light.color * intensity; +} + void main (void) { - float d = subpassLoad (depth).r; + //float d = subpassLoad (depth).r; vec3 c = subpassLoad (color).rgb; vec3 n = subpassLoad (normal).rgb; vec3 p = subpassLoad (position).rgb; + vec3 light = vec3 (0); - c = vec3 (d, d, d); - c = (n + 1)/2; - c = (p / 1024 + 1) / 2; - frag_color = vec4 (c, 1); + if (MaxLights > 0) { + for (int i = 0; i < lightCount; i++) { + light += calc_light (lights[i], p, n); + } + } + frag_color = vec4 (c * light, 1); } diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 84c756cdc..8e41cf312 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -42,22 +42,85 @@ #include "qfalloca.h" #include "QF/sys.h" +#include "QF/va.h" #include "QF/Vulkan/qf_lighting.h" +#include "QF/Vulkan/buffer.h" #include "QF/Vulkan/debug.h" #include "QF/Vulkan/descriptor.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" +#include "QF/Vulkan/staging.h" + +#include "compat.h" #include "r_internal.h" #include "vid_vulkan.h" +static void +update_lights (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + lightingctx_t *lctx = ctx->lighting_context; + lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; + + dlight_t *lights[NUM_LIGHTS]; + qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); + qfv_light_buffer_t *light_data = QFV_PacketExtend (packet, + sizeof (*light_data)); + + light_data->lightCount = 0; + R_FindNearLights (r_origin, NUM_LIGHTS - 1, lights); + for (int i = 0; i < NUM_LIGHTS - 1; i++) { + if (!lights[i]) { + break; + } + light_data->lightCount++; + VectorCopy (lights[i]->color, light_data->lights[i].color); + VectorCopy (lights[i]->origin, light_data->lights[i].position); + light_data->lights[i].radius = lights[i]->radius; + light_data->lights[i].intensity = 1; + VectorZero (light_data->lights[i].direction); + light_data->lights[i].cone = 1; + } + + VkBufferMemoryBarrier wr_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + lframe->light_buffer, 0, sizeof (qfv_light_buffer_t) }, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, 0, 0, 1, wr_barriers, 0, 0); + VkBufferCopy copy_region[] = { + { packet->offset, 0, sizeof (qfv_light_buffer_t) }, + }; + dfunc->vkCmdCopyBuffer (packet->cmd, ctx->staging->buffer, + lframe->light_buffer, 1, ©_region[0]); + VkBufferMemoryBarrier rd_barriers[] = { + { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + lframe->light_buffer, 0, sizeof (qfv_light_buffer_t) }, + }; + dfunc->vkCmdPipelineBarrier (packet->cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, + 0, 0, 0, 1, rd_barriers, 0, 0); + QFV_PacketSubmit (packet); +} + void Vulkan_Lighting_Draw (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + update_lights (ctx); + lightingctx_t *lctx = ctx->lighting_context; __auto_type cframe = &ctx->frames.a[ctx->curFrame]; lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; @@ -82,15 +145,16 @@ Vulkan_Lighting_Draw (vulkan_ctx_t *ctx) dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, lctx->pipeline); + lframe->bufferInfo[0].buffer = lframe->light_buffer; lframe->imageInfo[0].imageView = ctx->attachment_views->a[QFV_attachDepth]; lframe->imageInfo[1].imageView = ctx->attachment_views->a[QFV_attachColor]; lframe->imageInfo[2].imageView = ctx->attachment_views->a[QFV_attachNormal]; lframe->imageInfo[3].imageView = ctx->attachment_views->a[QFV_attachPosition]; - dfunc->vkUpdateDescriptorSets (device->dev, LIGHTING_IMAGE_INFOS, - lframe->descriptors + LIGHTING_BUFFER_INFOS, - 0, 0); + dfunc->vkUpdateDescriptorSets (device->dev, + LIGHTING_BUFFER_INFOS + LIGHTING_IMAGE_INFOS, + lframe->descriptors, 0, 0); VkDescriptorSet sets[] = { lframe->descriptors[1].dstSet, @@ -134,6 +198,7 @@ void Vulkan_Lighting_Init (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; lightingctx_t *lctx = calloc (1, sizeof (lightingctx_t)); ctx->lighting_context = lctx; @@ -146,6 +211,25 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx) lctx->pipeline = Vulkan_CreatePipeline (ctx, "lighting"); lctx->layout = Vulkan_CreatePipelineLayout (ctx, "lighting_layout"); + __auto_type lbuffers = QFV_AllocBufferSet (frames, alloca); + for (size_t i = 0; i < frames; i++) { + lbuffers->a[i] = QFV_CreateBuffer (device, sizeof (qfv_light_buffer_t), + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, + lbuffers->a[i], + va (ctx->va_ctx, "buffer:lighting:%zd", i)); + } + VkMemoryRequirements requirements; + dfunc->vkGetBufferMemoryRequirements (device->dev, lbuffers->a[0], + &requirements); + lctx->light_memory = QFV_AllocBufferMemory (device, lbuffers->a[0], + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + frames * requirements.size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + lctx->light_memory, "memory:lighting"); + + __auto_type cmdSet = QFV_AllocCommandBufferSet (1, alloca); __auto_type attach = QFV_AllocDescriptorSetLayoutSet (frames, alloca); @@ -171,6 +255,10 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx) QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet); lframe->cmd = cmdSet->a[0]; + lframe->light_buffer = lbuffers->a[i]; + QFV_BindBufferMemory (device, lbuffers->a[i], lctx->light_memory, + i * requirements.size); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER, lframe->cmd, "cmd:lighting"); for (int j = 0; j < LIGHTING_BUFFER_INFOS; j++) { @@ -201,6 +289,11 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx) qfv_devfuncs_t *dfunc = device->funcs; lightingctx_t *lctx = ctx->lighting_context; + for (size_t i = 0; i < lctx->frames.size; i++) { + lightingframe_t *lframe = &lctx->frames.a[i]; + dfunc->vkDestroyBuffer (device->dev, lframe->light_buffer, 0); + } + dfunc->vkFreeMemory (device->dev, lctx->light_memory, 0); dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0); free (lctx->frames.a); free (lctx); From fd97bb145674f55a85b9e395e626794d066a9129 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 25 Feb 2021 16:11:47 +0900 Subject: [PATCH 368/435] [vulkan] Implement linear falloff It's possibly too bright, but it might be the lights themselves. Still, it looks better than the no-falloff implementation. --- libs/video/renderer/vulkan/shader/lighting.frag | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index 9eef7c8bd..3dfb755be 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -29,12 +29,12 @@ calc_light (LightData light, vec3 position, vec3 normal) vec3 incoming = normalize (dist); float spotdot = -dot (incoming, light.direction); float lightdot = dot (incoming, normal); - float d = dot (dist, dist); + float d = sqrt (dot (dist, dist)); float r = light.radius; - float intensity = light.intensity * step (d, r * r); + float intensity = light.intensity * step (d, r); intensity *= step (spotdot, light.cone) * clamp (lightdot, 0, 1); - return light.color * intensity; + return light.color * intensity * (r - d); } void From 407ea15e35260aba8f159402a3ab23798eb96a52 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 2 Mar 2021 15:05:19 +0900 Subject: [PATCH 369/435] [util] Fix some test bitrot --- libs/util/test/test-plist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/util/test/test-plist.c b/libs/util/test/test-plist.c index 0335493f2..bc8e0457a 100644 --- a/libs/util/test/test-plist.c +++ b/libs/util/test/test-plist.c @@ -29,7 +29,7 @@ test_string_io (const char *str) item = PL_NewString (str); saved = PL_WritePropertyList (item); PL_Free (item); - item = PL_GetPropertyList (saved); + item = PL_GetPropertyList (saved, 0); res = PL_String (item); if (!strcmp (str, res)) return 1; From 22c0bec03a9017529e63467d8769cb32612fe6ae Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Mar 2021 13:02:35 +0900 Subject: [PATCH 370/435] [build] Clean up obsolete QF_PROCESS_NEED_DIRS Its need went away with the shift to non-recursive make. The macro is still available just in case. --- config.d/build_control.m4 | 8 -------- 1 file changed, 8 deletions(-) diff --git a/config.d/build_control.m4 b/config.d/build_control.m4 index be71d59f4..09e4a10c0 100644 --- a/config.d/build_control.m4 +++ b/config.d/build_control.m4 @@ -260,13 +260,8 @@ fi QF_NEED(top, [libs hw nq qtv qw]) -QF_PROCESS_NEED_DIRS(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis wad wav]) QF_PROCESS_NEED_FUNC(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis wad wav], QF_NEED(top,tools)) -QF_PROCESS_NEED_DIRS(libs,[util gamecode ruamoko gib audio image models video console net qw client]) - -QF_PROCESS_NEED_DIRS(ruamoko,[qwaq]) - if test "$ENABLE_tools_qfcc" = "yes" -a "$ENABLE_tools_pak" = "yes"; then QF_NEED(top, [ruamoko]) qfac_qfcc_include_qf="\$(qfcc_include_qf)" @@ -294,10 +289,7 @@ if test "$HAVE_ZLIB" = "yes"; then fi QF_SUBST(progs_gz) -QF_PROCESS_NEED_DIRS(top, [libs hw nq qtv qw tools ruamoko]) - QF_PROCESS_NEED_LIBS(swrend, [asm]) -QF_PROCESS_NEED_DIRS(vid_render, [gl glsl sw sw32 vulkan]) QF_PROCESS_NEED_LIBS(models, [gl glsl sw vulkan], [libs/models]) QF_PROCESS_NEED_LIBS(alias, [gl glsl sw vulkan], [libs/models/alias]) QF_PROCESS_NEED_LIBS(brush, [gl glsl sw vulkan], [libs/models/brush]) From 9617bbef97be221895953c426d847b365005574e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Mar 2021 13:04:26 +0900 Subject: [PATCH 371/435] [build] Create static libs for render targets The static libs are used to build the plugins, but make it easy to use only those modules needed for tests. Fixes the link error when running "make check" with non-static plugins. --- config.d/build_control.m4 | 8 ++++ libs/video/renderer/Makemodule.am | 39 ++++++++++++++++--- libs/video/renderer/vulkan/test/Makemodule.am | 2 +- .../video/renderer/vulkan/vkgen/Makemodule.am | 2 + 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/config.d/build_control.m4 b/config.d/build_control.m4 index 09e4a10c0..a5fc7bc51 100644 --- a/config.d/build_control.m4 +++ b/config.d/build_control.m4 @@ -41,6 +41,7 @@ if test "x$HAVE_FBDEV" = xyes; then CL_TARGETS="$CL_TARGETS FBDEV" VID_TARGETS="$VID_TARGETS libs/video/targets/libQFfbdev.la" QF_NEED(vid_render, [sw]) + QF_NEED(render, [sw]) QF_NEED(models, [sw]) QF_NEED(alias, [sw]) QF_NEED(brush, [sw]) @@ -73,6 +74,7 @@ if test "x$HAVE_X" = xyes; then VID_TARGETS="$VID_TARGETS libs/video/targets/libQFx11.la" if test "$HAVE_VULKAN" = "yes"; then QF_NEED(vid_render, [vulkan]) + QF_NEED(render, [vulkan]) QF_NEED(models, [vulkan]) QF_NEED(alias, [vulkan]) QF_NEED(brush, [vulkan]) @@ -80,6 +82,7 @@ if test "x$HAVE_X" = xyes; then QF_NEED(sprite, [vulkan]) fi QF_NEED(vid_render, [sw sw32 gl glsl]) + QF_NEED(render, [sw sw32 gl glsl]) QF_NEED(models, [sw gl glsl]) QF_NEED(alias, [sw gl glsl]) QF_NEED(brush, [sw gl glsl]) @@ -105,12 +108,14 @@ if test "x$HAVE_SDL" = xyes; then VID_TARGETS="$VID_TARGETS libs/video/targets/libQFsdl.la" if test "$HAVE_VULKAN" = "yes"; then QF_NEED(vid_render, [vulkan]) + QF_NEED(render, [vulkan]) QF_NEED(alias, [vulkan]) QF_NEED(brush, [vulkan]) QF_NEED(iqm, [vulkan]) QF_NEED(sprite, [vulkan]) fi QF_NEED(vid_render, [sw sw32 gl glsl]) + QF_NEED(render, [sw sw32 gl glsl]) QF_NEED(models, [sw gl glsl]) QF_NEED(alias, [sw gl glsl]) QF_NEED(brush, [sw gl glsl]) @@ -133,6 +138,7 @@ if test "x$HAVE_SVGA" = xyes; then CL_TARGETS="$CL_TARGETS SVGAlib" VID_TARGETS="$VID_TARGETS libs/video/targets/libQFsvga.la" QF_NEED(vid_render, [sw]) + QF_NEED(render, [sw]) QF_NEED(models, [sw]) QF_NEED(alias, [sw]) QF_NEED(brush, [sw]) @@ -155,6 +161,7 @@ fi # CL_TARGETS="$CL_TARGETS WGL" # VID_TARGETS="$VID_TARGETS libs/video/targets/libQFwgl.la" # QF_NEED(vid_render, [gl]) +# QF_NEED(render, [gl]) # QF_NEED(models, [gl]) # QF_NEED(alias, [gl]) # QF_NEED(brush, [gl]) @@ -290,6 +297,7 @@ fi QF_SUBST(progs_gz) QF_PROCESS_NEED_LIBS(swrend, [asm]) +QF_PROCESS_NEED_LIBS(render, [gl glsl sw sw32 vulkan], [libs/video/renderer]) QF_PROCESS_NEED_LIBS(models, [gl glsl sw vulkan], [libs/models]) QF_PROCESS_NEED_LIBS(alias, [gl glsl sw vulkan], [libs/models/alias]) QF_PROCESS_NEED_LIBS(brush, [gl glsl sw vulkan], [libs/models/brush]) diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 8789de037..9eb2c2354 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -3,8 +3,12 @@ include libs/video/renderer/vulkan/vkgen/Makemodule.am #lib_LTLIBRARIES += @VID_REND_TARGETS@ plugin_LTLIBRARIES += @vid_render_plugins@ -noinst_LTLIBRARIES += libs/video/renderer/libQFrenderer.la @vid_render_static_plugins@ +noinst_LTLIBRARIES += \ + libs/video/renderer/libQFrenderer.la \ + @render_libs@ \ + @vid_render_static_plugins@ +#plugins EXTRA_LTLIBRARIES += \ libs/video/renderer/vid_render_sw.la \ libs/video/renderer/vid_render_sw32.la \ @@ -12,6 +16,14 @@ EXTRA_LTLIBRARIES += \ libs/video/renderer/vid_render_glsl.la \ libs/video/renderer/vid_render_vulkan.la +#helper libraries +EXTRA_LTLIBRARIES += \ + libs/video/renderer/librender_sw.la \ + libs/video/renderer/librender_sw32.la \ + libs/video/renderer/librender_gl.la \ + libs/video/renderer/librender_glsl.la \ + libs/video/renderer/librender_vulkan.la + video_renderer_common_sources = \ libs/video/renderer/crosshair.c \ libs/video/renderer/font8x8.c \ @@ -43,13 +55,16 @@ libs_video_renderer_libQFrenderer_la_SOURCES=\ libs/video/renderer/r_progs.c video_renderer_gl_libs= \ + libs/video/renderer/librender_gl.la \ libs/models/libmodels_gl.la libs_video_renderer_vid_render_gl_la_LDFLAGS= $(plugin_ldflags) libs_video_renderer_vid_render_gl_la_LIBADD= $(video_renderer_gl_libs) libs_video_renderer_vid_render_gl_la_DEPENDENCIES= $(video_renderer_gl_libs) libs_video_renderer_vid_render_gl_la_SOURCES=\ $(video_renderer_common_sources) \ - libs/video/renderer/vid_render_gl.c \ + libs/video/renderer/vid_render_gl.c + +libs_video_renderer_librender_gl_la_SOURCES = \ libs/video/renderer/gl/gl_draw.c \ libs/video/renderer/gl/gl_dyn_lights.c \ libs/video/renderer/gl/gl_dyn_part.c \ @@ -91,13 +106,16 @@ SUFFICES=.frag .vert .spv .spvc .fc .vc .slc .glsl .plist .plc $(am__mv) $@.t $@ video_renderer_glsl_libs= \ + libs/video/renderer/librender_glsl.la \ libs/models/libmodels_glsl.la libs_video_renderer_vid_render_glsl_la_LDFLAGS= $(plugin_ldflags) libs_video_renderer_vid_render_glsl_la_LIBADD= $(video_renderer_glsl_libs) libs_video_renderer_vid_render_glsl_la_DEPENDENCIES=$(video_renderer_glsl_libs) libs_video_renderer_vid_render_glsl_la_SOURCES=\ $(video_renderer_common_sources) \ - libs/video/renderer/vid_render_glsl.c \ + libs/video/renderer/vid_render_glsl.c + +libs_video_renderer_librender_glsl_la_SOURCES = \ libs/video/renderer/glsl/glsl_alias.c \ libs/video/renderer/glsl/glsl_bsp.c \ libs/video/renderer/glsl/glsl_draw.c \ @@ -116,13 +134,16 @@ libs_video_renderer_vid_render_glsl_la_SOURCES=\ libs/video/renderer/glsl/vid_common_glsl.c video_renderer_sw_libs= \ + libs/video/renderer/librender_sw.la \ libs/models/libmodels_sw.la libs_video_renderer_vid_render_sw_la_LDFLAGS= $(plugin_ldflags) libs_video_renderer_vid_render_sw_la_LIBADD= $(video_renderer_sw_libs) libs_video_renderer_vid_render_sw_la_DEPENDENCIES= $(video_renderer_sw_libs) libs_video_renderer_vid_render_sw_la_SOURCES=\ $(video_renderer_common_sources) \ - libs/video/renderer/vid_render_sw.c \ + libs/video/renderer/vid_render_sw.c + +libs_video_renderer_librender_sw_la_SOURCES = \ libs/video/renderer/sw/d_copy.S \ libs/video/renderer/sw/d_draw.S \ libs/video/renderer/sw/d_edge.c \ @@ -170,13 +191,16 @@ libs_video_renderer_vid_render_sw_la_SOURCES=\ libs/video/renderer/sw/vid_common_sw.c video_renderer_sw32_libs= \ + libs/video/renderer/librender_sw32.la \ libs/models/libmodels_sw.la libs_video_renderer_vid_render_sw32_la_LDFLAGS= $(plugin_ldflags) libs_video_renderer_vid_render_sw32_la_LIBADD= $(video_renderer_sw32_libs) libs_video_renderer_vid_render_sw32_la_DEPENDENCIES=$(video_renderer_sw32_libs) libs_video_renderer_vid_render_sw32_la_SOURCES=\ $(video_renderer_common_sources) \ - libs/video/renderer/vid_render_sw32.c \ + libs/video/renderer/vid_render_sw32.c + +libs_video_renderer_librender_sw32_la_SOURCES = \ libs/video/renderer/sw32/d_edge.c \ libs/video/renderer/sw32/d_fill.c \ libs/video/renderer/sw32/d_init.c \ @@ -213,13 +237,16 @@ renderpass_src = libs/video/renderer/vulkan/deferred.plist renderpass_gen = libs/video/renderer/vulkan/deferred.plc video_renderer_vulkan_libs = \ + libs/video/renderer/librender_vulkan.la \ libs/models/libmodels_vulkan.la libs_video_renderer_vid_render_vulkan_la_LDFLAGS= $(plugin_ldflags) libs_video_renderer_vid_render_vulkan_la_LIBADD= $(video_renderer_vulkan_libs) libs_video_renderer_vid_render_vulkan_la_DEPENDENCIES=$(video_renderer_vulkan_libs) libs_video_renderer_vid_render_vulkan_la_SOURCES = \ $(video_renderer_common_sources) \ - libs/video/renderer/vid_render_vulkan.c \ + libs/video/renderer/vid_render_vulkan.c + +libs_video_renderer_librender_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/barrier.c \ libs/video/renderer/vulkan/buffer.c \ libs/video/renderer/vulkan/command.c \ diff --git a/libs/video/renderer/vulkan/test/Makemodule.am b/libs/video/renderer/vulkan/test/Makemodule.am index cacb206f3..84c5ff136 100644 --- a/libs/video/renderer/vulkan/test/Makemodule.am +++ b/libs/video/renderer/vulkan/test/Makemodule.am @@ -7,7 +7,7 @@ TESTS += $(libs_video_renderer_vulkan_tests) check_PROGRAMS += $(libs_video_renderer_vulkan_tests) libs_video_renderer_vulkan_test_libs= \ - libs/video/renderer/vid_render_vulkan.la \ + libs/video/renderer/librender_vulkan.la \ libs/util/libQFutil.la libs_video_renderer_vulkan_test_test_staging_SOURCES= \ diff --git a/libs/video/renderer/vulkan/vkgen/Makemodule.am b/libs/video/renderer/vulkan/vkgen/Makemodule.am index b60e97f1d..ecb5853ee 100644 --- a/libs/video/renderer/vulkan/vkgen/Makemodule.am +++ b/libs/video/renderer/vulkan/vkgen/Makemodule.am @@ -47,5 +47,7 @@ EXTRA_DIST += \ libs/video/renderer/vulkan/vkgen/vkgen.h \ libs/video/renderer/vulkan/vkgen/vkstruct.h \ libs/video/renderer/vulkan/vkgen/vktype.h \ + $e + CLEANFILES += \ libs/video/renderer/vkgen/*.sym From 45c02556439763bc517875026e56907fe618ea86 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Mar 2021 16:17:15 +0900 Subject: [PATCH 372/435] [util] Add simd 4x4 matrix functions Currently just add, subtract, multiply (m m and m v). --- include/QF/simd/mat4f.h | 123 +++++++++++++++++++++++++++++++ include/QF/simd/types.h | 4 ++ libs/util/simd.c | 2 + libs/util/test/test-simd.c | 143 ++++++++++++++++++++++++++++++++++++- 4 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 include/QF/simd/mat4f.h diff --git a/include/QF/simd/mat4f.h b/include/QF/simd/mat4f.h new file mode 100644 index 000000000..3e1880ad6 --- /dev/null +++ b/include/QF/simd/mat4f.h @@ -0,0 +1,123 @@ +/* + QF/simd/mat4f.h + + Matrix functions for mat4f_t (ie, float precision) + + Copyright (C) 2021 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_simd_mat4f_h +#define __QF_simd_mat4f_h + +#include + +#include "QF/simd/types.h" + +GNU89INLINE inline void maddf (mat4f_t c, const mat4f_t a, const mat4f_t b); +GNU89INLINE inline void msubf (mat4f_t c, const mat4f_t a, const mat4f_t b); +GNU89INLINE inline void mmulf (mat4f_t c, const mat4f_t a, const mat4f_t b); +GNU89INLINE inline vec4f_t mvmulf (const mat4f_t m, vec4f_t v) __attribute__((const)); +GNU89INLINE inline vec4f_t m3vmulf (const mat4f_t m, vec4f_t v) __attribute__((const)); +GNU89INLINE inline void mat4fidentity (mat4f_t m); + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +maddf (mat4f_t c, const mat4f_t a, const mat4f_t b) +{ + c[0] = a[0] + b[0]; + c[1] = a[1] + b[1]; + c[2] = a[2] + b[2]; + c[3] = a[3] + b[3]; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +msubf (mat4f_t c, const mat4f_t a, const mat4f_t b) +{ + c[0] = a[0] - b[0]; + c[1] = a[1] - b[1]; + c[2] = a[2] - b[2]; + c[3] = a[3] - b[3]; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +mmulf (mat4f_t c, const mat4f_t a, const mat4f_t b) +{ + c[0] = a[0] * b[0][0] + a[1] * b[0][1] + a[2] * b[0][2] + a[3] * b[0][3]; + c[1] = a[0] * b[1][0] + a[1] * b[1][1] + a[2] * b[1][2] + a[3] * b[1][3]; + c[2] = a[0] * b[2][0] + a[1] * b[2][1] + a[2] * b[2][2] + a[3] * b[2][3]; + c[3] = a[0] * b[3][0] + a[1] * b[3][1] + a[2] * b[3][2] + a[3] * b[3][3]; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +mvmulf (const mat4f_t m, vec4f_t v) +{ + return m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * v[3]; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +m3vmulf (const mat4f_t m, vec4f_t v) +{ + vec4f_t w; + w = m[0] * v[0] + m[1] * v[1] + m[2] * v[2]; + w[3] = 1; + return w; +} + +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +mat4fidentity (mat4f_t m) +{ + m[0] = (vec4f_t) { 1, 0, 0, 0 }; + m[1] = (vec4f_t) { 0, 1, 0, 0 }; + m[2] = (vec4f_t) { 0, 0, 1, 0 }; + m[3] = (vec4f_t) { 0, 0, 0, 1 }; +} + +#endif//__QF_simd_mat4f_h diff --git a/include/QF/simd/types.h b/include/QF/simd/types.h index cd8b0da9d..e056abfac 100644 --- a/include/QF/simd/types.h +++ b/include/QF/simd/types.h @@ -82,4 +82,8 @@ VEC_TYPE (int, vec4i_t); #define VEC4I_FMT "[%d, %d, %d, %d]" #define VEC4_EXP(v) (v)[0], (v)[1], (v)[2], (v)[3] +#define MAT4_ROW(m, r) (m)[0][r], (m)[1][r], (m)[2][r], (m)[3][r] + +typedef vec4f_t mat4f_t[4]; +typedef vec4i_t mat4i_t[4]; #endif//__QF_simd_types_h diff --git a/libs/util/simd.c b/libs/util/simd.c index f5a0fcd35..84acc8798 100644 --- a/libs/util/simd.c +++ b/libs/util/simd.c @@ -32,6 +32,8 @@ #define IMPLEMENT_VEC4F_Funcs #define IMPLEMENT_VEC4D_Funcs +#define IMPLEMENT_MAT4F_Funcs #include "QF/simd/vec4d.h" #include "QF/simd/vec4f.h" +#include "QF/simd/mat4f.h" diff --git a/libs/util/test/test-simd.c b/libs/util/test/test-simd.c index 40a7276de..6fe524852 100644 --- a/libs/util/test/test-simd.c +++ b/libs/util/test/test-simd.c @@ -9,6 +9,7 @@ #include "QF/simd/vec4d.h" #include "QF/simd/vec4f.h" +#include "QF/simd/mat4f.h" #define right { 1, 0, 0 } #define forward { 0, 1, 0 } @@ -25,6 +26,22 @@ #define none { -1, -1, -1, -1 } #define nqident { 0, 0, 0, -1 } +#define identity \ + { { 1, 0, 0, 0 }, \ + { 0, 1, 0, 0 }, \ + { 0, 0, 1, 0 }, \ + { 0, 0, 0, 1 } } +#define rotate120 \ + { { 0, 1, 0, 0 }, \ + { 0, 0, 1, 0 }, \ + { 1, 0, 0, 0 }, \ + { 0, 0, 0, 1 } } +#define rotate240 \ + { { 0, 0, 1, 0 }, \ + { 1, 0, 0, 0 }, \ + { 0, 1, 0, 0 }, \ + { 0, 0, 0, 1 } } + #define s05 0.70710678118654757 typedef struct { @@ -43,6 +60,22 @@ typedef struct { vec4f_t ulp_errors; } vec4f_test_t; +typedef struct { + void (*op) (mat4f_t c, const mat4f_t a, const mat4f_t b); + mat4f_t a; + mat4f_t b; + mat4f_t expect; + mat4f_t ulp_errors; +} mat4f_test_t; + +typedef struct { + vec4f_t (*op) (const mat4f_t a, vec4f_t b); + mat4f_t a; + vec4f_t b; + vec4f_t expect; + vec4f_t ulp_errors; +} mv4f_test_t; + static vec4d_t tvtruncd (vec4d_t v, vec4d_t ignore) { return vtruncd (v); @@ -314,6 +347,26 @@ static vec4f_test_t vec4f_tests[] = { }; #define num_vec4f_tests (sizeof (vec4f_tests) / (sizeof (vec4f_tests[0]))) +static mat4f_test_t mat4f_tests[] = { + { mmulf, identity, identity, identity }, + { mmulf, rotate120, identity, rotate120 }, + { mmulf, identity, rotate120, rotate120 }, + { mmulf, rotate120, rotate120, rotate240 }, + { mmulf, rotate120, rotate240, identity }, + { mmulf, rotate240, rotate120, identity }, +}; +#define num_mat4f_tests (sizeof (mat4f_tests) / (sizeof (mat4f_tests[0]))) + +static mv4f_test_t mv4f_tests[] = { + { mvmulf, identity, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } }, + { mvmulf, identity, { 0, 1, 0, 0 }, { 0, 1, 0, 0 } }, + { mvmulf, identity, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } }, + { mvmulf, identity, { 0, 0, 0, 1 }, { 0, 0, 0, 1 } }, + { mvmulf, rotate120, { 1, 2, 3, 4 }, { 3, 1, 2, 4 } }, + { mvmulf, rotate240, { 1, 2, 3, 4 }, { 2, 3, 1, 4 } }, +}; +#define num_mv4f_tests (sizeof (mv4f_tests) / (sizeof (mv4f_tests[0]))) + static int run_vec4d_tests (void) { @@ -326,7 +379,7 @@ run_vec4d_tests (void) vec4l_t res = result != expect; if (res[0] || res[1] || res[2] || res[3]) { ret |= 1; - printf ("\nrun_vec4d_tests\n"); + printf ("\nrun_vec4d_tests %zd\n", i); printf ("a: " VEC4D_FMT "\n", VEC4_EXP(test->a)); printf ("b: " VEC4D_FMT "\n", VEC4_EXP(test->b)); printf ("r: " VEC4D_FMT "\n", VEC4_EXP(result)); @@ -351,7 +404,7 @@ run_vec4f_tests (void) vec4i_t res = result != expect; if (res[0] || res[1] || res[2] || res[3]) { ret |= 1; - printf ("\nrun_vec4f_tests\n"); + printf ("\nrun_vec4f_tests %zd\n", i); printf ("a: " VEC4F_FMT "\n", VEC4_EXP(test->a)); printf ("b: " VEC4F_FMT "\n", VEC4_EXP(test->b)); printf ("r: " VEC4F_FMT "\n", VEC4_EXP(result)); @@ -364,11 +417,97 @@ run_vec4f_tests (void) return ret; } +static int +run_mat4f_tests (void) +{ + int ret = 0; + + for (size_t i = 0; i < num_mat4f_tests; i++) { + __auto_type test = &mat4f_tests[i]; + mat4f_t result; + mat4f_t expect; + mat4i_t res = {}; + + test->op (result, test->a, test->b); + maddf (expect, test->expect, test->ulp_errors); + + int fail = 0; + for (int j = 0; j < 4; j++) { + res[j] = result[j] != expect[j]; + fail |= res[j][0] || res[j][1] || res[j][2] || res[j][3]; + } + if (fail) { + ret |= 1; + printf ("\nrun_mat4f_tests %zd\n", i); + printf ("a: " VEC4F_FMT "\n", MAT4_ROW(test->a, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 3)); + printf ("b: " VEC4F_FMT "\n", MAT4_ROW(test->b, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->b, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->b, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->b, 3)); + printf ("r: " VEC4F_FMT "\n", MAT4_ROW(result, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 3)); + printf ("t: " VEC4I_FMT "\n", MAT4_ROW(res, 0)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 1)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 2)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 3)); + printf ("E: " VEC4F_FMT "\n", MAT4_ROW(expect, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 3)); + printf ("e: " VEC4F_FMT "\n", MAT4_ROW(test->expect, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 3)); + printf ("u: " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 3)); + } + } + return ret; +} + +static int +run_mv4f_tests (void) +{ + int ret = 0; + + for (size_t i = 0; i < num_mv4f_tests; i++) { + __auto_type test = &mv4f_tests[i]; + vec4f_t result = test->op (test->a, test->b); + vec4f_t expect = test->expect + test->ulp_errors; + vec4i_t res = result != expect; + + if (res[0] || res[1] || res[2] || res[3]) { + ret |= 1; + printf ("\nrun_mat4f_tests %zd\n", i); + printf ("a: " VEC4F_FMT "\n", MAT4_ROW(test->a, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 3)); + printf ("b: " VEC4F_FMT "\n", VEC4_EXP(test->b)); + printf ("r: " VEC4F_FMT "\n", VEC4_EXP(result)); + printf ("t: " VEC4I_FMT "\n", VEC4_EXP(res)); + printf ("E: " VEC4F_FMT "\n", VEC4_EXP(expect)); + printf ("e: " VEC4F_FMT "\n", VEC4_EXP(test->expect)); + printf ("u: " VEC4F_FMT "\n", VEC4_EXP(test->ulp_errors)); + } + } + return ret; +} + int main (void) { int ret = 0; ret |= run_vec4d_tests (); ret |= run_vec4f_tests (); + ret |= run_mat4f_tests (); + ret |= run_mv4f_tests (); return ret; } From eb0aa2dceaa63ccab8d025135dcf7ac8f9221064 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Mar 2021 16:21:37 +0900 Subject: [PATCH 373/435] [renderer] Clean up most globals in efrags There's still the memory management itself to clean up, but the main code no longer uses any static/global variables (holdover from when the function was recursive rather). --- libs/video/renderer/r_efrag.c | 61 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/libs/video/renderer/r_efrag.c b/libs/video/renderer/r_efrag.c index 8785d3d7d..4c93c935c 100644 --- a/libs/video/renderer/r_efrag.c +++ b/libs/video/renderer/r_efrag.c @@ -33,11 +33,9 @@ #include "QF/render.h" #include "QF/sys.h" +#include "qfalloca.h" #include "r_internal.h" -static mnode_t *r_pefragtopnode; -static vec3_t r_emins, r_emaxs; - typedef struct s_efrag_list { struct s_efrag_list *next; efrag_t efrags[MAX_EFRAGS]; @@ -48,10 +46,6 @@ static t_efrag_list *efrag_list; /* ENTITY FRAGMENT FUNCTIONS */ -static efrag_t **lastlink; -static entity_t *r_addent; - - static inline void init_efrag_list (t_efrag_list *efl) { @@ -133,32 +127,39 @@ R_RemoveEfrags (entity_t *ent) ent->efrag = 0; } -#define NODE_STACK_SIZE 1024 -static mnode_t *node_stack[NODE_STACK_SIZE]; -static mnode_t **node_ptr = node_stack + NODE_STACK_SIZE; - static void -R_SplitEntityOnNode (mnode_t *node) +R_SplitEntityOnNode (mod_brush_t *brush, entity_t *ent, + vec3_t emins, vec3_t emaxs) { efrag_t *ef; plane_t *splitplane; mleaf_t *leaf; int sides; + efrag_t **lastlink; + mnode_t **node_stack; + mnode_t **node_ptr; + mnode_t *node = brush->nodes; - *--node_ptr = 0; + node_stack = alloca ((brush->depth + 2) * sizeof (mnode_t *)); + node_ptr = node_stack; + + lastlink = &ent->efrag; + + *node_ptr++ = 0; while (node) { // add an efrag if the node is a leaf if (__builtin_expect (node->contents < 0, 0)) { - if (!r_pefragtopnode) - r_pefragtopnode = node; + if (!ent->topnode) { + ent->topnode = node; + } leaf = (mleaf_t *) node; ef = new_efrag (); // ensures ef->entnext is 0 // add the link to the chain of links on the entity - ef->entity = r_addent; + ef->entity = ent; *lastlink = ef; lastlink = &ef->entnext; @@ -167,28 +168,29 @@ R_SplitEntityOnNode (mnode_t *node) ef->leafnext = leaf->efrags; leaf->efrags = ef; - node = *node_ptr++; + node = *--node_ptr; } else { // NODE_MIXED splitplane = node->plane; - sides = BOX_ON_PLANE_SIDE (r_emins, r_emaxs, splitplane); + sides = BOX_ON_PLANE_SIDE (emins, emaxs, splitplane); if (sides == 3) { // split on this plane // if this is the first splitter of this bmodel, remember it - if (!r_pefragtopnode) - r_pefragtopnode = node; + if (!ent->topnode) { + ent->topnode = node; + } } // recurse down the contacted sides if (sides & 1 && node->children[0]->contents != CONTENTS_SOLID) { if (sides & 2 && node->children[1]->contents != CONTENTS_SOLID) - *--node_ptr = node->children[1]; + *node_ptr++ = node->children[1]; node = node->children[0]; } else { if (sides & 2 && node->children[1]->contents != CONTENTS_SOLID) node = node->children[1]; else - node = *node_ptr++; + node = *--node_ptr; } } } @@ -198,6 +200,7 @@ void R_AddEfrags (mod_brush_t *brush, entity_t *ent) { model_t *entmodel; + vec3_t emins, emaxs; if (!ent->model || !r_worldentity.model) return; @@ -205,19 +208,13 @@ R_AddEfrags (mod_brush_t *brush, entity_t *ent) if (ent == &r_worldentity) return; // never add the world - r_addent = ent; - - lastlink = &ent->efrag; - r_pefragtopnode = 0; - entmodel = ent->model; - VectorAdd (ent->origin, entmodel->mins, r_emins); - VectorAdd (ent->origin, entmodel->maxs, r_emaxs); + VectorAdd (ent->origin, entmodel->mins, emins); + VectorAdd (ent->origin, entmodel->maxs, emaxs); - R_SplitEntityOnNode (brush->nodes); - - ent->topnode = r_pefragtopnode; + ent->topnode = 0; + R_SplitEntityOnNode (brush, ent, emins, emaxs); } void From 60348ab458561afb26409e1d83fe0067d806f046 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Mar 2021 16:34:44 +0900 Subject: [PATCH 374/435] [headers] Fix some inconsistent include guards --- include/QF/cexpr.h | 6 +++--- include/QF/cmem.h | 6 +++--- include/QF/darray.h | 8 +++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index 4e2dd3bcb..9a79690a6 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __expr_h -#define __expr_h +#ifndef __QF_expr_h +#define __QF_expr_h #include @@ -140,4 +140,4 @@ extern exprtype_t cexpr_plitem; extern binop_t cexpr_struct_binops[]; extern binop_t cexpr_struct_pointer_binops[]; -#endif +#endif//__QF_expr_h diff --git a/include/QF/cmem.h b/include/QF/cmem.h index 5f0d733ea..f9c47d4c1 100644 --- a/include/QF/cmem.h +++ b/include/QF/cmem.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __cmem_h -#define __cmem_h +#ifndef __QF_cmem_h +#define __QF_cmem_h #include "QF/qtypes.h" @@ -115,4 +115,4 @@ void delete_memsuper (memsuper_t *super); void *cmemalloc (memsuper_t *super, size_t size); void cmemfree (memsuper_t *super, void *mem); -#endif//__cmem_h +#endif//__QF_cmem_h diff --git a/include/QF/darray.h b/include/QF/darray.h index 50dc6c348..c2e21d7e1 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -28,8 +28,10 @@ */ -#ifndef __darray_h -#define __darray_h +#ifndef __QF_darray_h +#define __QF_darray_h + +#include "QF/sys.h" /** \defgroup darray Dynamic Arrays \ingroup utils @@ -363,4 +365,4 @@ ///@} -#endif//__darray_h +#endif//__QF_darray_h From e3762d8f38dec6a7617c49deb4b619ff69f9c314 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Mar 2021 18:01:35 +0900 Subject: [PATCH 375/435] [util] Make plist mostly null-safe The main purpose is to allow fluent-style: const char *targetname = PL_String (PL_ObjectForKey (entity, "targetname")); if (targetname && !PL_ObjectForKey (targets, targetname)) { PL_D_AddObject (targets, targetname, entity); } [note: the above is iffy due to ownership of entity, but the code from which the above comes works around the issue] --- include/QF/qfplist.h | 52 ++++++++------- libs/util/qfplist.c | 152 ++++++++++++++++++++++++------------------- 2 files changed, 113 insertions(+), 91 deletions(-) diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index cef305086..a4994476d 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -136,14 +136,14 @@ char *PL_WritePropertyList (const plitem_t *pl); /** Retrieve the type of an object. - \param item The object + \param item The object. Must not be null. \return the type of the object */ pltype_t PL_Type (const plitem_t *item) __attribute__((pure)); /** Retrieve the line number of an object. - \param item The object + \param item The object. Must not be null. \return the line number on which the object began, or 0 if not from a string */ @@ -152,15 +152,16 @@ int PL_Line (const plitem_t *item) __attribute__((pure)); /** Retrieve the data size from a binary object. \param binary The binary object - \return the size in bytes of the binary object 0 if binary isn't a binary - object. + \return the size in bytes of the binary object 0 if \a binary isn't a + binary object (includes if \a binary is null). */ size_t PL_BinarySize (const plitem_t *binary) __attribute__((pure)); /** Retrieve the data from a binary object. \param binary The binary object - \return pointer to the actual data or NULL if binary isn't a binary object. + \return pointer to the actual data or NULL if \b binary isn't a binary + object (includes if \a binary is null). \note You are NOT responsible for freeing the returned object. It will be destroyed when its container is. */ @@ -170,7 +171,7 @@ const void *PL_BinaryData (const plitem_t *binary) __attribute__((pure)); \param string The string object \return pointer to the actual string value or NULL if string isn't a - string. + string (includes if \a string is null). \note You are NOT responsible for freeing the returned object. It will be destroyed when its container is. */ @@ -180,8 +181,8 @@ const char *PL_String (const plitem_t *string) __attribute__((pure)); \param dict The dictionary to retrieve a value from \param key The unique key associated with the value - \return the value associated with the key, or NULL if not found or dict - isn't a dictionary. + \return the value associated with the key, or NULL if not found or \a dict + isn't a dictionary (includes if \a dict is null). \note You are NOT responsible for freeing the returned object. It will be destroyed when its container is. */ @@ -191,8 +192,8 @@ plitem_t *PL_ObjectForKey (const plitem_t *dict, const char *key); \param dict The Dictionary to remove the value from \param key The unique key associated with the value to be removed - \return the value associated with the key, or NULL if not found or dict - isn't a dictionary. + \return the value associated with the key, or NULL if not found or \a dict + isn't a dictionary (includes if \a dict is null). \note You are responsible for freeing the returned object. */ plitem_t *PL_RemoveObjectForKey (const plitem_t *dict, const char *key); @@ -202,19 +203,18 @@ plitem_t *PL_RemoveObjectForKey (const plitem_t *dict, const char *key); \param dict The dictionary to get the key from \param index The index of the key \return the key at the specified index, or NULL if index is out of range or - dict is not a dictionaly - isn't an array. + dict is not a dictionary (includes if \a dict is null). \note You are NOT responsible for freeing the returned object. It will be destroyed when its container is. */ -const char *PL_KeyAtIndex (const plitem_t *array, int index) __attribute__((pure)); +const char *PL_KeyAtIndex (const plitem_t *dict, int index) __attribute__((pure)); /** Retrieve a value from an array object. \param array The array to get the value from \param index The index within the array to retrieve - \return the value at the specified index, or NULL if index is out of range - or array is not an array. + \return the value at the specified index, or NULL if \a index is out of + range or \a array is not an array (includes in \a array is null). \note You are NOT responsible for freeing the returned object. It will be destroyed when its container is. */ @@ -223,7 +223,8 @@ plitem_t *PL_ObjectAtIndex (const plitem_t *array, int index) __attribute__((pur /** Retrieve a list of all keys in a dictionary. \param dict The dictionary to list - \return an Array containing Strings or NULL if dict isn't a dictionary + \return an Array containing Strings or NULL if \a dict isn't a dictionary + (includes if \a dict is null). \note You are responsible for freeing this array. */ plitem_t *PL_D_AllKeys (const plitem_t *dict); @@ -232,7 +233,8 @@ plitem_t *PL_D_AllKeys (const plitem_t *dict); \param dict The dictionary to get the number of keys of. - \return Returns the number of keys in the dictionary. + \return Returns the number of keys in the dictionary or 0 if \a dict isn't + a dictionary (includes if \a dict is null). */ int PL_D_NumKeys (const plitem_t *dict) __attribute__((pure)); @@ -242,7 +244,8 @@ int PL_D_NumKeys (const plitem_t *dict) __attribute__((pure)); \param key The key of the key/value pair to be added to the dictionary \param value The value of the key/value pair to be added to the dictionary - \return true on success, false on failure + \return true on success, false on failure (\a dict is null or not a + dictionary) \note the dictionary becomes the owner of the value. */ @@ -253,7 +256,8 @@ qboolean PL_D_AddObject (plitem_t *dict, const char *key, plitem_t *value); \param array The array to which the item will be added \param item The item to be added to the array - \return true on success, false on failure + \return true on success, false on failure (\a array is null or not an + array) \note the array becomes the owner of the added item. */ @@ -263,7 +267,8 @@ qboolean PL_A_AddObject (plitem_t *array, plitem_t *item); \param array The array from which to get the number of objects - \return number of objects in the array + \return number of objects in the array or 0 if \a array is null or not + an array. */ int PL_A_NumObjects (const plitem_t *array) __attribute__((pure)); @@ -273,7 +278,8 @@ int PL_A_NumObjects (const plitem_t *array) __attribute__((pure)); \param item The item to be added to the array \param index The location at which to insert the item into the array - \return true on success, false on failure + \return true on success, false on failure (\a array is null or not an + array). \note the array becomes the owner of the added item. */ @@ -285,7 +291,7 @@ qboolean PL_A_InsertObjectAtIndex (plitem_t *array, plitem_t *item, int index); \param array The array from which to remove the value \param index The index within the array to remove \return the value associated with the index, or NULL if not found or array - isn't an array. + is noll or an array. \note You are responsible for freeing the returned object. */ plitem_t *PL_RemoveObjectAtIndex (plitem_t *array, int index); @@ -323,7 +329,7 @@ plitem_t *PL_NewString (const char *str); /** Free a property list object. This function takes care of freeing any referenced property list data, so - call it only on top-level objects. + call it only on top-level objects. Safe to call with a null argument. \param item the property list object to be freed */ diff --git a/libs/util/qfplist.c b/libs/util/qfplist.c index 56c168168..454c549f7 100644 --- a/libs/util/qfplist.c +++ b/libs/util/qfplist.c @@ -132,11 +132,11 @@ init_quotables (void) quotable_bitmap[*c / 8] &= ~(1 << (*c % 8)); } -static plitem_t *PL_ParsePropertyListItem (pldata_t *); -static qboolean PL_SkipSpace (pldata_t *); -static char *PL_ParseQuotedString (pldata_t *); -static char *PL_ParseUnquotedString (pldata_t *); -static char *PL_ParseData (pldata_t *, int *); +static plitem_t *pl_parsepropertylistitem (pldata_t *); +static qboolean pl_skipspace (pldata_t *); +static char *pl_parsequotedstring (pldata_t *); +static char *pl_parseunquotedstring (pldata_t *); +static char *pl_parsedata (pldata_t *, int *); static const char * dict_get_key (const void *i, void *unused) @@ -156,7 +156,7 @@ dict_free (void *i, void *unused) } static plitem_t * -PL_NewItem (pltype_t type) +pl_newitem (pltype_t type) { plitem_t *item = calloc (1, sizeof (plitem_t)); item->type = type; @@ -166,7 +166,7 @@ PL_NewItem (pltype_t type) VISIBLE plitem_t * PL_NewDictionary (hashlink_t **hashlinks) { - plitem_t *item = PL_NewItem (QFDictionary); + plitem_t *item = pl_newitem (QFDictionary); pldict_t *dict = malloc (sizeof (pldict_t)); dict->tab = Hash_NewTable (1021, dict_get_key, dict_free, NULL, hashlinks); DARRAY_INIT (&dict->keys, 8); @@ -177,7 +177,7 @@ PL_NewDictionary (hashlink_t **hashlinks) VISIBLE plitem_t * PL_NewArray (void) { - plitem_t *item = PL_NewItem (QFArray); + plitem_t *item = pl_newitem (QFArray); plarray_t *array = calloc (1, sizeof (plarray_t)); item->data = array; return item; @@ -186,7 +186,7 @@ PL_NewArray (void) VISIBLE plitem_t * PL_NewData (void *data, size_t size) { - plitem_t *item = PL_NewItem (QFBinary); + plitem_t *item = pl_newitem (QFBinary); plbinary_t *bin = malloc (sizeof (plbinary_t)); item->data = bin; bin->data = data; @@ -197,7 +197,7 @@ PL_NewData (void *data, size_t size) static plitem_t * new_string (char *str, int line) { - plitem_t *item = PL_NewItem (QFString); + plitem_t *item = pl_newitem (QFString); item->data = str; item->line = line; return item; @@ -215,6 +215,9 @@ PL_Free (plitem_t *item) pldict_t *dict; plarray_t *array; + if (!item) { + return; + } switch (item->type) { case QFDictionary: dict = item->data; @@ -252,51 +255,54 @@ PL_Free (plitem_t *item) VISIBLE size_t PL_BinarySize (const plitem_t *binary) { - plbinary_t *bin = (plbinary_t *) binary->data; - - if (binary->type != QFBinary) + if (!binary || binary->type != QFBinary) { return 0; + } + + plbinary_t *bin = (plbinary_t *) binary->data; return bin->size; } VISIBLE const void * PL_BinaryData (const plitem_t *binary) { - plbinary_t *bin = (plbinary_t *) binary->data; - - if (binary->type != QFBinary) + if (!binary || binary->type != QFBinary) { return 0; + } + + plbinary_t *bin = (plbinary_t *) binary->data; return bin->data; } VISIBLE const char * PL_String (const plitem_t *string) { - if (string->type != QFString) + if (!string || string->type != QFString) { return NULL; + } return string->data; } VISIBLE plitem_t * PL_ObjectForKey (const plitem_t *item, const char *key) { - pldict_t *dict = (pldict_t *) item->data; - dictkey_t *k; - - if (item->type != QFDictionary) + if (!item || item->type != QFDictionary) { return NULL; + } - k = (dictkey_t *) Hash_Find (dict->tab, key); + pldict_t *dict = (pldict_t *) item->data; + dictkey_t *k = (dictkey_t *) Hash_Find (dict->tab, key); return k ? k->value : NULL; } VISIBLE const char * PL_KeyAtIndex (const plitem_t *item, int index) { - pldict_t *dict = (pldict_t *) item->data; - - if (item->type != QFDictionary) + if (!item || item->type != QFDictionary) { return NULL; + } + + pldict_t *dict = (pldict_t *) item->data; if (index < 0 || (size_t) index >= dict->keys.size) { return NULL; } @@ -307,13 +313,14 @@ PL_KeyAtIndex (const plitem_t *item, int index) VISIBLE plitem_t * PL_RemoveObjectForKey (const plitem_t *item, const char *key) { + if (!item || item->type != QFDictionary) { + return NULL; + } + pldict_t *dict = (pldict_t *) item->data; dictkey_t *k; plitem_t *value; - if (item->type != QFDictionary) - return NULL; - k = (dictkey_t *) Hash_Del (dict->tab, key); if (!k) return NULL; @@ -332,13 +339,14 @@ PL_RemoveObjectForKey (const plitem_t *item, const char *key) VISIBLE plitem_t * PL_D_AllKeys (const plitem_t *item) { + if (!item || item->type != QFDictionary) { + return NULL; + } + pldict_t *dict = (pldict_t *) item->data; dictkey_t *current; plitem_t *array; - if (item->type != QFDictionary) - return NULL; - if (!(array = PL_NewArray ())) return NULL; @@ -353,32 +361,35 @@ PL_D_AllKeys (const plitem_t *item) VISIBLE int PL_D_NumKeys (const plitem_t *item) { - pldict_t *dict = (pldict_t *) item->data; - if (item->type != QFDictionary) + if (!item || item->type != QFDictionary) { return 0; + } + + pldict_t *dict = (pldict_t *) item->data; return Hash_NumElements (dict->tab); } VISIBLE plitem_t * PL_ObjectAtIndex (const plitem_t *array, int index) { - plarray_t *arr = (plarray_t *) array->data; - - if (array->type != QFArray) + if (!array || array->type != QFArray) { return NULL; + } + plarray_t *arr = (plarray_t *) array->data; return index >= 0 && index < arr->numvals ? arr->values[index] : NULL; } VISIBLE qboolean PL_D_AddObject (plitem_t *item, const char *key, plitem_t *value) { + if (!item || item->type != QFDictionary || !value) { + return false; + } + pldict_t *dict = (pldict_t *) item->data; dictkey_t *k; - if (item->type != QFDictionary) - return false; - if ((k = Hash_Find (dict->tab, key))) { PL_Free ((plitem_t *) k->value); k->value = value; @@ -400,10 +411,11 @@ PL_D_AddObject (plitem_t *item, const char *key, plitem_t *value) VISIBLE qboolean PL_A_InsertObjectAtIndex (plitem_t *array, plitem_t *item, int index) { - plarray_t *arr; - - if (array->type != QFArray) + if (!array || array->type != QFArray || !item) { return false; + } + + plarray_t *arr; arr = (plarray_t *)array->data; @@ -442,20 +454,22 @@ PL_A_AddObject (plitem_t *array, plitem_t *item) VISIBLE int PL_A_NumObjects (const plitem_t *array) { - if (array->type != QFArray) + if (!array || array->type != QFArray) { return 0; + } return ((plarray_t *) array->data)->numvals; } VISIBLE plitem_t * PL_RemoveObjectAtIndex (plitem_t *array, int index) { + if (!array || array->type != QFArray) { + return 0; + } + plarray_t *arr; plitem_t *item; - if (array->type != QFArray) - return 0; - arr = (plarray_t *)array->data; if (index < 0 || index >= arr->numvals) @@ -472,7 +486,7 @@ PL_RemoveObjectAtIndex (plitem_t *array, int index) } static qboolean -PL_SkipSpace (pldata_t *pl) +pl_skipspace (pldata_t *pl) { while (pl->pos < pl->end) { char c = pl->ptr[pl->pos]; @@ -545,7 +559,7 @@ make_byte (byte h, byte l) } static char * -PL_ParseData (pldata_t *pl, int *len) +pl_parsedata (pldata_t *pl, int *len) { unsigned start = ++pl->pos; int nibbles = 0, i; @@ -578,7 +592,7 @@ PL_ParseData (pldata_t *pl, int *len) } static char * -PL_ParseQuotedString (pldata_t *pl) +pl_parsequotedstring (pldata_t *pl) { unsigned int start = ++pl->pos; unsigned int escaped = 0; @@ -731,7 +745,7 @@ PL_ParseQuotedString (pldata_t *pl) } static char * -PL_ParseUnquotedString (pldata_t *pl) +pl_parseunquotedstring (pldata_t *pl) { unsigned int start = pl->pos; char *str; @@ -747,11 +761,11 @@ PL_ParseUnquotedString (pldata_t *pl) } static plitem_t * -PL_ParsePropertyListItem (pldata_t *pl) +pl_parsepropertylistitem (pldata_t *pl) { plitem_t *item = NULL; - if (!PL_SkipSpace (pl)) + if (!pl_skipspace (pl)) return NULL; switch (pl->ptr[pl->pos]) { @@ -762,16 +776,16 @@ PL_ParsePropertyListItem (pldata_t *pl) pl->pos++; - while (PL_SkipSpace (pl) && pl->ptr[pl->pos] != '}') { + while (pl_skipspace (pl) && pl->ptr[pl->pos] != '}') { plitem_t *key; plitem_t *value; - if (!(key = PL_ParsePropertyListItem (pl))) { + if (!(key = pl_parsepropertylistitem (pl))) { PL_Free (item); return NULL; } - if (!(PL_SkipSpace (pl))) { + if (!(pl_skipspace (pl))) { PL_Free (key); PL_Free (item); return NULL; @@ -793,13 +807,13 @@ PL_ParsePropertyListItem (pldata_t *pl) pl->pos++; // If there is no value, lose the key - if (!(value = PL_ParsePropertyListItem (pl))) { + if (!(value = pl_parsepropertylistitem (pl))) { PL_Free (key); PL_Free (item); return NULL; } - if (!(PL_SkipSpace (pl))) { + if (!(pl_skipspace (pl))) { PL_Free (key); PL_Free (value); PL_Free (item); @@ -842,15 +856,15 @@ PL_ParsePropertyListItem (pldata_t *pl) pl->pos++; - while (PL_SkipSpace (pl) && pl->ptr[pl->pos] != ')') { + while (pl_skipspace (pl) && pl->ptr[pl->pos] != ')') { plitem_t *value; - if (!(value = PL_ParsePropertyListItem (pl))) { + if (!(value = pl_parsepropertylistitem (pl))) { PL_Free (item); return NULL; } - if (!(PL_SkipSpace (pl))) { + if (!(pl_skipspace (pl))) { PL_Free (value); PL_Free (item); return NULL; @@ -879,7 +893,7 @@ PL_ParsePropertyListItem (pldata_t *pl) case '<': { int len; - char *str = PL_ParseData (pl, &len); + char *str = pl_parsedata (pl, &len); if (!str) { return NULL; @@ -892,7 +906,7 @@ PL_ParsePropertyListItem (pldata_t *pl) case '"': { int line = pl->line; - char *str = PL_ParseQuotedString (pl); + char *str = pl_parsequotedstring (pl); if (!str) { return NULL; @@ -903,7 +917,7 @@ PL_ParsePropertyListItem (pldata_t *pl) default: { int line = pl->line; - char *str = PL_ParseUnquotedString (pl); + char *str = pl_parseunquotedstring (pl); if (!str) { return NULL; @@ -931,7 +945,7 @@ PL_GetPropertyList (const char *string, hashlink_t **hashlinks) pl->va_ctx = va_create_context (4); pl->hashlinks = hashlinks; - if ((newpl = PL_ParsePropertyListItem (pl))) { + if ((newpl = pl_parsepropertylistitem (pl))) { va_destroy_context (pl->va_ctx); free (pl); return newpl; @@ -1111,10 +1125,12 @@ PL_WritePropertyList (const plitem_t *pl) { dstring_t *dstr = dstring_newstr (); - if (!quotable_bitmap[0]) - init_quotables (); - write_item (dstr, pl, 0); - write_string_len (dstr, "\n", 1); + if (pl) { + if (!quotable_bitmap[0]) + init_quotables (); + write_item (dstr, pl, 0); + write_string_len (dstr, "\n", 1); + } return dstring_freeze (dstr); } From 2cc30f9dfdf897fccdc61e30c99103e04cac67d7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Mar 2021 18:10:58 +0900 Subject: [PATCH 376/435] [headers] Fix a doxygen warning --- include/QF/darray.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/darray.h b/include/QF/darray.h index c2e21d7e1..0ea0a26d6 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -100,7 +100,7 @@ \param array_size The size of the array. \param alloc Allocator taking (obj, size) where obj is allocator specific data (eg, a memory pool). - \param data Additional data for the allocator. + \param obj Additional data for the allocator. */ #define DARRAY_ALLOCFIXED_OBJ(array_type, array_size, alloc, obj) \ ({ \ From 0da3b35ef566f451617d5b3866c8c449e7678c4a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Mar 2021 18:11:59 +0900 Subject: [PATCH 377/435] [util] Add macro for using vectors with scanf --- include/QF/math/vector.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/QF/math/vector.h b/include/QF/math/vector.h index 630332907..6189d002c 100644 --- a/include/QF/math/vector.h +++ b/include/QF/math/vector.h @@ -176,6 +176,8 @@ extern const vec_t *const vec3_origin; //For printf etc #define VectorExpand(v) (v)[0], (v)[1], (v)[2] +//For scanf etc +#define VectorExpandAddr(v) &(v)[0], &(v)[1], &(v)[2] /* * VectorDistance, the distance between two points. From 4d8ce22c17e67df9ed1d6fb5ce0faaddb4d97d5d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Mar 2021 18:14:16 +0900 Subject: [PATCH 378/435] [vulkan] Load the map's lights into an array It's not used yet as work needs to be done to better support generic entities, but this is the next step to real-time lighting (though, to be honest, I expect it will be too slow to be usable). --- include/QF/Vulkan/qf_lighting.h | 7 +- .../renderer/vulkan/shader/lighting.frag | 2 +- libs/video/renderer/vulkan/vulkan_lighting.c | 108 ++++++++++++++++++ libs/video/renderer/vulkan/vulkan_main.c | 2 + 4 files changed, 116 insertions(+), 3 deletions(-) diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h index 8eaa53a6f..cd9e7d46c 100644 --- a/include/QF/Vulkan/qf_lighting.h +++ b/include/QF/Vulkan/qf_lighting.h @@ -40,11 +40,13 @@ typedef struct qfv_light_s { vec3_t color; float intensity; vec3_t position; - int radius; + float radius; vec3_t direction; float cone; } qfv_light_t; +typedef struct qfv_lightset_s DARRAY_TYPE (qfv_light_t) qfv_lightset_t; + #define NUM_LIGHTS 128 typedef struct qfv_light_buffer_s { @@ -52,7 +54,6 @@ typedef struct qfv_light_buffer_s { qfv_light_t lights[NUM_LIGHTS] __attribute__((aligned(16))); } qfv_light_buffer_t; - #define LIGHTING_BUFFER_INFOS 1 #define LIGHTING_IMAGE_INFOS 4 @@ -73,6 +74,7 @@ typedef struct lightingctx_s { VkPipeline pipeline; VkPipelineLayout layout; VkDeviceMemory light_memory; + qfv_lightset_t lights; } lightingctx_t; struct vulkan_ctx_s; @@ -80,5 +82,6 @@ struct vulkan_ctx_s; void Vulkan_Lighting_Init (struct vulkan_ctx_s *ctx); void Vulkan_Lighting_Shutdown (struct vulkan_ctx_s *ctx); void Vulkan_Lighting_Draw (struct vulkan_ctx_s *ctx); +void Vulkan_LoadLights (const char *entity_data, struct vulkan_ctx_s *ctx); #endif//__QF_Vulkan_qf_lighting_h diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index 3dfb755be..e2db7cc78 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -9,7 +9,7 @@ struct LightData { vec3 color; float intensity; vec3 position; - int radius; + float radius; vec3 direction; float cone; }; diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 8e41cf312..07f0f9927 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -41,6 +41,10 @@ #include "qfalloca.h" +#include "QF/dstring.h" +#include "QF/progs.h" +#include "QF/qfplist.h" +#include "QF/script.h" #include "QF/sys.h" #include "QF/va.h" @@ -203,6 +207,8 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx) lightingctx_t *lctx = calloc (1, sizeof (lightingctx_t)); ctx->lighting_context = lctx; + DARRAY_INIT (&lctx->lights, 16); + size_t frames = ctx->frames.size; DARRAY_INIT (&lctx->frames, frames); DARRAY_RESIZE (&lctx->frames, frames); @@ -295,6 +301,108 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx) } dfunc->vkFreeMemory (device->dev, lctx->light_memory, 0); dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0); + DARRAY_CLEAR (&lctx->lights); free (lctx->frames.a); free (lctx); } + +static void +parse_light (qfv_light_t *light, const plitem_t *entity, + const plitem_t *targets) +{ + const char *str; + + if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) { + sscanf (str, "%f %f %f", VectorExpandAddr (light->position)); + } + + light->cone = 1; + if ((str = PL_String (PL_ObjectForKey (entity, "target")))) { + vec3_t position = {}; + plitem_t *target = PL_ObjectForKey (targets, str); + if (target) { + if ((str = PL_String (PL_ObjectForKey (target, "origin")))) { + sscanf (str, "%f %f %f", VectorExpandAddr (position)); + } + VectorSubtract (position, light->position, light->direction); + VectorNormalize (light->direction); + } + + float angle = 40; + if ((str = PL_String (PL_ObjectForKey (entity, "angle")))) { + angle = atof (str); + } + light->cone = -cos (angle * M_PI / 360); // half angle + } + + light->intensity = 1; + if ((str = PL_String (PL_ObjectForKey (entity, "light"))) + || (str = PL_String (PL_ObjectForKey (entity, "_light")))) { + light->radius = atof (str); + } + + VectorSet (1, 1, 1, light->color); +} + +void +Vulkan_LoadLights (const char *entity_data, vulkan_ctx_t *ctx) +{ + lightingctx_t *lctx = ctx->lighting_context; + plitem_t *entities = 0; + + lctx->lights.size = 0; + + script_t *script = Script_New (); + Script_Start (script, "ent data", entity_data); + + if (Script_GetToken (script, 1)) { + if (strequal (script->token->str, "(")) { + // new style (plist) entity data + entities = PL_GetPropertyList (entity_data, &ctx->hashlinks); + } else { + // old style entity data + Script_UngetToken (script); + // FIXME ED_ConvertToPlist aborts if an error is encountered. + entities = ED_ConvertToPlist (script, 0, &ctx->hashlinks); + } + } + Script_Delete (script); + + if (entities) { + plitem_t *targets = PL_NewDictionary (&ctx->hashlinks); + + // find all the targets so spotlights can be aimed + for (int i = 1; i < PL_A_NumObjects (entities); i++) { + plitem_t *entity = PL_ObjectAtIndex (entities, i); + const char *targetname = PL_String (PL_ObjectForKey (entity, + "targetname")); + if (targetname && !PL_ObjectForKey (targets, targetname)) { + PL_D_AddObject (targets, targetname, entity); + } + } + + for (int i = 1; i < PL_A_NumObjects (entities); i++) { + plitem_t *entity = PL_ObjectAtIndex (entities, i); + const char *classname = PL_String (PL_ObjectForKey (entity, + "classname")); + if (classname && strnequal (classname, "light", 5)) { + qfv_light_t light = {}; + + parse_light (&light, entity, targets); + printf ("[%g, %g, %g] %g, [%g %g %g] %g, [%g %g %g] %g\n", + VectorExpand (light.color), light.intensity, + VectorExpand (light.position), light.radius, + VectorExpand (light.direction), light.cone); + DARRAY_APPEND (&lctx->lights, light); + } + } + // targets does not own the objects, so need to remove them before + // freeing targets + for (int i = PL_D_NumKeys (targets); i-- > 0; ) { + PL_RemoveObjectForKey (targets, PL_KeyAtIndex (targets, i)); + } + PL_Free (targets); + PL_Free (entities); + } + printf ("loaded %zd lights\n", lctx->lights.size); +} diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index b4bdc8872..69916682e 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -49,6 +49,7 @@ #include "QF/Vulkan/qf_alias.h" #include "QF/Vulkan/qf_bsp.h" //#include "QF/Vulkan/qf_iqm.h" +#include "QF/Vulkan/qf_lighting.h" #include "QF/Vulkan/qf_lightmap.h" #include "QF/Vulkan/qf_main.h" #include "QF/Vulkan/qf_particles.h" @@ -217,6 +218,7 @@ Vulkan_NewMap (model_t *worldmodel, struct model_s **models, int num_models, Vulkan_RegisterTextures (models, num_models, ctx); Vulkan_BuildLightmaps (models, num_models, ctx); Vulkan_BuildDisplayLists (models, num_models, ctx); + Vulkan_LoadLights (worldmodel->brush.entities, ctx); } /*void From 0366b72d4a3e17a32008db4d1a60d11fd40fbac3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 3 Mar 2021 18:16:27 +0900 Subject: [PATCH 379/435] [vulkan] remove the fps printing Now that pixels are rendered, there's no need to print the fps separately as the in-game display works quite nicely. --- libs/video/renderer/vid_render_vulkan.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 059250fff..00c307dbc 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -118,8 +118,6 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) { const VkSubpassContents subpassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS; - static int count = 0; - static double startTime; uint32_t imageIndex = 0; qfv_device_t *device = vulkan_ctx->device; qfv_devfuncs_t *dfunc = device->funcs; @@ -199,16 +197,6 @@ vulkan_R_RenderFrame (SCR_Func scr_3dfunc, SCR_Func *scr_funcs) vulkan_ctx->curFrame++; vulkan_ctx->curFrame %= vulkan_ctx->frames.size; - - if (++count >= 100) { - double currenTime = Sys_DoubleTime (); - double time = currenTime - startTime; - startTime = currenTime; - printf ("%d frames in %g s: %g fps \r", - count, time, count / time); - fflush (stdout); - count = 0; - } } static void From 4a97bc3ba549ee2abe0ed3033051f6265fe03a35 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 4 Mar 2021 17:39:05 +0900 Subject: [PATCH 380/435] [util] Create simd quaternion to matrix function This seems to be pretty close to as fast as it gets (might be able to do better with some shuffles of the negation constants instead of loading separate constants). --- include/QF/simd/mat4f.h | 50 +++++++++++++++++++++++ libs/util/test/test-quat.c | 32 +++++++++++++++ libs/util/test/test-simd.c | 82 +++++++++++++++++++++++++++++++++++++- 3 files changed, 163 insertions(+), 1 deletion(-) diff --git a/include/QF/simd/mat4f.h b/include/QF/simd/mat4f.h index 3e1880ad6..24773da87 100644 --- a/include/QF/simd/mat4f.h +++ b/include/QF/simd/mat4f.h @@ -38,6 +38,7 @@ GNU89INLINE inline void mmulf (mat4f_t c, const mat4f_t a, const mat4f_t b); GNU89INLINE inline vec4f_t mvmulf (const mat4f_t m, vec4f_t v) __attribute__((const)); GNU89INLINE inline vec4f_t m3vmulf (const mat4f_t m, vec4f_t v) __attribute__((const)); GNU89INLINE inline void mat4fidentity (mat4f_t m); +GNU89INLINE inline void mat4fquat (mat4f_t m, vec4f_t q); #ifndef IMPLEMENT_MAT4F_Funcs GNU89INLINE inline @@ -120,4 +121,53 @@ mat4fidentity (mat4f_t m) m[3] = (vec4f_t) { 0, 0, 0, 1 }; } +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +mat4fquat (mat4f_t m, vec4f_t q) +{ + vec4f_t xq = q[0] * q; + vec4f_t yq = q[1] * q; + vec4f_t zq = q[2] * q; + vec4f_t wq = q[3] * q; + + static const vec4i_t shuff103 = { 1, 0, 3, 2 }; + static const vec4i_t shuff230 = { 2, 3, 0, 1 }; + static const vec4i_t shuff321 = { 3, 2, 1, 0 }; +#define p (0) +#define m (1u << 31) + static const vec4i_t mpm = { m, p, m, 0 }; + static const vec4i_t pmm = { p, m, m, 0 }; + static const vec4i_t mmp = { m, m, p, 0 }; + static const vec4i_t mask = { ~0u, ~0u, ~0u, 0 }; +#undef p +#undef m + { + vec4f_t a = xq; + vec4f_t b = _mm_xor_ps (__builtin_shuffle (yq, shuff103), (__m128) mpm); + vec4f_t c = _mm_xor_ps (__builtin_shuffle (zq, shuff230), (__m128) pmm); + vec4f_t d = _mm_xor_ps (__builtin_shuffle (wq, shuff321), (__m128) mmp); + + m[0] = _mm_and_ps (a + b - c - d, (__m128) mask); + } + { + vec4f_t a = _mm_xor_ps (__builtin_shuffle (xq, shuff103), (__m128) mpm); + vec4f_t b = yq; + vec4f_t c = _mm_xor_ps (__builtin_shuffle (zq, shuff321), (__m128) mmp); + vec4f_t d = _mm_xor_ps (__builtin_shuffle (wq, shuff230), (__m128) pmm); + m[1] = _mm_and_ps (b + c - a - d, (__m128) mask); + } + { + vec4f_t a = _mm_xor_ps (__builtin_shuffle (xq, shuff230), (__m128) pmm); + vec4f_t b = _mm_xor_ps (__builtin_shuffle (yq, shuff321), (__m128) mmp); + vec4f_t c = zq; + vec4f_t d = _mm_xor_ps (__builtin_shuffle (wq, shuff103), (__m128) mpm); + m[2] = _mm_and_ps (a - b + c - d, (__m128) mask); + } + m[3] = (vec4f_t) { 0, 0, 0, 1 }; +} + #endif//__QF_simd_mat4f_h diff --git a/libs/util/test/test-quat.c b/libs/util/test/test-quat.c index 9144f56be..cafceb2c8 100644 --- a/libs/util/test/test-quat.c +++ b/libs/util/test/test-quat.c @@ -362,6 +362,31 @@ fail: return 0; } +static int +test_quat_mat2(const quat_t q, const quat_t expect) +{ + int i; + vec_t m[9]; + + QuatToMatrix (q, m, 0, 1); + Mat3Transpose (m, m); + + for (i = 0; i < 9; i++) + if (m[i] != expect[i]) // exact tests here + goto fail; + return 1; +fail: + printf ("\ntest_quat_mat\n"); + printf ("%11.9g %11.9g %11.9g %11.9g\n", QuatExpand (q)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 0), VectorExpand (expect + 0)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 3), VectorExpand (expect + 3)); + printf ("%11.9g %11.9g %11.9g %11.9g %11.9g %11.9g\n", + VectorExpand (m + 6), VectorExpand (expect + 6)); + return 0; +} + int main (int argc, const char **argv) { @@ -407,5 +432,12 @@ main (int argc, const char **argv) res = 1; } + for (i = 0; i < num_quat_mat_tests; i ++) { + vec_t *q = quat_mat_tests[i].q; + vec_t *expect = quat_mat_tests[i].expect; + if (!test_quat_mat2 (q, expect)) + res = 1; + } + return res; } diff --git a/libs/util/test/test-simd.c b/libs/util/test/test-simd.c index 6fe524852..b14a1be9c 100644 --- a/libs/util/test/test-simd.c +++ b/libs/util/test/test-simd.c @@ -7,6 +7,7 @@ #include #include +#include "QF/mathlib.h" #include "QF/simd/vec4d.h" #include "QF/simd/vec4f.h" #include "QF/simd/mat4f.h" @@ -76,6 +77,13 @@ typedef struct { vec4f_t ulp_errors; } mv4f_test_t; +typedef struct { + void (*op) (mat4f_t m, vec4f_t q); + vec4f_t q; + mat4f_t expect; + mat4f_t ulp_errors; +} mq4f_test_t; + static vec4d_t tvtruncd (vec4d_t v, vec4d_t ignore) { return vtruncd (v); @@ -367,6 +375,20 @@ static mv4f_test_t mv4f_tests[] = { }; #define num_mv4f_tests (sizeof (mv4f_tests) / (sizeof (mv4f_tests[0]))) +// expect filled in using non-simd QuatToMatrix (has its own tests) +static mq4f_test_t mq4f_tests[] = { + { mat4fquat, { 0, 0, 0, 1 } }, + { mat4fquat, { 0.5, 0.5, 0.5, 0.5 } }, + { mat4fquat, { 0.5, 0.5, -0.5, 0.5 } }, + { mat4fquat, { 0.5, -0.5, 0.5, 0.5 } }, + { mat4fquat, { 0.5, -0.5, -0.5, 0.5 } }, + { mat4fquat, { -0.5, 0.5, 0.5, 0.5 } }, + { mat4fquat, { -0.5, 0.5, -0.5, 0.5 } }, + { mat4fquat, { -0.5, -0.5, 0.5, 0.5 } }, + { mat4fquat, { -0.5, -0.5, -0.5, 0.5 } }, +}; +#define num_mq4f_tests (sizeof (mq4f_tests) / (sizeof (mq4f_tests[0]))) + static int run_vec4d_tests (void) { @@ -485,7 +507,7 @@ run_mv4f_tests (void) if (res[0] || res[1] || res[2] || res[3]) { ret |= 1; - printf ("\nrun_mat4f_tests %zd\n", i); + printf ("\nrun_mv4f_tests %zd\n", i); printf ("a: " VEC4F_FMT "\n", MAT4_ROW(test->a, 0)); printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 1)); printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 2)); @@ -501,6 +523,63 @@ run_mv4f_tests (void) return ret; } +static int +run_mq4f_tests (void) +{ + int ret = 0; + + for (size_t i = 0; i < num_mq4f_tests; i++) { + __auto_type test = &mq4f_tests[i]; + quat_t q; + vec_t m[16]; + memcpy (q, &test->q, sizeof (quat_t)); + QuatToMatrix (q, m, 1, 1); + memcpy (&test->expect, m, sizeof (mat4f_t)); + } + for (size_t i = 0; i < num_mq4f_tests; i++) { + __auto_type test = &mq4f_tests[i]; + mat4f_t result; + mat4f_t expect; + mat4i_t res = {}; + + test->op (result, test->q); + maddf (expect, test->expect, test->ulp_errors); + memcpy (expect, (void *) &test->expect, sizeof (mat4f_t)); + + int fail = 0; + for (int j = 0; j < 4; j++) { + res[j] = result[j] != expect[j]; + fail |= res[j][0] || res[j][1] || res[j][2] || res[j][3]; + } + if (fail) { + ret |= 1; + printf ("\nrun_mq4f_tests %zd\n", i); + printf ("q: " VEC4F_FMT "\n", VEC4_EXP(test->q)); + printf ("r: " VEC4F_FMT "\n", MAT4_ROW(result, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 3)); + printf ("t: " VEC4I_FMT "\n", MAT4_ROW(res, 0)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 1)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 2)); + printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 3)); + printf ("E: " VEC4F_FMT "\n", MAT4_ROW(expect, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 3)); + printf ("e: " VEC4F_FMT "\n", MAT4_ROW(test->expect, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 3)); + printf ("u: " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 3)); + } + } + return ret; +} + int main (void) { @@ -509,5 +588,6 @@ main (void) ret |= run_vec4f_tests (); ret |= run_mat4f_tests (); ret |= run_mv4f_tests (); + ret |= run_mq4f_tests (); return ret; } From 14bc560624cbaac5fcff6ab2e1f3975edcc92847 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 7 Mar 2021 17:39:22 +0900 Subject: [PATCH 381/435] [build] Add option to enable gcov data generation Nice to be able to check how good the tests are (or aren't, as the case may be). --- config.d/compiling.m4 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/config.d/compiling.m4 b/config.d/compiling.m4 index d9ba92887..7a4908efa 100644 --- a/config.d/compiling.m4 +++ b/config.d/compiling.m4 @@ -223,6 +223,12 @@ QF_CC_OPTION(-Wsuggest-attribute=const) QF_CC_OPTION(-Wsuggest-attribute=noreturn) QF_CC_OPTION(-Wsuggest-attribute=format) +AC_ARG_ENABLE(coverage, +[ --enable-coverage Enable generation of data for gcov]) +if test "x$enable_coverage" = xyes; then + QF_CC_OPTION(-fprofile-arcs -ftest-coverage) +fi + dnl QuakeForge uses lots of BCPL-style (//) comments, which can cause problems dnl with many compilers that do not support the latest ISO standards. Well, dnl that is our cover story -- the reality is that we like them and do not want @@ -250,8 +256,7 @@ if test "x$GCC" != xyes; then fi AC_ARG_ENABLE(Werror, -[ --disable-Werror Do not treat warnings as errors] -) +[ --disable-Werror Do not treat warnings as errors]) dnl We want warnings, lots of warnings... dnl The help text should be INVERTED before release! dnl when in git, this test defaults to ENABLED. From 941a1267bcbb341f7c8d2612bb54384f5f81dee3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Mar 2021 11:35:18 +0900 Subject: [PATCH 382/435] [util] Fix a count error when resizing darrays Turns out I had never fully tested inserts. --- include/QF/darray.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/darray.h b/include/QF/darray.h index 0ea0a26d6..61500256a 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -253,7 +253,7 @@ } \ DARRAY_RESIZE (ar, ar->size + sp); \ memmove (&ar->a[po + sp], &ar->a[po], \ - (ar->size - po) * sizeof (*ar->a)); \ + (ar->size - po - sp) * sizeof (*ar->a)); \ &ar->a[po]; \ }) From 2c5742a0765eb7017ba9e9cc40ab74f7674e193f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Mar 2021 11:37:47 +0900 Subject: [PATCH 383/435] [renderer] Remove some variable warts Ugh, Hungarian notation is still lurking... --- libs/video/renderer/r_efrag.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/video/renderer/r_efrag.c b/libs/video/renderer/r_efrag.c index 4c93c935c..cbfd0d2c8 100644 --- a/libs/video/renderer/r_efrag.c +++ b/libs/video/renderer/r_efrag.c @@ -218,26 +218,26 @@ R_AddEfrags (mod_brush_t *brush, entity_t *ent) } void -R_StoreEfrags (const efrag_t *pefrag) +R_StoreEfrags (const efrag_t *efrag) { - entity_t *pent; + entity_t *ent; model_t *model; - while (pefrag) { - pent = pefrag->entity; - model = pent->model; + while (efrag) { + ent = efrag->entity; + model = ent->model; switch (model->type) { case mod_alias: case mod_brush: case mod_sprite: case mod_iqm: - if (pent->visframe != r_framecount) { - R_EnqueueEntity (pent); + if (ent->visframe != r_framecount) { + R_EnqueueEntity (ent); // mark that we've recorded this entity for this frame - pent->visframe = r_framecount; + ent->visframe = r_framecount; } - pefrag = pefrag->leafnext; + efrag = efrag->leafnext; break; default: From 3230270ae3046ce010f34aaee35389351913bd86 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Mar 2021 11:39:41 +0900 Subject: [PATCH 384/435] [entity] Start work on a new entity library The plan is to have a fully component based entity system. This adds hierarchical transforms. Not particularly useful for quake itself at this stage, but it will allow for much more flexibility later on, especially when QuakeForge becomes more general-purpose. --- include/QF/entity.h | 122 ++++++ libs/Makemodule.am | 1 + libs/entity/Makemodule.am | 13 + libs/entity/hierarchy.c | 444 +++++++++++++++++++ libs/entity/test/Makemodule.am | 19 + libs/entity/test/test-hierarchy.c | 707 ++++++++++++++++++++++++++++++ libs/entity/transform.c | 317 ++++++++++++++ 7 files changed, 1623 insertions(+) create mode 100644 include/QF/entity.h create mode 100644 libs/entity/Makemodule.am create mode 100644 libs/entity/hierarchy.c create mode 100644 libs/entity/test/Makemodule.am create mode 100644 libs/entity/test/test-hierarchy.c create mode 100644 libs/entity/transform.c diff --git a/include/QF/entity.h b/include/QF/entity.h new file mode 100644 index 000000000..9bf676190 --- /dev/null +++ b/include/QF/entity.h @@ -0,0 +1,122 @@ +/* + entity.h + + Entity management + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/02/26 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_entity_h +#define __QF_entity_h + +#include "QF/darray.h" +#include "QF/mathlib.h" +#include "QF/simd/vec4f.h" +#include "QF/simd/mat4f.h" + +/** \defgroup entity Entity management + \ingroup utils +*/ +///@{ + +typedef struct mat4fset_s DARRAY_TYPE (mat4f_t) mat4fset_t; +typedef struct vec4fset_s DARRAY_TYPE (vec4f_t) vec4fset_t; +typedef struct uint32set_s DARRAY_TYPE (uint32_t) uint32set_t; +typedef struct byteset_s DARRAY_TYPE (byte) byteset_t; +typedef struct stringset_s DARRAY_TYPE (char *) stringset_t; +typedef struct xformset_s DARRAY_TYPE (struct transform_s *) xformset_t; +typedef struct entityset_s DARRAY_TYPE (struct entity_s *) entityset_t; + +#define null_transform (~0u) + +typedef struct hierarchy_s { + xformset_t transform; + entityset_t entity; + uint32set_t childCount; + uint32set_t childIndex; + uint32set_t parentIndex; + stringset_t name; + uint32set_t tag; + byteset_t modified; + mat4fset_t localMatrix; + mat4fset_t localInverse; + mat4fset_t worldMatrix; + mat4fset_t worldInverse; + vec4fset_t localRotation; + vec4fset_t localScale; + vec4fset_t worldRotation; + vec4fset_t worldScale; +} hierarchy_t; + +typedef struct transform_s { + hierarchy_t *hierarchy; + uint32_t index; +} transform_t; + +transform_t *Transform_New (transform_t *parent); +void Transform_Delete (transform_t *transform); +transform_t *Transform_NewNamed (transform_t *parent, const char *name); +uint32_t Transform_ChildCount (const transform_t *transform) __attribute__((pure)); +transform_t *Transform_GetChild (const transform_t *transform, + uint32_t childIndex) __attribute__((pure)); +void Transform_SetParent (transform_t *transform, transform_t *parent); +transform_t *Transform_GetParent (const transform_t *transform) __attribute__((pure)); +void Transform_SetName (transform_t *transform, const char *name); +const char *Transform_GetName (const transform_t *transform) __attribute__((pure)); +void Transform_SetTag (transform_t *transform, uint32_t tag); +uint32_t Transform_GetTag (const transform_t *transform) __attribute__((pure)); +void Transform_GetLocalMatrix (const transform_t *transform, mat4f_t mat); +void Transform_GetLocalInverse (const transform_t *transform, mat4f_t mat); +void Transform_GetWorldMatrix (const transform_t *transform, mat4f_t mat); +void Transform_GetWorldInverse (const transform_t *transform, mat4f_t mat); +vec4f_t Transform_GetLocalPosition (const transform_t *transform) __attribute__((pure)); +void Transform_SetLocalPosition (transform_t *transform_t, vec4f_t position); +vec4f_t Transform_GetLocalRotation (const transform_t *transform) __attribute__((pure)); +void Transform_SetLocalRotation (transform_t *transform_t, vec4f_t rotation); +vec4f_t Transform_GetLocalScale (const transform_t *transform) __attribute__((pure)); +void Transform_SetLocalScale (transform_t *transform_t, vec4f_t scale); +vec4f_t Transform_GetWorldPosition (const transform_t *transform) __attribute__((pure)); +void Transform_SetWorldPosition (transform_t *transform_t, vec4f_t position); +vec4f_t Transform_GetWorldRotation (const transform_t *transform) __attribute__((pure)); +void Transform_SetWorldRotation (transform_t *transform_t, vec4f_t rotation); +vec4f_t Transform_GetWorldScale (const transform_t *transform) __attribute__((pure)); +// NOTE: these use X: right, Y: forward, Z:up +// aslo, not guaranteed to be normalized or even orthogonal +vec4f_t Transform_Forward (const transform_t *transform) __attribute__((pure)); +vec4f_t Transform_Right (const transform_t *transform) __attribute__((pure)); +vec4f_t Transform_Up (const transform_t *transform) __attribute__((pure)); +// no SetWorldScale because after rotations, non uniform scale becomes shear + +hierarchy_t *Hierarchy_New (size_t grow, int createRoot); +hierarchy_t *Hierarchy_Copy (hierarchy_t *src); +void Hierarchy_Delete (hierarchy_t *hierarchy); + +void Hierarchy_UpdateMatrices (hierarchy_t *hierarchy); +uint32_t Hierarchy_InsertHierarchy (hierarchy_t *dst, const hierarchy_t *src, + uint32_t dstParent, uint32_t srcRoot); +void Hierarchy_RemoveHierarchy (hierarchy_t *hierarchy, uint32_t index); +///@} + +#endif//__QF_entity_h diff --git a/libs/Makemodule.am b/libs/Makemodule.am index 5a68c67ba..86fcac7df 100644 --- a/libs/Makemodule.am +++ b/libs/Makemodule.am @@ -7,6 +7,7 @@ include libs/image/Makemodule.am include libs/models/Makemodule.am include libs/video/Makemodule.am include libs/console/Makemodule.am +include libs/entity/Makemodule.am include libs/net/Makemodule.am include libs/client/Makemodule.am diff --git a/libs/entity/Makemodule.am b/libs/entity/Makemodule.am new file mode 100644 index 000000000..d8ac9a7e1 --- /dev/null +++ b/libs/entity/Makemodule.am @@ -0,0 +1,13 @@ +include libs/entity/test/Makemodule.am + +entity_deps=libs/util/libQFutil.la + +lib_LTLIBRARIES += libs/entity/libQFentity.la + +libs_entity_libQFentity_la_LDFLAGS= $(lib_ldflags) +libs_entity_libQFentity_la_LIBADD= $(entity_deps) +libs_entity_libQFentity_la_DEPENDENCIES= $(entity_deps) +libs_entity_libQFentity_la_SOURCES= \ + libs/entity/hierarchy.c \ + libs/entity/transform.c \ + $e diff --git a/libs/entity/hierarchy.c b/libs/entity/hierarchy.c new file mode 100644 index 000000000..cadb3771c --- /dev/null +++ b/libs/entity/hierarchy.c @@ -0,0 +1,444 @@ +/* + hierarchy.c + + General hierarchy handling + + Copyright (C) 2021 Bill Currke + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/entity.h" + +static void +hierarchy_UpdateTransformIndices (hierarchy_t *hierarchy, uint32_t start, + int offset) +{ + for (size_t i = start; i < hierarchy->transform.size; i++) { + if (hierarchy->transform.a[i]) { + hierarchy->transform.a[i]->index += offset; + } + } +} + +static void +hierarchy_UpdateChildIndices (hierarchy_t *hierarchy, uint32_t start, + int offset) +{ + for (size_t i = start; i < hierarchy->childIndex.size; i++) { + hierarchy->childIndex.a[i] += offset; + } +} + +static void +hierarchy_UpdateParentIndices (hierarchy_t *hierarchy, uint32_t start, + int offset) +{ + for (size_t i = start; i < hierarchy->parentIndex.size; i++) { + hierarchy->parentIndex.a[i] += offset; + } +} + +static void +hierarchy_calcLocalInverse (hierarchy_t *h, uint32_t index) +{ + // This takes advantage of the fact that localMatrix is a simple + // homogenous scale/rotate/translate matrix with no shear + vec4f_t x = h->localMatrix.a[index][0]; + vec4f_t y = h->localMatrix.a[index][1]; + vec4f_t z = h->localMatrix.a[index][2]; + vec4f_t t = h->localMatrix.a[index][3]; + + // "one" is to ensure both the scalar and translation have 1 in their + // forth components + vec4f_t one = { 0, 0, 0, 1 }; + vec4f_t nx = { x[0], y[0], z[0], 0 }; + vec4f_t ny = { x[1], y[1], z[1], 0 }; + vec4f_t nz = { x[2], y[2], z[2], 0 }; + vec4f_t nt = one - t[0] * nx - t[1] * ny - t[2] * nz; + // vertical dot product!!! + vec4f_t s = 1 / (nx * nx + ny * ny + nz * nz + one); + h->localInverse.a[index][0] = nx * s; + h->localInverse.a[index][1] = ny * s; + h->localInverse.a[index][2] = nz * s; + h->localInverse.a[index][3] = nt * s; +} + +void +Hierarchy_UpdateMatrices (hierarchy_t *h) +{ + for (size_t i = 0; i < h->localInverse.size; i++) { + if (h->modified.a[i]) { + hierarchy_calcLocalInverse (h, i); + } + } + if (h->modified.a[0]) { + memcpy (h->worldMatrix.a[0], + h->localMatrix.a[0], sizeof (mat4_t)); + memcpy (h->worldInverse.a[0], + h->localInverse.a[0], sizeof (mat4_t)); + h->worldRotation.a[0] = h->localRotation.a[0]; + h->worldScale.a[0] = h->localScale.a[0]; + } + for (size_t i = 1; i < h->worldMatrix.size; i++) { + uint32_t parent = h->parentIndex.a[i]; + + if (h->modified.a[i] || h->modified.a[parent]) { + mmulf (h->worldMatrix.a[i], + h->worldMatrix.a[parent], h->localMatrix.a[i]); + h->modified.a[i] = 1; + } + } + for (size_t i = 1; i < h->worldInverse.size; i++) { + uint32_t parent = h->parentIndex.a[i]; + + if (h->modified.a[i] || h->modified.a[parent]) { + mmulf (h->worldInverse.a[i], + h->localInverse.a[i], h->worldInverse.a[parent]); + } + } + for (size_t i = 1; i < h->worldRotation.size; i++) { + uint32_t parent = h->parentIndex.a[i]; + if (h->modified.a[i] || h->modified.a[parent]) { + h->worldRotation.a[i] = qmulf (h->worldRotation.a[parent], + h->localRotation.a[i]); + } + } + for (size_t i = 1; i < h->worldScale.size; i++) { + uint32_t parent = h->parentIndex.a[i]; + if (h->modified.a[i] || h->modified.a[parent]) { + h->worldScale.a[i] = m3vmulf (h->worldMatrix.a[parent], + h->localScale.a[i]); + } + } + memset (h->modified.a, 0, h->modified.size); +} + +static void +hierarchy_open (hierarchy_t *hierarchy, uint32_t index, uint32_t count) +{ + DARRAY_OPEN_AT (&hierarchy->transform, index, count); + DARRAY_OPEN_AT (&hierarchy->entity, index, count); + DARRAY_OPEN_AT (&hierarchy->childCount, index, count); + DARRAY_OPEN_AT (&hierarchy->childIndex, index, count); + DARRAY_OPEN_AT (&hierarchy->parentIndex, index, count); + DARRAY_OPEN_AT (&hierarchy->name, index, count); + DARRAY_OPEN_AT (&hierarchy->tag, index, count); + DARRAY_OPEN_AT (&hierarchy->modified, index, count); + DARRAY_OPEN_AT (&hierarchy->localMatrix, index, count); + DARRAY_OPEN_AT (&hierarchy->localInverse, index, count); + DARRAY_OPEN_AT (&hierarchy->worldMatrix, index, count); + DARRAY_OPEN_AT (&hierarchy->worldInverse, index, count); + DARRAY_OPEN_AT (&hierarchy->localRotation, index, count); + DARRAY_OPEN_AT (&hierarchy->localScale, index, count); + DARRAY_OPEN_AT (&hierarchy->worldRotation, index, count); + DARRAY_OPEN_AT (&hierarchy->worldScale, index, count); +} + +static void +hierarchy_close (hierarchy_t *hierarchy, uint32_t index, uint32_t count) +{ + if (count) { + DARRAY_CLOSE_AT (&hierarchy->transform, index, count); + DARRAY_CLOSE_AT (&hierarchy->entity, index, count); + DARRAY_CLOSE_AT (&hierarchy->childCount, index, count); + DARRAY_CLOSE_AT (&hierarchy->childIndex, index, count); + DARRAY_CLOSE_AT (&hierarchy->parentIndex, index, count); + DARRAY_CLOSE_AT (&hierarchy->name, index, count); + DARRAY_CLOSE_AT (&hierarchy->tag, index, count); + DARRAY_CLOSE_AT (&hierarchy->modified, index, count); + DARRAY_CLOSE_AT (&hierarchy->localMatrix, index, count); + DARRAY_CLOSE_AT (&hierarchy->localInverse, index, count); + DARRAY_CLOSE_AT (&hierarchy->worldMatrix, index, count); + DARRAY_CLOSE_AT (&hierarchy->worldInverse, index, count); + DARRAY_CLOSE_AT (&hierarchy->localRotation, index, count); + DARRAY_CLOSE_AT (&hierarchy->localScale, index, count); + DARRAY_CLOSE_AT (&hierarchy->worldRotation, index, count); + DARRAY_CLOSE_AT (&hierarchy->worldScale, index, count); + } +} + +static void +hierarchy_move (hierarchy_t *dst, const hierarchy_t *src, + uint32_t dstIndex, uint32_t srcIndex, uint32_t count) +{ + memcpy (&dst->transform.a[dstIndex], &src->transform.a[srcIndex], + count * sizeof(dst->transform.a[0])); + memset (&src->transform.a[srcIndex], 0, + count * sizeof(dst->transform.a[0])); + memcpy (&dst->entity.a[dstIndex], &src->entity.a[srcIndex], + count * sizeof(dst->entity.a[0])); + memcpy (&dst->name.a[dstIndex], &src->name.a[srcIndex], + count * sizeof(dst->name.a[0])); + memcpy (&dst->tag.a[dstIndex], &src->tag.a[srcIndex], + count * sizeof(dst->tag.a[0])); + memset (&dst->modified.a[dstIndex], 1, count * sizeof(dst->modified.a[0])); + memcpy (&dst->localMatrix.a[dstIndex], &src->localMatrix.a[srcIndex], + count * sizeof(dst->localMatrix.a[0])); + memcpy (&dst->localInverse.a[dstIndex], &src->localInverse.a[srcIndex], + count * sizeof(dst->localInverse.a[0])); + memcpy (&dst->localRotation.a[dstIndex], &src->localRotation.a[srcIndex], + count * sizeof(dst->localRotation.a[0])); + memcpy (&dst->localScale.a[dstIndex], &src->localScale.a[srcIndex], + count * sizeof(dst->localScale.a[0])); + + for (uint32_t i = 0; i < count; i++) { + dst->transform.a[dstIndex + i]->hierarchy = dst; + dst->transform.a[dstIndex + i]->index = dstIndex + i; + } +} + +static void +hierarchy_init (hierarchy_t *dst, uint32_t index, + uint32_t parentIndex, uint32_t childIndex, uint32_t count) +{ + memset (&dst->transform.a[index], 0, + count * sizeof(dst->transform.a[0])); + memset (&dst->entity.a[index], 0, count * sizeof(dst->entity.a[0])); + memset (&dst->name.a[index], 0, count * sizeof(dst->name.a[0])); + memset (&dst->tag.a[index], 0, count * sizeof(dst->tag.a[0])); + memset (&dst->modified.a[index], 1, count * sizeof(dst->modified.a[0])); + + for (uint32_t i = 0; i < count; i++) { + mat4fidentity (dst->localMatrix.a[index]); + mat4fidentity (dst->localInverse.a[index]); + dst->localRotation.a[index] = (vec4f_t) { 0, 0, 0, 1 }; + dst->localScale.a[index] = (vec4f_t) { 1, 1, 1, 1 }; + + dst->parentIndex.a[index + i] = parentIndex; + dst->childCount.a[index + i] = 0; + dst->childIndex.a[index + i] = childIndex; + } +} + +static uint32_t +hierarchy_insert (hierarchy_t *dst, const hierarchy_t *src, + uint32_t dstParent, uint32_t srcRoot, uint32_t count) +{ + uint32_t insertIndex; // where the transforms will be inserted + uint32_t childIndex; // where the transforms' children will inserted + + // The newly added transforms are always last children of the parent + // transform + insertIndex = dst->childIndex.a[dstParent] + dst->childCount.a[dstParent]; + + // By design, all of a transform's children are in one contiguous block, + // and the blocks of children for each transform are ordered by their + // parents. Thus the child index of each transform increases monotonically + // for each child index in the array, regardless of the level of the owning + // transform (higher levels always come before lower levels). + uint32_t neighbor = insertIndex - 1; // insertIndex never zero + childIndex = dst->childIndex.a[neighbor] + dst->childCount.a[neighbor]; + + // Any transforms that come after the inserted transforms need to have + // thier indices adjusted. + hierarchy_UpdateTransformIndices (dst, insertIndex, count); + // The parent transform's child index is not affected, but the child + // indices of all transforms immediately after the parent transform are. + hierarchy_UpdateChildIndices (dst, dstParent + 1, count); + hierarchy_UpdateParentIndices (dst, childIndex, count); + + // The beginning of the block of children for the new transforms was + // computed from the pre-insert indices of the related transforms, thus + // the index must be updated by the number of transforms being inserted + // (it would have been updated thusly if the insert was done before + // updating the indices of the other transforms). + childIndex += count; + + hierarchy_open (dst, insertIndex, count); + if (src) { + hierarchy_move (dst, src, insertIndex, srcRoot, count); + } else { + hierarchy_init (dst, insertIndex, dstParent, childIndex, count); + } + for (uint32_t i = 0; i < count; i++) { + dst->parentIndex.a[insertIndex + i] = dstParent; + dst->childIndex.a[insertIndex + i] = childIndex; + dst->childCount.a[insertIndex + i] = 0; + } + + dst->childCount.a[dstParent] += count; + return insertIndex; +} + +static void +hierarchy_insert_children (hierarchy_t *dst, const hierarchy_t *src, + uint32_t dstParent, uint32_t srcRoot) +{ + uint32_t insertIndex; + uint32_t childIndex = src->childIndex.a[srcRoot]; + uint32_t childCount = src->childCount.a[srcRoot]; + + if (childCount) { + insertIndex = hierarchy_insert (dst, src, dstParent, + childIndex, childCount); + for (uint32_t i = 0; i < childCount; i++) { + hierarchy_insert_children (dst, src, insertIndex + i, + childIndex + i); + } + } +} + +uint32_t +Hierarchy_InsertHierarchy (hierarchy_t *dst, const hierarchy_t *src, + uint32_t dstParent, uint32_t srcRoot) +{ + uint32_t insertIndex; + + if (dstParent == null_transform) { + if (dst->transform.size) { + Sys_Error ("attempt to insert root in non-empty hierarchy"); + } + hierarchy_open (dst, 0, 1); + hierarchy_move (dst, src, 0, srcRoot, 1); + dst->parentIndex.a[0] = null_transform; + dst->childIndex.a[0] = 1; + dst->childCount.a[0] = 0; + insertIndex = 0; + } else { + if (!dst->transform.size) { + Sys_Error ("attempt to insert non-root in empty hierarchy"); + } + insertIndex = hierarchy_insert (dst, src, dstParent, srcRoot, 1); + } + // if src is null, then inserting a new transform which has no children + if (src) { + hierarchy_insert_children (dst, src, insertIndex, srcRoot); + } + Hierarchy_UpdateMatrices (dst); + return insertIndex; +} + +static void +hierarchy_remove_children (hierarchy_t *hierarchy, uint32_t index) +{ + uint32_t childIndex = hierarchy->childIndex.a[index]; + uint32_t childCount = hierarchy->childCount.a[index]; + uint32_t parentIndex = hierarchy->parentIndex.a[index]; + uint32_t nieceIndex = null_transform; + + if (parentIndex != null_transform) { + uint32_t siblingIndex = hierarchy->childIndex.a[parentIndex]; + siblingIndex += hierarchy->childCount.a[parentIndex] - 1; + nieceIndex = hierarchy->childIndex.a[siblingIndex]; + } + for (uint32_t i = childCount; i-- > 0; ) { + hierarchy_remove_children (hierarchy, childIndex + i); + } + hierarchy_close (hierarchy, childIndex, childCount); + hierarchy->childCount.a[index] = 0; + + if (childCount) { + hierarchy_UpdateTransformIndices (hierarchy, childIndex, -childCount); + hierarchy_UpdateChildIndices (hierarchy, index, -childCount); + if (nieceIndex != null_transform) { + hierarchy_UpdateParentIndices (hierarchy, nieceIndex, -childCount); + } + } +} + +void +Hierarchy_RemoveHierarchy (hierarchy_t *hierarchy, uint32_t index) +{ + uint32_t parentIndex = hierarchy->parentIndex.a[index]; + uint32_t childIndex = hierarchy->childIndex.a[index]; + uint32_t siblingIndex = null_transform; + if (parentIndex != null_transform) { + siblingIndex = hierarchy->childIndex.a[parentIndex]; + } + hierarchy_remove_children (hierarchy, index); + hierarchy_close (hierarchy, index, 1); + if (siblingIndex != null_transform) { + hierarchy_UpdateTransformIndices (hierarchy, index, -1); + hierarchy_UpdateChildIndices (hierarchy, siblingIndex, -1); + hierarchy_UpdateParentIndices (hierarchy, childIndex - 1, -1); + } +} + +hierarchy_t * +Hierarchy_New (size_t grow, int createRoot) +{ + if (!grow) { + grow = 16; + } + hierarchy_t *hierarchy = malloc (sizeof (hierarchy_t)); + + DARRAY_INIT (&hierarchy->transform, grow); + DARRAY_INIT (&hierarchy->entity, grow); + DARRAY_INIT (&hierarchy->childCount, grow); + DARRAY_INIT (&hierarchy->childIndex, grow); + DARRAY_INIT (&hierarchy->parentIndex, grow); + DARRAY_INIT (&hierarchy->name, grow); + DARRAY_INIT (&hierarchy->tag, grow); + DARRAY_INIT (&hierarchy->modified, grow); + DARRAY_INIT (&hierarchy->localMatrix, grow); + DARRAY_INIT (&hierarchy->localInverse, grow); + DARRAY_INIT (&hierarchy->worldMatrix, grow); + DARRAY_INIT (&hierarchy->worldInverse, grow); + DARRAY_INIT (&hierarchy->localRotation, grow); + DARRAY_INIT (&hierarchy->localScale, grow); + DARRAY_INIT (&hierarchy->worldRotation, grow); + DARRAY_INIT (&hierarchy->worldScale, grow); + + if (createRoot) { + hierarchy_open (hierarchy, 0, 1); + hierarchy_init (hierarchy, 0, null_transform, 1, 1); + } + + return hierarchy; +} + +void +Hierarchy_Delete (hierarchy_t *hierarchy) +{ + for (size_t i = 0; i < hierarchy->transform.size; i++) { + free (hierarchy->transform.a[i]); + } + for (size_t i = 0; i < hierarchy->name.size; i++) { + free (hierarchy->name.a[i]); + } + DARRAY_CLEAR (&hierarchy->transform); + DARRAY_CLEAR (&hierarchy->entity); + DARRAY_CLEAR (&hierarchy->childCount); + DARRAY_CLEAR (&hierarchy->childIndex); + DARRAY_CLEAR (&hierarchy->parentIndex); + DARRAY_CLEAR (&hierarchy->name); + DARRAY_CLEAR (&hierarchy->tag); + DARRAY_CLEAR (&hierarchy->modified); + DARRAY_CLEAR (&hierarchy->localMatrix); + DARRAY_CLEAR (&hierarchy->localInverse); + DARRAY_CLEAR (&hierarchy->worldMatrix); + DARRAY_CLEAR (&hierarchy->worldInverse); + DARRAY_CLEAR (&hierarchy->localRotation); + DARRAY_CLEAR (&hierarchy->localScale); + DARRAY_CLEAR (&hierarchy->worldRotation); + DARRAY_CLEAR (&hierarchy->worldScale); + free (hierarchy); +} diff --git a/libs/entity/test/Makemodule.am b/libs/entity/test/Makemodule.am new file mode 100644 index 000000000..b0f98ae2b --- /dev/null +++ b/libs/entity/test/Makemodule.am @@ -0,0 +1,19 @@ +libs_entity_tests = \ + libs/entity/test/test-hierarchy \ + $e + +TESTS += $(libs_entity_tests) + +check_PROGRAMS += $(libs_entity_tests) + +libs_entity_test_libs= \ + libs/entity/libQFentity.la \ + libs/util/libQFutil.la + +libs_entity_test_test_hierarchy_SOURCES= \ + libs/entity/test/test-hierarchy.c \ + $e +libs_entity_test_test_hierarchy_LDADD= \ + $(libs_entity_test_libs) +libs_entity_test_test_hierarchy_DEPENDENCIES= \ + $(libs_entity_test_libs) diff --git a/libs/entity/test/test-hierarchy.c b/libs/entity/test/test-hierarchy.c new file mode 100644 index 000000000..513f33fca --- /dev/null +++ b/libs/entity/test/test-hierarchy.c @@ -0,0 +1,707 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "QF/entity.h" + +// NOTE: these are the columns of the matrix! (not that it matters for a +// symmetrical matrix, but...) +mat4f_t identity = { + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 }, +}; +vec4f_t one = { 1, 1, 1, 1 }; + +static int +vec4_equal (vec4f_t a, vec4f_t b) +{ + vec4i_t res = a != b; + return !(res[0] || res[1] || res[2] || res[3]); +} + +static int +mat4_equal (const mat4f_t a, const mat4f_t b) +{ + vec4i_t res = {}; + + for (int i = 0; i < 4; i++) { + res |= a[i] != b[i]; + } + return !(res[0] || res[1] || res[2] || res[3]); +} + +static int +check_hierarchy_size (hierarchy_t *h, uint32_t size) +{ + if (h->transform.size != size + || h->entity.size != size + || h->childCount.size != size + || h->childIndex.size != size + || h->parentIndex.size != size + || h->name.size != size + || h->tag.size != size + || h->modified.size != size + || h->localMatrix.size != size + || h->localInverse.size != size + || h->worldMatrix.size != size + || h->worldInverse.size != size + || h->localRotation.size != size + || h->localScale.size != size + || h->worldRotation.size != size + || h->worldScale.size != size) { + printf ("hierarchy does not have exactly %u" + " transform or array sizes are inconsistent\n", size); + return 0; + } + for (size_t i = 0; i < h->transform.size; i++) { + if (h->transform.a[i]->hierarchy != h) { + printf ("transform %zd (%s) does not point to hierarchy\n", + i, h->name.a[i]); + } + } + return 1; +} + +static void +dump_hierarchy (hierarchy_t *h) +{ + for (size_t i = 0; i < h->transform.size; i++) { + printf ("%2zd: %5s %2u %2u %2u %2u\n", i, h->name.a[i], + h->transform.a[i]->index, h->parentIndex.a[i], + h->childIndex.a[i], h->childCount.a[i]); + } + puts (""); +} + +static int +check_indices (transform_t *transform, uint32_t index, uint32_t parentIndex, + uint32_t childIndex, uint32_t childCount) +{ + hierarchy_t *h = transform->hierarchy; + if (transform->index != index) { + printf ("%s/%s index incorrect: expect %u got %u\n", + h->name.a[transform->index], h->name.a[index], + index, transform->index); + return 0; + } + if (h->parentIndex.a[index] != parentIndex) { + printf ("%s parent index incorrect: expect %u got %u\n", + h->name.a[index], parentIndex, h->parentIndex.a[index]); + return 0; + } + if (h->childIndex.a[index] != childIndex) { + printf ("%s child index incorrect: expect %u got %u\n", + h->name.a[index], childIndex, h->childIndex.a[index]); + return 0; + } + if (h->childCount.a[index] != childCount) { + printf ("%s child count incorrect: expect %u got %u\n", + h->name.a[index], childCount, h->childCount.a[index]); + return 0; + } + return 1; +} + +static int +test_single_transform (void) +{ + transform_t *transform = Transform_New (0); + hierarchy_t *h; + + if (!transform) { + printf ("Transform_New returned null\n"); + return 1; + } + if (!(h = transform->hierarchy)) { + printf ("New transform has no hierarchy\n"); + return 1; + } + if (!check_hierarchy_size (h, 1)) { return 1; } + if (!check_indices (transform, 0, null_transform, 1, 0)) { return 1; } + + if (!mat4_equal (h->localMatrix.a[0], identity) + || !mat4_equal (h->localInverse.a[0], identity) + || !mat4_equal (h->worldMatrix.a[0], identity) + || !mat4_equal (h->worldInverse.a[0], identity)) { + printf ("New transform matrices not identity\n"); + return 1; + } + + if (!vec4_equal (h->localRotation.a[0], identity[3]) + || !vec4_equal (h->localScale.a[0], one)) { + printf ("New transform rotation or scale not identity\n"); + return 1; + } + + // Delete the hierarchy directly as setparent isn't fully tested + Hierarchy_Delete (transform->hierarchy); + + return 0; +} + +static int +test_parent_child_init (void) +{ + transform_t *parent = Transform_New (0); + transform_t *child = Transform_New (parent); + + if (parent->hierarchy != child->hierarchy) { + printf ("parent and child transforms have separate hierarchies\n"); + return 1; + } + + if (!check_hierarchy_size (parent->hierarchy, 2)) { return 1; } + + if (!check_indices (parent, 0, null_transform, 1, 1)) { return 1; } + if (!check_indices (child, 1, 0, 2, 0)) { return 1; } + + hierarchy_t *h = parent->hierarchy; + if (!mat4_equal (h->localMatrix.a[0], identity) + || !mat4_equal (h->localInverse.a[0], identity) + || !mat4_equal (h->worldMatrix.a[0], identity) + || !mat4_equal (h->worldInverse.a[0], identity)) { + printf ("Parent transform matrices not identity\n"); + return 1; + } + + if (!vec4_equal (h->localRotation.a[0], identity[3]) + || !vec4_equal (h->localScale.a[0], one)) { + printf ("Parent transform rotation or scale not identity\n"); + return 1; + } + + if (!mat4_equal (h->localMatrix.a[1], identity) + || !mat4_equal (h->localInverse.a[1], identity) + || !mat4_equal (h->worldMatrix.a[1], identity) + || !mat4_equal (h->worldInverse.a[1], identity)) { + printf ("Child transform matrices not identity\n"); + return 1; + } + + if (!vec4_equal (h->localRotation.a[1], identity[3]) + || !vec4_equal (h->localScale.a[1], one)) { + printf ("Child transform rotation or scale not identity\n"); + return 1; + } + + // Delete the hierarchy directly as setparent isn't fully tested + Hierarchy_Delete (parent->hierarchy); + + return 0; +} + +static int +test_parent_child_setparent (void) +{ + transform_t *parent = Transform_New (0); + transform_t *child = Transform_New (0); + + Transform_SetName (parent, "parent"); + Transform_SetName (child, "child"); + + if (!check_indices (parent, 0, null_transform, 1, 0)) { return 1; } + if (!check_indices (child, 0, null_transform, 1, 0)) { return 1; } + + if (parent->hierarchy == child->hierarchy) { + printf ("parent and child transforms have same hierarchy before" + " set paret\n"); + return 1; + } + + Transform_SetParent (child, parent); + + if (parent->hierarchy != child->hierarchy) { + printf ("parent and child transforms have separate hierarchies\n"); + return 1; + } + + if (!check_hierarchy_size (parent->hierarchy, 2)) { return 1; } + + if (!check_indices (parent, 0, null_transform, 1, 1)) { return 1; } + if (!check_indices (child, 1, 0, 2, 0)) { return 1; } + + hierarchy_t *h = parent->hierarchy; + if (!mat4_equal (h->localMatrix.a[0], identity) + || !mat4_equal (h->localInverse.a[0], identity) + || !mat4_equal (h->worldMatrix.a[0], identity) + || !mat4_equal (h->worldInverse.a[0], identity)) { + printf ("Parent transform matrices not identity\n"); + return 1; + } + + if (!vec4_equal (h->localRotation.a[0], identity[3]) + || !vec4_equal (h->localScale.a[0], one)) { + printf ("Parent transform rotation or scale not identity\n"); + return 1; + } + + if (!mat4_equal (h->localMatrix.a[1], identity) + || !mat4_equal (h->localInverse.a[1], identity) + || !mat4_equal (h->worldMatrix.a[1], identity) + || !mat4_equal (h->worldInverse.a[1], identity)) { + printf ("Child transform matrices not identity\n"); + return 1; + } + + if (!vec4_equal (h->localRotation.a[1], identity[3]) + || !vec4_equal (h->localScale.a[1], one)) { + printf ("Child transform rotation or scale not identity\n"); + return 1; + } + + // Delete the hierarchy directly as setparent isn't fully tested + Hierarchy_Delete (parent->hierarchy); + + return 0; +} + +static int +test_build_hierarchy (void) +{ + printf ("test_build_hierarchy\n"); + + transform_t *root = Transform_NewNamed (0, "root"); + transform_t *A = Transform_NewNamed (root, "A"); + transform_t *B = Transform_NewNamed (root, "B"); + transform_t *C = Transform_NewNamed (root, "C"); + + if (!check_indices (root, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices (A, 1, 0, 4, 0)) { return 1; } + if (!check_indices (B, 2, 0, 4, 0)) { return 1; } + if (!check_indices (C, 3, 0, 4, 0)) { return 1; } + + transform_t *B1 = Transform_NewNamed (B, "B1"); + + if (!check_indices (root, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices ( A, 1, 0, 4, 0)) { return 1; } + if (!check_indices ( B, 2, 0, 4, 1)) { return 1; } + if (!check_indices ( C, 3, 0, 5, 0)) { return 1; } + if (!check_indices (B1, 4, 2, 5, 0)) { return 1; } + + transform_t *A1 = Transform_NewNamed (A, "A1"); + + if (!check_indices (root, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices ( A, 1, 0, 4, 1)) { return 1; } + if (!check_indices ( B, 2, 0, 5, 1)) { return 1; } + if (!check_indices ( C, 3, 0, 6, 0)) { return 1; } + if (!check_indices (A1, 4, 1, 6, 0)) { return 1; } + if (!check_indices (B1, 5, 2, 6, 0)) { return 1; } + transform_t *A1a = Transform_NewNamed (A1, "A1a"); + transform_t *B2 = Transform_NewNamed (B, "B2"); + transform_t *A2 = Transform_NewNamed (A, "A2"); + transform_t *B3 = Transform_NewNamed (B, "B3"); + transform_t *B2a = Transform_NewNamed (B2, "B2a"); + + if (!check_hierarchy_size (root->hierarchy, 11)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices ( A, 1, 0, 4, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 6, 3)) { return 1; } + if (!check_indices ( C, 3, 0, 9, 0)) { return 1; } + if (!check_indices ( A1, 4, 1, 9, 1)) { return 1; } + if (!check_indices ( A2, 5, 1, 10, 0)) { return 1; } + if (!check_indices ( B1, 6, 2, 10, 0)) { return 1; } + if (!check_indices ( B2, 7, 2, 10, 1)) { return 1; } + if (!check_indices ( B3, 8, 2, 11, 0)) { return 1; } + if (!check_indices (A1a, 9, 4, 11, 0)) { return 1; } + if (!check_indices (B2a, 10, 7, 11, 0)) { return 1; } + + transform_t *D = Transform_NewNamed (root, "D"); + + if (!check_hierarchy_size (root->hierarchy, 12)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 4)) { return 1; } + if (!check_indices ( A, 1, 0, 5, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 7, 3)) { return 1; } + if (!check_indices ( C, 3, 0, 10, 0)) { return 1; } + if (!check_indices ( D, 4, 0, 10, 0)) { return 1; } + if (!check_indices ( A1, 5, 1, 10, 1)) { return 1; } + if (!check_indices ( A2, 6, 1, 11, 0)) { return 1; } + if (!check_indices ( B1, 7, 2, 11, 0)) { return 1; } + if (!check_indices ( B2, 8, 2, 11, 1)) { return 1; } + if (!check_indices ( B3, 9, 2, 12, 0)) { return 1; } + if (!check_indices (A1a, 10, 5, 12, 0)) { return 1; } + if (!check_indices (B2a, 11, 8, 12, 0)) { return 1; } + + dump_hierarchy (root->hierarchy); + transform_t *C1 = Transform_NewNamed (C, "C1"); + dump_hierarchy (root->hierarchy); + if (!check_hierarchy_size (root->hierarchy, 13)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 4)) { return 1; } + if (!check_indices ( A, 1, 0, 5, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 7, 3)) { return 1; } + if (!check_indices ( C, 3, 0, 10, 1)) { return 1; } + if (!check_indices ( D, 4, 0, 11, 0)) { return 1; } + if (!check_indices ( A1, 5, 1, 11, 1)) { return 1; } + if (!check_indices ( A2, 6, 1, 12, 0)) { return 1; } + if (!check_indices ( B1, 7, 2, 12, 0)) { return 1; } + if (!check_indices ( B2, 8, 2, 12, 1)) { return 1; } + if (!check_indices ( B3, 9, 2, 13, 0)) { return 1; } + if (!check_indices ( C1, 10, 3, 13, 0)) { return 1; } + if (!check_indices (A1a, 11, 5, 13, 0)) { return 1; } + if (!check_indices (B2a, 12, 8, 13, 0)) { return 1; } + + // Delete the hierarchy directly as setparent isn't fully tested + Hierarchy_Delete (root->hierarchy); + + return 0; +} + +static int +test_build_hierarchy2 (void) +{ + printf ("test_build_hierarchy2\n"); + + transform_t *root = Transform_NewNamed (0, "root"); + transform_t *A = Transform_NewNamed (root, "A"); + transform_t *B = Transform_NewNamed (root, "B"); + transform_t *C = Transform_NewNamed (root, "C"); + transform_t *B1 = Transform_NewNamed (B, "B1"); + transform_t *A1 = Transform_NewNamed (A, "A1"); + transform_t *A1a = Transform_NewNamed (A1, "A1a"); + transform_t *B2 = Transform_NewNamed (B, "B2"); + transform_t *A2 = Transform_NewNamed (A, "A2"); + transform_t *B3 = Transform_NewNamed (B, "B3"); + transform_t *B2a = Transform_NewNamed (B2, "B2a"); + transform_t *D = Transform_NewNamed (root, "D"); + transform_t *C1 = Transform_NewNamed (C, "C1"); + + if (!check_hierarchy_size (root->hierarchy, 13)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 4)) { return 1; } + if (!check_indices ( A, 1, 0, 5, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 7, 3)) { return 1; } + if (!check_indices ( C, 3, 0, 10, 1)) { return 1; } + if (!check_indices ( D, 4, 0, 11, 0)) { return 1; } + if (!check_indices ( A1, 5, 1, 11, 1)) { return 1; } + if (!check_indices ( A2, 6, 1, 12, 0)) { return 1; } + if (!check_indices ( B1, 7, 2, 12, 0)) { return 1; } + if (!check_indices ( B2, 8, 2, 12, 1)) { return 1; } + if (!check_indices ( B3, 9, 2, 13, 0)) { return 1; } + if (!check_indices ( C1, 10, 3, 13, 0)) { return 1; } + if (!check_indices (A1a, 11, 5, 13, 0)) { return 1; } + if (!check_indices (B2a, 12, 8, 13, 0)) { return 1; } + + transform_t *T = Transform_NewNamed (0, "T"); + transform_t *X = Transform_NewNamed (T, "X"); + transform_t *Y = Transform_NewNamed (T, "Y"); + transform_t *Z = Transform_NewNamed (T, "Z"); + transform_t *Y1 = Transform_NewNamed (Y, "Y1"); + transform_t *X1 = Transform_NewNamed (X, "X1"); + transform_t *X1a = Transform_NewNamed (X1, "X1a"); + transform_t *Y2 = Transform_NewNamed (Y, "Y2"); + transform_t *X2 = Transform_NewNamed (X, "X2"); + transform_t *Y3 = Transform_NewNamed (Y, "Y3"); + transform_t *Y2a = Transform_NewNamed (Y2, "Y2a"); + transform_t *Z1 = Transform_NewNamed (Z, "Z1"); + + dump_hierarchy (T->hierarchy); + if (!check_hierarchy_size (T->hierarchy, 12)) { return 1; } + + if (!check_indices ( T, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices ( X, 1, 0, 4, 2)) { return 1; } + if (!check_indices ( Y, 2, 0, 6, 3)) { return 1; } + if (!check_indices ( Z, 3, 0, 9, 1)) { return 1; } + if (!check_indices ( X1, 4, 1, 10, 1)) { return 1; } + if (!check_indices ( X2, 5, 1, 11, 0)) { return 1; } + if (!check_indices ( Y1, 6, 2, 11, 0)) { return 1; } + if (!check_indices ( Y2, 7, 2, 11, 1)) { return 1; } + if (!check_indices ( Y3, 8, 2, 12, 0)) { return 1; } + if (!check_indices ( Z1, 9, 3, 12, 0)) { return 1; } + if (!check_indices (X1a, 10, 4, 12, 0)) { return 1; } + if (!check_indices (Y2a, 11, 7, 12, 0)) { return 1; } + + Transform_SetParent (T, B); + + dump_hierarchy (root->hierarchy); + + if (!check_hierarchy_size (root->hierarchy, 25)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 4)) { return 1; } + if (!check_indices ( A, 1, 0, 5, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 7, 4)) { return 1; } + if (!check_indices ( C, 3, 0, 11, 1)) { return 1; } + if (!check_indices ( D, 4, 0, 12, 0)) { return 1; } + if (!check_indices ( A1, 5, 1, 12, 1)) { return 1; } + if (!check_indices ( A2, 6, 1, 13, 0)) { return 1; } + if (!check_indices ( B1, 7, 2, 13, 0)) { return 1; } + if (!check_indices ( B2, 8, 2, 13, 1)) { return 1; } + if (!check_indices ( B3, 9, 2, 14, 0)) { return 1; } + if (!check_indices ( T, 10, 2, 14, 3)) { return 1; } + if (!check_indices ( C1, 11, 3, 17, 0)) { return 1; } + if (!check_indices (A1a, 12, 5, 17, 0)) { return 1; } + if (!check_indices (B2a, 13, 8, 17, 0)) { return 1; } + if (!check_indices ( X, 14, 10, 17, 2)) { return 1; } + if (!check_indices ( Y, 15, 10, 19, 3)) { return 1; } + if (!check_indices ( Z, 16, 10, 22, 1)) { return 1; } + if (!check_indices ( X1, 17, 14, 23, 1)) { return 1; } + if (!check_indices ( X2, 18, 14, 24, 0)) { return 1; } + if (!check_indices ( Y1, 19, 15, 24, 0)) { return 1; } + if (!check_indices ( Y2, 20, 15, 24, 1)) { return 1; } + if (!check_indices ( Y3, 21, 15, 25, 0)) { return 1; } + if (!check_indices ( Z1, 22, 16, 25, 0)) { return 1; } + if (!check_indices (X1a, 23, 17, 25, 0)) { return 1; } + if (!check_indices (Y2a, 24, 20, 25, 0)) { return 1; } + + Transform_SetParent (Y, 0); + + dump_hierarchy (root->hierarchy); + dump_hierarchy (Y->hierarchy); + if (!check_hierarchy_size (root->hierarchy, 20)) { return 1; } + if (!check_hierarchy_size (Y->hierarchy, 5)) { return 1; } + + if (!check_indices (root, 0, null_transform, 1, 4)) { return 1; } + if (!check_indices ( A, 1, 0, 5, 2)) { return 1; } + if (!check_indices ( B, 2, 0, 7, 4)) { return 1; } + if (!check_indices ( C, 3, 0, 11, 1)) { return 1; } + if (!check_indices ( D, 4, 0, 12, 0)) { return 1; } + if (!check_indices ( A1, 5, 1, 12, 1)) { return 1; } + if (!check_indices ( A2, 6, 1, 13, 0)) { return 1; } + if (!check_indices ( B1, 7, 2, 13, 0)) { return 1; } + if (!check_indices ( B2, 8, 2, 13, 1)) { return 1; } + if (!check_indices ( B3, 9, 2, 14, 0)) { return 1; } + if (!check_indices ( T, 10, 2, 14, 3)) { return 1; } + if (!check_indices ( C1, 11, 3, 17, 0)) { return 1; } + if (!check_indices (A1a, 12, 5, 17, 0)) { return 1; } + if (!check_indices (B2a, 13, 8, 17, 0)) { return 1; } + if (!check_indices ( X, 14, 10, 16, 2)) { return 1; } + if (!check_indices ( Z, 15, 10, 18, 1)) { return 1; } + if (!check_indices ( X1, 16, 14, 19, 1)) { return 1; } + if (!check_indices ( X2, 17, 14, 20, 0)) { return 1; } + if (!check_indices ( Z1, 18, 15, 20, 0)) { return 1; } + if (!check_indices (X1a, 19, 16, 20, 0)) { return 1; } + + if (!check_indices ( Y, 0, null_transform, 1, 3)) { return 1; } + if (!check_indices ( Y1, 1, 0, 4, 0)) { return 1; } + if (!check_indices ( Y2, 2, 0, 4, 1)) { return 1; } + if (!check_indices ( Y3, 3, 0, 5, 0)) { return 1; } + if (!check_indices (Y2a, 4, 2, 5, 0)) { return 1; } + + // Delete the hierarchy directly as setparent isn't fully tested + Hierarchy_Delete (root->hierarchy); + Hierarchy_Delete (Y->hierarchy); + + return 0; +} + +static int +check_vector (const transform_t *transform, + vec4f_t (*func) (const transform_t *t), + vec4f_t expect, const char *msg) +{ + vec4f_t res = func(transform); + if (!vec4_equal (res, expect)) { + printf ("%s %s: expected "VEC4F_FMT" got "VEC4F_FMT"\n", + Transform_GetName (transform), msg, + VEC4_EXP (expect), VEC4_EXP (res)); + return 0; + } + return 1; +} + +static int +test_frames (void) +{ + transform_t *root = Transform_NewNamed (0, "root"); + transform_t *A = Transform_NewNamed (root, "A"); + transform_t *B = Transform_NewNamed (root, "B"); + transform_t *A1 = Transform_NewNamed (A, "A1"); + transform_t *B1 = Transform_NewNamed (B, "B1"); + + Transform_SetLocalPosition (root, (vec4f_t) { 0, 0, 1, 1 }); + Transform_SetLocalPosition (A, (vec4f_t) { 1, 0, 0, 1 }); + Transform_SetLocalRotation (A, (vec4f_t) { 0.5, 0.5, 0.5, 0.5 }); + Transform_SetLocalPosition (B, (vec4f_t) { 0, 1, 0, 1 }); + Transform_SetLocalRotation (B, (vec4f_t) { 0.5, -0.5, 0.5, 0.5 }); + Transform_SetLocalPosition (A1, (vec4f_t) { 1, 0, 0, 1 }); + Transform_SetLocalRotation (A1, (vec4f_t) { -0.5, -0.5, -0.5, 0.5 }); + Transform_SetLocalPosition (B1, (vec4f_t) { 0, 1, 0, 1 }); + Transform_SetLocalRotation (B1, (vec4f_t) { -0.5, 0.5, -0.5, 0.5 }); + + hierarchy_t *h = root->hierarchy; + for (size_t i = 0; i < h->transform.size; i++) { + mat4f_t res; + mmulf (res, h->localMatrix.a[i], h->localInverse.a[i]); + if (!mat4_equal (res, identity)) { + printf ("%s: localInverse not inverse of localMatrix\n", + h->name.a[i]); + printf ("l: " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 3)); + printf ("i: " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 3)); + printf ("r: " VEC4F_FMT "\n", MAT4_ROW(res, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 3)); + return 1; + } + puts (h->name.a[i]); + printf ("l: " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localMatrix.a[i], 3)); + printf ("i: " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->localInverse.a[i], 3)); + } + for (size_t i = 0; i < h->transform.size; i++) { + mat4f_t res; + mmulf (res, h->worldMatrix.a[i], h->worldInverse.a[i]); + if (!mat4_equal (res, identity)) { + printf ("%s: worldInverse not inverse of worldMatrix\n", + h->name.a[i]); + printf ("l: " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 3)); + printf ("i: " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 3)); + printf ("r: " VEC4F_FMT "\n", MAT4_ROW(res, 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(res, 3)); + return 1; + } + puts (h->name.a[i]); + printf ("l: " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldMatrix.a[i], 3)); + printf ("i: " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 0)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 1)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 2)); + printf (" " VEC4F_FMT "\n", MAT4_ROW(h->worldInverse.a[i], 3)); + } + + if (!check_vector (root, Transform_GetLocalPosition, + (vec4f_t) { 0, 0, 1, 1 }, "local position")) { + return 1; + } + if (!check_vector (root, Transform_GetWorldPosition, + (vec4f_t) { 0, 0, 1, 1 }, "world position")) { + return 1; + } + if (!check_vector (root, Transform_Right, (vec4f_t) { 1, 0, 0, 0 }, + "right")) { + return 1; + } + if (!check_vector (root, Transform_Forward, (vec4f_t) { 0, 1, 0, 0 }, + "right")) { + return 1; + } + if (!check_vector (root, Transform_Up, (vec4f_t) { 0, 0, 1, 0 }, + "up")) { + return 1; + } + + if (!check_vector (A, Transform_GetLocalPosition, (vec4f_t) { 1, 0, 0, 1 }, + "local position")) { + return 1; + } + if (!check_vector (A, Transform_GetWorldPosition, (vec4f_t) { 1, 0, 1, 1 }, + "world position")) { + return 1; + } + if (!check_vector (A, Transform_Right, (vec4f_t) { 0, 1, 0, 0 }, + "right")) { + return 1; + } + if (!check_vector (A, Transform_Forward, (vec4f_t) { 0, 0, 1, 0 }, + "forward")) { + return 1; + } + if (!check_vector (A, Transform_Up, (vec4f_t) { 1, 0, 0, 0 }, + "up")) { + return 1; + } + if (!check_vector (A1, Transform_GetLocalPosition, (vec4f_t) { 1, 0, 0, 1 }, + "local position")) { + return 1; + } + if (!check_vector (A1, Transform_GetWorldPosition, (vec4f_t) { 1, 1, 1, 1 }, + "world position")) { + return 1; + } + if (!check_vector (A1, Transform_Right, (vec4f_t) { 1, 0, 0, 0 }, + "right")) { + return 1; + } + if (!check_vector (A1, Transform_Forward, (vec4f_t) { 0, 1, 0, 0 }, + "forward")) { + return 1; + } + if (!check_vector (A1, Transform_Up, (vec4f_t) { 0, 0, 1, 0 }, + "up")) { + return 1; + } + + if (!check_vector (B, Transform_GetLocalPosition, (vec4f_t) { 0, 1, 0, 1 }, + "local position")) { + return 1; + } + if (!check_vector (B, Transform_GetWorldPosition, (vec4f_t) { 0, 1, 1, 1 }, + "world position")) { + return 1; + } + if (!check_vector (B, Transform_Right, (vec4f_t) { 0, 0, 1, 0 }, + "right")) { + return 1; + } + if (!check_vector (B, Transform_Forward, (vec4f_t) {-1, 0, 0, 0 }, + "forward")) { + return 1; + } + if (!check_vector (B, Transform_Up, (vec4f_t) { 0,-1, 0, 0 }, + "up")) { + return 1; + } + if (!check_vector (B1, Transform_GetLocalPosition, (vec4f_t) { 0, 1, 0, 1 }, + "local position")) { + return 1; + } + if (!check_vector (B1, Transform_GetWorldPosition, (vec4f_t) {-1, 1, 1, 1 }, + "world position")) { + return 1; + } + if (!check_vector (B1, Transform_Right, (vec4f_t) { 1, 0, 0, 0 }, + "right")) { + return 1; + } + if (!check_vector (B1, Transform_Forward, (vec4f_t) { 0, 1, 0, 0 }, + "forward")) { + return 1; + } + if (!check_vector (B1, Transform_Up, (vec4f_t) { 0, 0, 1, 0 }, + "up")) { + return 1; + } + + return 0; +} + +int +main (void) +{ + if (test_single_transform ()) { return 1; } + if (test_parent_child_init ()) { return 1; } + if (test_parent_child_setparent ()) { return 1; } + if (test_build_hierarchy ()) { return 1; } + if (test_build_hierarchy2 ()) { return 1; } + if (test_frames ()) { return 1; } + + return 0; +} diff --git a/libs/entity/transform.c b/libs/entity/transform.c new file mode 100644 index 000000000..18382e56c --- /dev/null +++ b/libs/entity/transform.c @@ -0,0 +1,317 @@ +/* + transform.c + + General transform handling + + Copyright (C) 2021 Bill Currke + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/entity.h" +#include "QF/render.h" + +transform_t * +Transform_New (transform_t *parent) +{ + transform_t *transform = malloc (sizeof (transform_t)); + + if (parent) { + transform->hierarchy = parent->hierarchy; + transform->index = Hierarchy_InsertHierarchy (parent->hierarchy, 0, + parent->index, 0); + } else { + transform->hierarchy = Hierarchy_New (16, 1);//FIXME should be config + transform->index = 0; + } + transform->hierarchy->transform.a[transform->index] = transform; + Hierarchy_UpdateMatrices (transform->hierarchy); + return transform; +} + +void +Transform_Delete (transform_t *transform) +{ + if (transform->index != 0) { + // The transform is not the root, so pull it out of its current + // hierarchy so deleting it is easier + Transform_SetParent (transform, 0); + } + Hierarchy_Delete (transform->hierarchy); +} + +transform_t * +Transform_NewNamed (transform_t *parent, const char *name) +{ + transform_t *transform = Transform_New (parent); + Transform_SetName (transform, name); + return transform; +} + +uint32_t +Transform_ChildCount (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->childCount.a[transform->index]; +} + +transform_t * +Transform_GetChild (const transform_t *transform, uint32_t childIndex) +{ + hierarchy_t *h = transform->hierarchy; + if (childIndex >= h->childCount.a[transform->index]) { + return 0; + } + return h->transform.a[h->childIndex.a[transform->index] + childIndex]; +} + +void +Transform_SetParent (transform_t *transform, transform_t *parent) +{ + if (parent) { + hierarchy_t *hierarchy = transform->hierarchy; + uint32_t index = transform->index; + Hierarchy_InsertHierarchy (parent->hierarchy, hierarchy, + parent->index, index); + Hierarchy_RemoveHierarchy (hierarchy, index); + if (!hierarchy->name.size) { + Hierarchy_Delete (hierarchy); + } + } else { + // null parent -> make transform root + if (!transform->index) { + // already root + return; + } + hierarchy_t *hierarchy = transform->hierarchy; + uint32_t index = transform->index; + + hierarchy_t *new_hierarchy = Hierarchy_New (16, 0); + Hierarchy_InsertHierarchy (new_hierarchy, hierarchy, null_transform, + index); + Hierarchy_RemoveHierarchy (hierarchy, index); + } +} + +transform_t * +Transform_GetParent (const transform_t *transform) +{ + if (transform->index == 0) { + return 0; + } + hierarchy_t *h = transform->hierarchy; + return h->transform.a[h->parentIndex.a[transform->index]]; +} + +void +Transform_SetName (transform_t *transform, const char *name) +{ + hierarchy_t *h = transform->hierarchy; + //FIXME create a string pool (similar to qfcc's, or even move that to util) + if (h->name.a[transform->index]) { + free (h->name.a[transform->index]); + } + h->name.a[transform->index] = strdup (name); +} + +const char * +Transform_GetName (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->name.a[transform->index]; +} + +void +Transform_SetTag (transform_t *transform, uint32_t tag) +{ + hierarchy_t *h = transform->hierarchy; + h->tag.a[transform->index] = tag; +} + +uint32_t +Transform_GetTag (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->tag.a[transform->index]; +} + +void +Transform_GetLocalMatrix (const transform_t *transform, mat4f_t mat) +{ + hierarchy_t *h = transform->hierarchy; + memcpy (mat, h->localMatrix.a[transform->index], sizeof (mat4f_t)); +} + +void +Transform_GetLocalInverse (const transform_t *transform, mat4f_t mat) +{ + hierarchy_t *h = transform->hierarchy; + memcpy (mat, h->localInverse.a[transform->index], sizeof (mat4f_t)); +} + +void +Transform_GetWorldMatrix (const transform_t *transform, mat4f_t mat) +{ + hierarchy_t *h = transform->hierarchy; + memcpy (mat, h->worldMatrix.a[transform->index], sizeof (mat4f_t)); +} + +void +Transform_GetWorldInverse (const transform_t *transform, mat4f_t mat) +{ + hierarchy_t *h = transform->hierarchy; + memcpy (mat, h->worldInverse.a[transform->index], sizeof (mat4f_t)); +} + +vec4f_t +Transform_GetLocalPosition (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->localMatrix.a[transform->index][3]; +} + +void +Transform_SetLocalPosition (transform_t *transform, vec4f_t position) +{ + hierarchy_t *h = transform->hierarchy; + h->localMatrix.a[transform->index][3] = position; + h->modified.a[transform->index] = 1; + Hierarchy_UpdateMatrices (h); +} + +vec4f_t +Transform_GetLocalRotation (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->localRotation.a[transform->index]; +} + +void +Transform_SetLocalRotation (transform_t *transform, vec4f_t rotation) +{ + hierarchy_t *h = transform->hierarchy; + vec4f_t scale = h->localScale.a[transform->index]; + + mat4f_t mat; + mat4fquat (mat, rotation); + + h->localMatrix.a[transform->index][0] = mat[0] * scale[0]; + h->localMatrix.a[transform->index][1] = mat[1] * scale[1]; + h->localMatrix.a[transform->index][2] = mat[2] * scale[2]; + h->modified.a[transform->index] = 1; + Hierarchy_UpdateMatrices (h); +} + +vec4f_t +Transform_GetLocalScale (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->localScale.a[transform->index]; +} + +void +Transform_SetLocalScale (transform_t *transform, vec4f_t scale) +{ + hierarchy_t *h = transform->hierarchy; + vec4f_t rotation = h->localRotation.a[transform->index]; + + mat4f_t mat; + mat4fquat (mat, rotation); + + h->localMatrix.a[transform->index][0] = mat[0] * scale[0]; + h->localMatrix.a[transform->index][1] = mat[1] * scale[1]; + h->localMatrix.a[transform->index][2] = mat[2] * scale[2]; + h->modified.a[transform->index] = 1; + Hierarchy_UpdateMatrices (h); +} + +vec4f_t +Transform_GetWorldPosition (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->worldMatrix.a[transform->index][3]; +} + +void +Transform_SetWorldPosition (transform_t *transform, vec4f_t position) +{ + if (transform->index) { + hierarchy_t *h = transform->hierarchy; + uint32_t parent = h->parentIndex.a[transform->index]; + position = mvmulf (h->worldInverse.a[parent], position); + } + Transform_SetLocalPosition (transform, position); +} + +vec4f_t +Transform_GetWorldRotation (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->worldRotation.a[transform->index]; +} + +void +Transform_SetWorldRotation (transform_t *transform, vec4f_t rotation) +{ + if (transform->index) { + hierarchy_t *h = transform->hierarchy; + uint32_t parent = h->parentIndex.a[transform->index]; + rotation = qmulf (qconjf (h->worldRotation.a[parent]), rotation); + } + Transform_SetLocalRotation (transform, rotation); +} + +vec4f_t +Transform_GetWorldScale (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->worldScale.a[transform->index]; +} + +vec4f_t +Transform_Forward (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->worldMatrix.a[transform->index][1]; +} + +vec4f_t +Transform_Right (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->worldMatrix.a[transform->index][0]; +} + +vec4f_t +Transform_Up (const transform_t *transform) +{ + hierarchy_t *h = transform->hierarchy; + return h->worldMatrix.a[transform->index][2]; +} From 09e1a63470f2bd38f37895003d7fde1c96fde130 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Mar 2021 23:50:32 +0900 Subject: [PATCH 385/435] [util] Add a simd mat4 transpose function --- include/QF/simd/mat4f.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/QF/simd/mat4f.h b/include/QF/simd/mat4f.h index 24773da87..719e4c561 100644 --- a/include/QF/simd/mat4f.h +++ b/include/QF/simd/mat4f.h @@ -38,6 +38,7 @@ GNU89INLINE inline void mmulf (mat4f_t c, const mat4f_t a, const mat4f_t b); GNU89INLINE inline vec4f_t mvmulf (const mat4f_t m, vec4f_t v) __attribute__((const)); GNU89INLINE inline vec4f_t m3vmulf (const mat4f_t m, vec4f_t v) __attribute__((const)); GNU89INLINE inline void mat4fidentity (mat4f_t m); +GNU89INLINE inline void mat4ftranspose (mat4f_t t, const mat4f_t m); GNU89INLINE inline void mat4fquat (mat4f_t m, vec4f_t q); #ifndef IMPLEMENT_MAT4F_Funcs @@ -121,6 +122,24 @@ mat4fidentity (mat4f_t m) m[3] = (vec4f_t) { 0, 0, 0, 1 }; } +#ifndef IMPLEMENT_MAT4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +void +mat4ftranspose (mat4f_t t, const mat4f_t m) +{ + vec4f_t a = m[0]; + vec4f_t b = m[1]; + vec4f_t c = m[2]; + vec4f_t d = m[3]; + t[0] = (vec4f_t) { a[0], b[0], c[0], d[0] }; + t[1] = (vec4f_t) { a[1], b[1], c[1], d[1] }; + t[2] = (vec4f_t) { a[2], b[2], c[2], d[2] }; + t[3] = (vec4f_t) { a[3], b[3], c[3], d[3] }; +} + #ifndef IMPLEMENT_MAT4F_Funcs GNU89INLINE inline #else From fbc1bd9f6ef834a1ccf7e6bdd33c551277c39794 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 9 Mar 2021 23:52:40 +0900 Subject: [PATCH 386/435] [renderer] Clean up entity_t to a certain extent This is the first step towards component-based entities. There's still some transform-related stuff in the struct that needs to be moved, but it's all entirely client related (rather than renderer) and will probably go into a "client" component. Also, the current components are directly included structs rather than references as I didn't want to deal with the object management at this stage. As part of the process (because transforms use simd) this also starts the process of moving QF to using simd for vectors and matrices. There's now a mess of simd and sisd code mixed together, but it works surprisingly well together. --- include/QF/entity.h | 12 +- include/QF/render.h | 71 ++++---- include/r_local.h | 6 +- libs/entity/transform.c | 21 ++- libs/video/renderer/gl/gl_dyn_part.c | 2 +- libs/video/renderer/gl/gl_lightmap.c | 4 +- libs/video/renderer/gl/gl_mod_alias.c | 76 +++++---- libs/video/renderer/gl/gl_mod_iqm.c | 6 +- libs/video/renderer/gl/gl_mod_sprite.c | 109 ++++++------ libs/video/renderer/gl/gl_rmain.c | 23 ++- libs/video/renderer/gl/gl_rmisc.c | 5 +- libs/video/renderer/gl/gl_rsurf.c | 29 ++-- libs/video/renderer/glsl/glsl_alias.c | 55 +++--- libs/video/renderer/glsl/glsl_bsp.c | 48 +++--- libs/video/renderer/glsl/glsl_iqm.c | 27 +-- libs/video/renderer/glsl/glsl_main.c | 88 +++++----- libs/video/renderer/glsl/glsl_particles.c | 16 +- libs/video/renderer/glsl/glsl_sprite.c | 37 ++-- libs/video/renderer/r_alias.c | 6 +- libs/video/renderer/r_bsp.c | 6 +- libs/video/renderer/r_efrag.c | 26 +-- libs/video/renderer/r_ent.c | 44 +++-- libs/video/renderer/r_iqm.c | 4 +- libs/video/renderer/r_light.c | 2 +- libs/video/renderer/sw/sw_ralias.c | 52 +++--- libs/video/renderer/sw/sw_rbsp.c | 16 +- libs/video/renderer/sw/sw_rdraw.c | 4 +- libs/video/renderer/sw/sw_riqm.c | 31 ++-- libs/video/renderer/sw/sw_rmain.c | 39 +++-- libs/video/renderer/sw/sw_rmisc.c | 2 +- libs/video/renderer/sw/sw_rpart.c | 2 +- libs/video/renderer/sw/sw_rsprite.c | 15 +- libs/video/renderer/sw/sw_rsurf.c | 2 +- libs/video/renderer/sw32/sw32_ralias.c | 47 ++--- libs/video/renderer/sw32/sw32_rbsp.c | 18 +- libs/video/renderer/sw32/sw32_rdraw.c | 4 +- libs/video/renderer/sw32/sw32_riqm.c | 27 +-- libs/video/renderer/sw32/sw32_rmain.c | 39 +++-- libs/video/renderer/sw32/sw32_rmisc.c | 2 +- libs/video/renderer/sw32/sw32_rpart.c | 2 +- libs/video/renderer/sw32/sw32_rsprite.c | 15 +- libs/video/renderer/sw32/sw32_rsurf.c | 2 +- libs/video/renderer/vulkan/vulkan_alias.c | 27 +-- libs/video/renderer/vulkan/vulkan_bsp.c | 34 ++-- libs/video/renderer/vulkan/vulkan_main.c | 8 +- nq/source/Makemodule.am | 1 + nq/source/cl_ents.c | 106 +++++++----- nq/source/cl_main.c | 5 +- nq/source/cl_parse.c | 22 +-- nq/source/cl_tent.c | 31 ++-- nq/source/cl_view.c | 8 +- qw/source/Makemodule.am | 1 + qw/source/cl_demo.c | 10 +- qw/source/cl_entparse.c | 4 +- qw/source/cl_ents.c | 198 ++++++++++++---------- qw/source/cl_parse.c | 6 +- qw/source/cl_tent.c | 44 +++-- qw/source/cl_view.c | 15 +- ruamoko/qwaq/Makemodule.am | 1 + 59 files changed, 881 insertions(+), 682 deletions(-) diff --git a/include/QF/entity.h b/include/QF/entity.h index 9bf676190..032db67a2 100644 --- a/include/QF/entity.h +++ b/include/QF/entity.h @@ -92,16 +92,18 @@ void Transform_GetLocalInverse (const transform_t *transform, mat4f_t mat); void Transform_GetWorldMatrix (const transform_t *transform, mat4f_t mat); void Transform_GetWorldInverse (const transform_t *transform, mat4f_t mat); vec4f_t Transform_GetLocalPosition (const transform_t *transform) __attribute__((pure)); -void Transform_SetLocalPosition (transform_t *transform_t, vec4f_t position); +void Transform_SetLocalPosition (transform_t *transform, vec4f_t position); vec4f_t Transform_GetLocalRotation (const transform_t *transform) __attribute__((pure)); -void Transform_SetLocalRotation (transform_t *transform_t, vec4f_t rotation); +void Transform_SetLocalRotation (transform_t *transform, vec4f_t rotation); vec4f_t Transform_GetLocalScale (const transform_t *transform) __attribute__((pure)); -void Transform_SetLocalScale (transform_t *transform_t, vec4f_t scale); +void Transform_SetLocalScale (transform_t *transform, vec4f_t scale); vec4f_t Transform_GetWorldPosition (const transform_t *transform) __attribute__((pure)); -void Transform_SetWorldPosition (transform_t *transform_t, vec4f_t position); +void Transform_SetWorldPosition (transform_t *transform, vec4f_t position); vec4f_t Transform_GetWorldRotation (const transform_t *transform) __attribute__((pure)); -void Transform_SetWorldRotation (transform_t *transform_t, vec4f_t rotation); +void Transform_SetWorldRotation (transform_t *transform, vec4f_t rotation); vec4f_t Transform_GetWorldScale (const transform_t *transform) __attribute__((pure)); +void Transform_SetLocalTransform (transform_t *transform, vec4f_t scale, + vec4f_t rotation, vec4f_t position); // NOTE: these use X: right, Y: forward, Z:up // aslo, not guaranteed to be normalized or even orthogonal vec4f_t Transform_Forward (const transform_t *transform) __attribute__((pure)); diff --git a/include/QF/render.h b/include/QF/render.h index 607b8b800..d6a871865 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -90,47 +90,56 @@ typedef struct //=============== +typedef struct animation_s { + int frame; + float syncbase; // randomize time base for local animations + float frame_start_time; + float frame_interval; + int pose1; + int pose2; + float blend; + int nolerp; // don't lerp this frame (pose data invalid) +} animation_t; + +typedef struct visibility_s { + struct entity_s *entity; // owning entity + struct efrag_s *efrag; // linked list of efrags + struct mnode_s *topnode; // bmodels, first world node that + // splits bmodel, or NULL if not split + // applies to other models, too + int visframe; // last frame this entity was + // found in an active leaf + int trivial_accept; // view clipping (frustum and depth) +} visibility_t; + +typedef struct renderer_s { + struct model_s *model; // NULL = no model + struct skin_s *skin; + float colormod[4]; // color tint and alpha for model + int skinnum; // for Alias models + int fullbright; + float min_light; + mat4_t full_transform; +} renderer_t; + typedef struct entity_s { struct entity_s *next; struct entity_s *unext; //FIXME this shouldn't be here. for qw demos + struct transform_s *transform; + animation_t animation; + visibility_t visibility; + renderer_t renderer; + int active; + //XXX FIXME XXX should not be here + float scale; vec3_t origin; vec3_t old_origin; vec3_t angles; - vec_t transform[4 * 4]; - vec_t full_transform[4 * 4]; - struct model_s *model; // NULL = no model - int frame; - int skinnum; // for Alias models - struct skin_s *skin; - - float syncbase; // for client-side animations - - struct efrag_s *efrag; // linked list of efrags - int visframe; // last frame this entity was - // found in an active leaf - float colormod[4]; // color tint and alpha for model - float scale; // size scaler of the model - - int fullbright; - float min_light; - - // FIXME: could turn these into a union - int trivial_accept; - struct mnode_s *topnode; // for bmodels, first world node that - // splits bmodel, or NULL if not split - - // Animation interpolation - float frame_start_time; - float frame_interval; - int pose1; - int pose2; - struct model_s *pose_model; // no lerp if not the same as model } entity_t; // !!! if this is changed, it must be changed in asm_draw.h too !!! -typedef struct -{ +typedef struct { vrect_t vrect; // subwindow in video for refresh // FIXME: not need vrect next field here? vrect_t aliasvrect; // scaled Alias version diff --git a/include/r_local.h b/include/r_local.h index 9e56b7343..37d5308c1 100644 --- a/include/r_local.h +++ b/include/r_local.h @@ -33,6 +33,8 @@ #include "QF/model.h" #include "QF/render.h" #include "QF/vid.h" +#include "QF/simd/mat4f.h" +#include "QF/simd/vec4f.h" #include "r_shared.h" #define ALIAS_BASE_SIZE_RATIO (1.0 / 11.0) @@ -136,8 +138,8 @@ extern qboolean r_cache_thrash; // set if thrashing the surface cache extern qboolean insubmodel; extern vec3_t r_worldmodelorg; -extern mat4_t glsl_projection; -extern mat4_t glsl_view; +extern mat4f_t glsl_projection; +extern mat4f_t glsl_view; void R_SetFrustum (void); diff --git a/libs/entity/transform.c b/libs/entity/transform.c index 18382e56c..0e274f83a 100644 --- a/libs/entity/transform.c +++ b/libs/entity/transform.c @@ -295,18 +295,35 @@ Transform_GetWorldScale (const transform_t *transform) return h->worldScale.a[transform->index]; } +void +Transform_SetLocalTransform (transform_t *transform, vec4f_t scale, + vec4f_t rotation, vec4f_t position) +{ + hierarchy_t *h = transform->hierarchy; + mat4f_t mat; + mat4fquat (mat, rotation); + + position[3] = 1; + h->localMatrix.a[transform->index][0] = mat[0] * scale[0]; + h->localMatrix.a[transform->index][1] = mat[1] * scale[1]; + h->localMatrix.a[transform->index][2] = mat[2] * scale[2]; + h->localMatrix.a[transform->index][3] = position; + h->modified.a[transform->index] = 1; + Hierarchy_UpdateMatrices (h); +} + vec4f_t Transform_Forward (const transform_t *transform) { hierarchy_t *h = transform->hierarchy; - return h->worldMatrix.a[transform->index][1]; + return h->worldMatrix.a[transform->index][0]; } vec4f_t Transform_Right (const transform_t *transform) { hierarchy_t *h = transform->hierarchy; - return h->worldMatrix.a[transform->index][0]; + return -h->worldMatrix.a[transform->index][1]; } vec4f_t diff --git a/libs/video/renderer/gl/gl_dyn_part.c b/libs/video/renderer/gl/gl_dyn_part.c index 5f510b26c..5aa093813 100644 --- a/libs/video/renderer/gl/gl_dyn_part.c +++ b/libs/video/renderer/gl/gl_dyn_part.c @@ -205,7 +205,7 @@ gl_R_ReadPointFile_f (void) vec3_t org; QFile *f; - mapname = strdup (r_worldentity.model->path); + mapname = strdup (r_worldentity.renderer.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); diff --git a/libs/video/renderer/gl/gl_lightmap.c b/libs/video/renderer/gl/gl_lightmap.c index c6270f5d4..d46c35014 100644 --- a/libs/video/renderer/gl/gl_lightmap.c +++ b/libs/video/renderer/gl/gl_lightmap.c @@ -582,7 +582,7 @@ gl_overbright_f (cvar_t *var) return; for (ent = r_ent_queue; ent; ent = ent->next) { - m = ent->model; + m = ent->renderer.model; if (m->type != mod_brush) continue; @@ -605,7 +605,7 @@ gl_overbright_f (cvar_t *var) } } - brush = &r_worldentity.model->brush; + brush = &r_worldentity.renderer.model->brush; for (i = 0, fa = brush->surfaces; i < brush->numsurfaces; i++, fa++) { if (fa->flags & (SURF_DRAWTURB | SURF_DRAWSKY)) diff --git a/libs/video/renderer/gl/gl_mod_alias.c b/libs/video/renderer/gl/gl_mod_alias.c index d47a1504f..4b90ba54a 100644 --- a/libs/video/renderer/gl/gl_mod_alias.c +++ b/libs/video/renderer/gl/gl_mod_alias.c @@ -43,6 +43,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/locs.h" #include "QF/mathlib.h" #include "QF/qargs.h" @@ -299,14 +300,14 @@ GL_GetAliasFrameVerts16 (aliashdr_t *paliashdr, entity_t *e) if (blend == 0.0) { - verts = verts + e->pose1 * count; + verts = verts + e->animation.pose1 * count; } else if (blend == 1.0) { - verts = verts + e->pose2 * count; + verts = verts + e->animation.pose2 * count; } else { trivertx16_t *verts1, *verts2; - verts1 = verts + e->pose1 * count; - verts2 = verts + e->pose2 * count; + verts1 = verts + e->animation.pose1 * count; + verts2 = verts + e->animation.pose2 * count; for (i = 0, vo_v = vo->verts; i < count; i++, vo_v++, verts1++, verts2++) { @@ -362,14 +363,14 @@ GL_GetAliasFrameVerts (aliashdr_t *paliashdr, entity_t *e) blend = 1.0; if (blend == 0.0) { - verts = verts + e->pose1 * count; + verts = verts + e->animation.pose1 * count; } else if (blend == 1.0) { - verts = verts + e->pose2 * count; + verts = verts + e->animation.pose2 * count; } else { trivertx_t *verts1, *verts2; - verts1 = verts + e->pose1 * count; - verts2 = verts + e->pose2 * count; + verts1 = verts + e->animation.pose1 * count; + verts2 = verts + e->animation.pose2 * count; for (i = 0, vo_v = vo->verts; i < count; i++, vo_v++, verts1++, verts2++) { @@ -415,7 +416,7 @@ gl_R_DrawAliasModel (entity_t *e) vec3_t dist, scale; vert_order_t *vo; - model = e->model; + model = e->renderer.model; radius = model->radius; if (e->scale != 1.0) @@ -425,18 +426,18 @@ gl_R_DrawAliasModel (entity_t *e) VectorSubtract (r_origin, e->origin, modelorg); - gl_modelalpha = e->colormod[3]; + gl_modelalpha = e->renderer.colormod[3]; - is_fullbright = (model->fullbright || e->fullbright); - minlight = max (model->min_light, e->min_light); + is_fullbright = (model->fullbright || e->renderer.fullbright); + minlight = max (model->min_light, e->renderer.min_light); - qfglColor4fv (e->colormod); + qfglColor4fv (e->renderer.colormod); if (!is_fullbright) { float lightadj; // get lighting information - R_LightPoint (&r_worldentity.model->brush, e->origin); + R_LightPoint (&r_worldentity.renderer.model->brush, e->origin); lightadj = (ambientcolor[0] + ambientcolor[1] + ambientcolor[2]) / 765.0; @@ -530,24 +531,25 @@ gl_R_DrawAliasModel (entity_t *e) VectorScale (emission, 1.5 / d, emission); } - emission[0] *= e->colormod[0]; - emission[1] *= e->colormod[1]; - emission[2] *= e->colormod[2]; - emission[3] *= e->colormod[3]; + emission[0] *= e->renderer.colormod[0]; + emission[1] *= e->renderer.colormod[1]; + emission[2] *= e->renderer.colormod[2]; + emission[3] *= e->renderer.colormod[3]; qfglColor4fv (emission); } } // locate the proper data - if (!(paliashdr = e->model->aliashdr)) - paliashdr = Cache_Get (&e->model->cache); + if (!(paliashdr = e->renderer.model->aliashdr)) { + paliashdr = Cache_Get (&e->renderer.model->cache); + } gl_c_alias_polys += paliashdr->mdl.numtris; // if the model has a colorised/external skin, use it, otherwise use // the skin embedded in the model data - if (e->skin && e->skin->texnum && !gl_nocolors->int_val) { - skin_t *skin = e->skin; + if (e->renderer.skin && e->renderer.skin->texnum && !gl_nocolors->int_val) { + skin_t *skin = e->renderer.skin; texture = skin->texnum; if (gl_fb_models->int_val) { @@ -556,10 +558,11 @@ gl_R_DrawAliasModel (entity_t *e) } else { maliasskindesc_t *skindesc; - skindesc = R_AliasGetSkindesc (e->skinnum, paliashdr); + skindesc = R_AliasGetSkindesc (e->renderer.skinnum, paliashdr); texture = skindesc->texnum; - if (gl_fb_models->int_val && !is_fullbright) + if (gl_fb_models->int_val && !is_fullbright) { fb_texture = skindesc->fb_texnum; + } } if (paliashdr->mdl.ident == HEADER_MDL16) { @@ -640,7 +643,7 @@ gl_R_DrawAliasModel (entity_t *e) qfglDisable (GL_NORMALIZE); } - qfglColor4fv (e->colormod); + qfglColor4fv (e->renderer.colormod); qfglBindTexture (GL_TEXTURE_2D, fb_texture); GL_DrawAliasFrameTri (vo); @@ -660,7 +663,7 @@ gl_R_DrawAliasModel (entity_t *e) qfglDisable (GL_NORMALIZE); } - qfglColor4fv (e->colormod); + qfglColor4fv (e->renderer.colormod); qfglBindTexture (GL_TEXTURE_2D, fb_texture); GL_DrawAliasFrame (vo); @@ -678,7 +681,7 @@ gl_R_DrawAliasModel (entity_t *e) // torches, grenades, and lightning bolts do not have shadows if (r_shadows->int_val && model->shadow_alpha) { - mat4_t shadow_mat; + mat4f_t shadow_mat; qfglPushMatrix (); gl_R_RotateForEntity (e); @@ -690,19 +693,19 @@ gl_R_DrawAliasModel (entity_t *e) qfglDepthMask (GL_FALSE); if (gl_modelalpha < 1.0) { - VectorBlend (e->colormod, dark, 0.5, color); + VectorBlend (e->renderer.colormod, dark, 0.5, color); color[3] = gl_modelalpha * (model->shadow_alpha / 255.0); qfglColor4fv (color); } else { color_black[3] = model->shadow_alpha; qfglColor4ubv (color_black); } - shadevector[0] = 1; - shadevector[1] = 0; - shadevector[2] = 1; - VectorNormalize (shadevector); - Mat4Transpose (e->transform, shadow_mat); - Mat4as3MultVec (shadow_mat, shadevector, shadevector); + //FIXME fully vectorize + vec4f_t vec = { 707106781, 0, 707106781, 0 }; + Transform_GetWorldMatrix (e->transform, shadow_mat); + mat4ftranspose (shadow_mat, shadow_mat); + vec = mvmulf (shadow_mat, vec); + VectorCopy (vec, shadevector); if (vo->tex_coord) GL_DrawAliasShadowTri (paliashdr, vo); else @@ -722,6 +725,7 @@ gl_R_DrawAliasModel (entity_t *e) qfglDisable (GL_LIGHT0 + used_lights); } - if (!e->model->aliashdr) - Cache_Release (&e->model->cache); + if (!e->renderer.model->aliashdr) { + Cache_Release (&e->renderer.model->cache); + } } diff --git a/libs/video/renderer/gl/gl_mod_iqm.c b/libs/video/renderer/gl/gl_mod_iqm.c index 4c50795b7..601a76fbf 100644 --- a/libs/video/renderer/gl/gl_mod_iqm.c +++ b/libs/video/renderer/gl/gl_mod_iqm.c @@ -90,7 +90,7 @@ gl_draw_iqm_frame (iqm_t *iqm, gliqm_t *gl, iqmframe_t *frame, iqmmesh *mesh) void gl_R_DrawIQMModel (entity_t *ent) { - model_t *model = ent->model; + model_t *model = ent->renderer.model; iqm_t *iqm = (iqm_t *) model->aliashdr; gliqm_t *gl = (gliqm_t *) iqm->extra_data; float blend; @@ -98,8 +98,8 @@ gl_R_DrawIQMModel (entity_t *ent) int i; blend = R_IQMGetLerpedFrames (ent, iqm); - frame = R_IQMBlendPalette (iqm, ent->pose1, ent->pose2, blend, 0, - gl->blend_palette, gl->palette_size); + frame = R_IQMBlendPalette (iqm, ent->animation.pose1, ent->animation.pose2, + blend, 0, gl->blend_palette, gl->palette_size); qfglPushMatrix (); gl_R_RotateForEntity (ent); diff --git a/libs/video/renderer/gl/gl_mod_sprite.c b/libs/video/renderer/gl/gl_mod_sprite.c index c5b484ed7..b6ce25f22 100644 --- a/libs/video/renderer/gl/gl_mod_sprite.c +++ b/libs/video/renderer/gl/gl_mod_sprite.c @@ -41,6 +41,7 @@ #include "QF/GL/defines.h" #include "QF/GL/funcs.h" +#include "QF/entity.h" #include "QF/model.h" #include "QF/render.h" #include "QF/sys.h" @@ -66,8 +67,8 @@ R_GetSpriteFrame (entity_t *currententity) mspriteframe_t *pspriteframe; mspritegroup_t *pspritegroup; - psprite = currententity->model->cache.data; - frame = currententity->frame; + psprite = currententity->renderer.model->cache.data; + frame = currententity->animation.frame; if ((frame >= psprite->numframes) || (frame < 0)) { Sys_MaskPrintf (SYS_DEV, "R_DrawSprite: no such frame %d\n", frame); @@ -82,7 +83,7 @@ R_GetSpriteFrame (entity_t *currententity) numframes = pspritegroup->numframes; fullinterval = pintervals[numframes - 1]; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; // when loading in Mod_LoadSpriteGroup, we guaranteed all interval // values are positive, so we don't have to worry about division by 0 @@ -103,35 +104,32 @@ static void R_DrawSpriteModel_f (entity_t *e) { float modelalpha, color[4]; - float *up, *right; + vec4f_t up = {}, right = {}; + vec4f_t origin, point1, point2; msprite_t *psprite; mspriteframe_t *frame; - vec3_t point, point1, point2, v_up; // don't bother culling, it's just a single polygon without a surface cache frame = R_GetSpriteFrame (e); - psprite = e->model->cache.data; + psprite = e->renderer.model->cache.data; if (psprite->type == SPR_ORIENTED) { // bullet marks on walls - up = e->transform + 2 * 4; - right = e->transform + 1 * 4; + up = Transform_Up (e->transform); + right = Transform_Right (e->transform); } else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) { - v_up[0] = 0; - v_up[1] = 0; - v_up[2] = 1; - up = v_up; - right = vright; + up = (vec4f_t) { 0, 0, 1, 0 }; + VectorCopy (vright, right); } else { // normal sprite - up = vup; - right = vright; + VectorCopy (vup, up); + VectorCopy (vright, right); } if (e->scale != 1.0) { - VectorScale (up, e->scale, up); - VectorScale (right, e->scale, right); + up *= e->scale; + right *= e->scale; } - VectorCopy (e->colormod, color); - modelalpha = color[3] = e->colormod[3]; + VectorCopy (e->renderer.colormod, color); + modelalpha = color[3] = e->renderer.colormod[3]; if (modelalpha < 1.0) qfglDepthMask (GL_FALSE); @@ -141,23 +139,24 @@ R_DrawSpriteModel_f (entity_t *e) qfglColor4fv (color); + origin = Transform_GetWorldPosition (e->transform); + point1 = origin + frame->down * up + frame->left * right; + point2 = origin + frame->up * up + frame->left * right; + qfglTexCoord2f (0, 1); - VectorMultAdd (e->origin, frame->down, up, point1); - VectorMultAdd (point1, frame->left, right, point); - qfglVertex3fv (point); + qfglVertex3fv (&point1[0]); qfglTexCoord2f (0, 0); - VectorMultAdd (e->origin, frame->up, up, point2); - VectorMultAdd (point2, frame->left, right, point); - qfglVertex3fv (point); + qfglVertex3fv (&point2[0]); + + point2 += frame->right * right; + point1 += frame->right * right; qfglTexCoord2f (1, 0); - VectorMultAdd (point2, frame->right, right, point); - qfglVertex3fv (point); + qfglVertex3fv (&point2[0]); qfglTexCoord2f (1, 1); - VectorMultAdd (point1, frame->right, right, point); - qfglVertex3fv (point); + qfglVertex3fv (&point1[0]); qfglEnd (); @@ -169,60 +168,60 @@ static void R_DrawSpriteModel_VA_f (entity_t *e) { unsigned char modelalpha, color[4]; - float *up, *right; + vec4f_t up = {}, right = {}; + vec4f_t origin, point1, point2; int i; // unsigned int vacount; msprite_t *psprite; mspriteframe_t *frame; - vec3_t point1, point2, v_up; varray_t2f_c4ub_v3f_t *VA; VA = gl_spriteVertexArray; // FIXME: Despair // don't bother culling, it's just a single polygon without a surface cache frame = R_GetSpriteFrame (e); - psprite = e->model->cache.data; + psprite = e->renderer.model->cache.data; qfglBindTexture (GL_TEXTURE_2D, frame->gl_texturenum); // FIXME: DESPAIR if (psprite->type == SPR_ORIENTED) { // bullet marks on walls - up = e->transform + 2 * 4; - right = e->transform + 1 * 4; + up = Transform_Up (e->transform); + right = Transform_Right (e->transform); } else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) { - v_up[0] = 0; - v_up[1] = 0; - v_up[2] = 1; - up = v_up; - right = vright; + up = (vec4f_t) { 0, 0, 1, 0 }; + VectorCopy (vright, right); } else { // normal sprite - up = vup; - right = vright; + VectorCopy (vup, up); + VectorCopy (vright, right); } if (e->scale != 1.0) { - VectorScale (up, e->scale, up); - VectorScale (right, e->scale, right); + up *= e->scale; + right *= e->scale; } - for (i = 0; i < 4; i++) - color[i] = e->colormod[i] * 255; + for (i = 0; i < 4; i++) { + color[i] = e->renderer.colormod[i] * 255; + } memcpy (VA[0].color, color, 4); + memcpy (VA[1].color, color, 4); + memcpy (VA[2].color, color, 4); + memcpy (VA[3].color, color, 4); modelalpha = color[3]; if (modelalpha < 255) qfglDepthMask (GL_FALSE); - VectorMultAdd (e->origin, frame->down, up, point1); - VectorMultAdd (point1, frame->left, right, VA[0].vertex); + origin = Transform_GetWorldPosition (e->transform); + point1 = origin + frame->down * up + frame->left * right; + VectorCopy (point1, VA[0].vertex); - memcpy (VA[1].color, color, 4); - VectorMultAdd (e->origin, frame->up, up, point2); - VectorMultAdd (point2, frame->left, right, VA[1].vertex); + point2 = origin + frame->up * up + frame->left * right; + VectorCopy (point2, VA[1].vertex); - memcpy (VA[2].color, color, 4); - VectorMultAdd (point2, frame->right, right, VA[2].vertex); - - memcpy (VA[3].color, color, 4); - VectorMultAdd (point1, frame->right, right, VA[3].vertex); + point2 += frame->right * right; + point1 += frame->right * right; + VectorCopy (point2, VA[2].vertex); + VectorCopy (point1, VA[3].vertex); // VA += 4; // vacount += 4; diff --git a/libs/video/renderer/gl/gl_rmain.c b/libs/video/renderer/gl/gl_rmain.c index 1f9b30696..23d7f7be4 100644 --- a/libs/video/renderer/gl/gl_rmain.c +++ b/libs/video/renderer/gl/gl_rmain.c @@ -44,6 +44,7 @@ #include "QF/cvar.h" #include "QF/draw.h" +#include "QF/entity.h" #include "QF/locs.h" #include "QF/mathlib.h" #include "QF/qargs.h" @@ -178,7 +179,9 @@ glrmain_init (void) void gl_R_RotateForEntity (entity_t *e) { - qfglMultMatrixf (e->transform); + mat4f_t mat; + Transform_GetWorldMatrix (e->transform, mat); + qfglMultMatrixf (&mat[0][0]); } /* @@ -217,7 +220,7 @@ R_DrawEntitiesOnList (void) } for (ent = r_ent_queue; ent; ent = ent->next) { - if (ent->model->type != mod_alias) + if (ent->renderer.model->type != mod_alias) continue; currententity = ent; @@ -249,7 +252,7 @@ R_DrawEntitiesOnList (void) } for (ent = r_ent_queue; ent; ent = ent->next) { - if (ent->model->type != mod_iqm) + if (ent->renderer.model->type != mod_iqm) continue; currententity = ent; @@ -262,7 +265,7 @@ R_DrawEntitiesOnList (void) if (gl_va_capable) qfglInterleavedArrays (GL_T2F_C4UB_V3F, 0, gl_spriteVertexArray); for (ent = r_ent_queue; ent; ent = ent->next) { - if (ent->model->type != mod_sprite) + if (ent->renderer.model->type != mod_sprite) continue; currententity = ent; @@ -279,7 +282,7 @@ R_DrawViewModel (void) || !r_drawviewmodel->int_val || gl_envmap || !r_drawentities->int_val - || !currententity->model) + || !currententity->renderer.model) return; // hack the depth range to prevent view model from poking into walls @@ -349,7 +352,7 @@ gl_R_SetupFrame (void) R_SetFrustum (); // current viewleaf - r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.model); + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.renderer.model); r_cache_thrash = false; @@ -559,10 +562,12 @@ R_Mirror (void) static void R_RenderView_ (void) { - if (r_norefresh->int_val) + if (r_norefresh->int_val) { return; - if (!r_worldentity.model) + } + if (!r_worldentity.renderer.model) { Sys_Error ("R_RenderView: NULL worldmodel"); + } gl_mirror = false; @@ -892,7 +897,7 @@ R_RenderViewFishEye (void) void gl_R_ClearState (void) { - r_worldentity.model = 0; + r_worldentity.renderer.model = 0; R_ClearEfrags (); R_ClearDlights (); gl_R_ClearParticles (); diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index 5c61fd70d..d9a1c6797 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -191,7 +191,7 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) d_lightstylevalue[i] = 264; // normal light value memset (&r_worldentity, 0, sizeof (r_worldentity)); - r_worldentity.model = worldmodel; + r_worldentity.renderer.model = worldmodel; brush = &worldmodel->brush; R_FreeAllEntities (); @@ -230,7 +230,8 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) continue; if (*models[i]->path == '*') continue; - if (models[i] != r_worldentity.model && models[i]->type == mod_brush) + if (models[i] != r_worldentity.renderer.model + && models[i]->type == mod_brush) register_textures (&models[i]->brush); } } diff --git a/libs/video/renderer/gl/gl_rsurf.c b/libs/video/renderer/gl/gl_rsurf.c index acd9f4ad3..b954fc066 100644 --- a/libs/video/renderer/gl/gl_rsurf.c +++ b/libs/video/renderer/gl/gl_rsurf.c @@ -45,6 +45,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" #include "QF/GL/defines.h" @@ -530,11 +531,14 @@ gl_R_DrawBrushModel (entity_t *e) qboolean rotated; vec3_t mins, maxs; mod_brush_t *brush; + mat4f_t worldMatrix; - model = e->model; + model = e->renderer.model; brush = &model->brush; - if (e->transform[0] != 1 || e->transform[5] != 1 || e->transform[10] != 1) { + Transform_GetWorldMatrix (e->transform, worldMatrix); + if (worldMatrix[0][0] != 1 || worldMatrix[1][1] != 1 + || worldMatrix[2][2] != 1) { rotated = true; radius = model->radius; #if 0 //QSG FIXME @@ -559,12 +563,11 @@ gl_R_DrawBrushModel (entity_t *e) VectorSubtract (r_refdef.vieworg, e->origin, modelorg); if (rotated) { - vec3_t temp; + vec4f_t temp = { modelorg[0], modelorg[1], modelorg[2], 0 }; - VectorCopy (modelorg, temp); - modelorg[0] = DotProduct (temp, e->transform + 0); - modelorg[1] = DotProduct (temp, e->transform + 4); - modelorg[2] = DotProduct (temp, e->transform + 8); + modelorg[0] = dotf (temp, worldMatrix[0])[0]; + modelorg[1] = dotf (temp, worldMatrix[1])[0]; + modelorg[2] = dotf (temp, worldMatrix[2])[0]; } // calculate dynamic lighting for bmodel if it's not an instanced model @@ -584,7 +587,7 @@ gl_R_DrawBrushModel (entity_t *e) qfglPushMatrix (); gl_R_RotateForEntity (e); - qfglGetFloatv (GL_MODELVIEW_MATRIX, e->full_transform); + qfglGetFloatv (GL_MODELVIEW_MATRIX, e->renderer.full_transform); qfglPopMatrix (); psurf = &brush->surfaces[brush->firstmodelsurface]; @@ -599,7 +602,8 @@ gl_R_DrawBrushModel (entity_t *e) // draw the polygon if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - chain_surface (brush, psurf, e->full_transform, e->colormod); + chain_surface (brush, psurf, e->renderer.full_transform, + e->renderer.colormod); } } } @@ -717,7 +721,7 @@ gl_R_DrawWorld (void) entity_t worldent; memset (&worldent, 0, sizeof (worldent)); - worldent.model = r_worldentity.model; + worldent.renderer.model = r_worldentity.renderer.model; VectorCopy (r_refdef.vieworg, modelorg); @@ -729,12 +733,13 @@ gl_R_DrawWorld (void) gl_R_DrawSky (); } - R_VisitWorldNodes (&r_worldentity.model->brush); + R_VisitWorldNodes (&r_worldentity.renderer.model->brush); if (r_drawentities->int_val) { entity_t *ent; for (ent = r_ent_queue; ent; ent = ent->next) { - if (ent->model->type != mod_brush) + if (ent->renderer.model->type != mod_brush) { continue; + } currententity = ent; gl_R_DrawBrushModel (currententity); diff --git a/libs/video/renderer/glsl/glsl_alias.c b/libs/video/renderer/glsl/glsl_alias.c index 3cbf4f89d..e0c29cfe4 100644 --- a/libs/video/renderer/glsl/glsl_alias.c +++ b/libs/video/renderer/glsl/glsl_alias.c @@ -43,6 +43,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/skin.h" #include "QF/sys.h" @@ -111,7 +112,7 @@ static struct { {"fog", 1}, }; -static mat4_t alias_vp; +static mat4f_t alias_vp; void glsl_R_InitAlias (void) @@ -159,8 +160,9 @@ calc_lighting (entity_t *ent, float *ambient, float *shadelight, int light; VectorSet ( -1, 0, 0, lightvec); //FIXME - light = R_LightPoint (&r_worldentity.model->brush, ent->origin); - *ambient = max (light, max (ent->model->min_light, ent->min_light) * 128); + light = R_LightPoint (&r_worldentity.renderer.model->brush, ent->origin); + *ambient = max (light, max (ent->renderer.model->min_light, + ent->renderer.min_light) * 128); *shadelight = *ambient; for (i = 0; i < r_maxdlights; i++) { @@ -228,50 +230,52 @@ glsl_R_DrawAlias (void) float skin_size[2]; float blend; entity_t *ent = currententity; - model_t *model = ent->model; + model_t *model = ent->renderer.model; aliashdr_t *hdr; vec_t norm_mat[9]; - mat4_t mvp_mat; int skin_tex; int colormap; aliasvrt_t *pose1 = 0; // VBO's are null based aliasvrt_t *pose2 = 0; // VBO's are null based + mat4f_t worldMatrix; if (!(hdr = model->aliashdr)) hdr = Cache_Get (&model->cache); calc_lighting (ent, &ambient, &shadelight, lightvec); + Transform_GetWorldMatrix (ent->transform, worldMatrix); // we need only the rotation for normals. - VectorCopy (ent->transform + 0, norm_mat + 0); - VectorCopy (ent->transform + 4, norm_mat + 3); - VectorCopy (ent->transform + 8, norm_mat + 6); + VectorCopy (worldMatrix[0], norm_mat + 0); + VectorCopy (worldMatrix[1], norm_mat + 3); + VectorCopy (worldMatrix[2], norm_mat + 6); // ent model scaling and offset - Mat4Zero (mvp_mat); - mvp_mat[0] = hdr->mdl.scale[0]; - mvp_mat[5] = hdr->mdl.scale[1]; - mvp_mat[10] = hdr->mdl.scale[2]; - mvp_mat[15] = 1; - VectorCopy (hdr->mdl.scale_origin, mvp_mat + 12); - Mat4Mult (ent->transform, mvp_mat, mvp_mat); - Mat4Mult (alias_vp, mvp_mat, mvp_mat); + mat4f_t mvp_mat = { + { hdr->mdl.scale[0], 0, 0, 0 }, + { 0, hdr->mdl.scale[1], 0, 0 }, + { 0, 0, hdr->mdl.scale[2], 0 }, + { hdr->mdl.scale_origin[0], hdr->mdl.scale_origin[1], + hdr->mdl.scale_origin[2], 1 }, + }; + mmulf (mvp_mat, worldMatrix, mvp_mat); + mmulf (mvp_mat, alias_vp, mvp_mat); colormap = glsl_colormap; - if (ent->skin && ent->skin->auxtex) - colormap = ent->skin->auxtex; - if (ent->skin && ent->skin->texnum) { - skin_t *skin = ent->skin; + if (ent->renderer.skin && ent->renderer.skin->auxtex) + colormap = ent->renderer.skin->auxtex; + if (ent->renderer.skin && ent->renderer.skin->texnum) { + skin_t *skin = ent->renderer.skin; skin_tex = skin->texnum; } else { maliasskindesc_t *skindesc; - skindesc = R_AliasGetSkindesc (ent->skinnum, hdr); + skindesc = R_AliasGetSkindesc (ent->renderer.skinnum, hdr); skin_tex = skindesc->texnum; } blend = R_AliasGetLerpedFrames (ent, hdr); - pose1 += ent->pose1 * hdr->poseverts; - pose2 += ent->pose2 * hdr->poseverts; + pose1 += ent->animation.pose1 * hdr->poseverts; + pose2 += ent->animation.pose2 * hdr->poseverts; skin_size[0] = hdr->mdl.skinwidth; skin_size[1] = hdr->mdl.skinheight; @@ -293,7 +297,8 @@ glsl_R_DrawAlias (void) qfeglUniform1f (quake_mdl.shadelight.location, shadelight); qfeglUniform3fv (quake_mdl.lightvec.location, 1, lightvec); qfeglUniform2fv (quake_mdl.skin_size.location, 1, skin_size); - qfeglUniformMatrix4fv (quake_mdl.mvp_matrix.location, 1, false, mvp_mat); + qfeglUniformMatrix4fv (quake_mdl.mvp_matrix.location, 1, false, + &mvp_mat[0][0]); qfeglUniformMatrix3fv (quake_mdl.norm_matrix.location, 1, false, norm_mat); #ifndef TETRAHEDRON @@ -321,7 +326,7 @@ glsl_R_AliasBegin (void) quat_t fog; // pre-multiply the view and projection matricies - Mat4Mult (glsl_projection, glsl_view, alias_vp); + mmulf (alias_vp, glsl_projection, glsl_view); qfeglUseProgram (quake_mdl.program); qfeglEnableVertexAttribArray (quake_mdl.vertexa.location); diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index 3b5ed0cd4..3fc716cf8 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -46,6 +46,7 @@ #include "QF/cvar.h" #include "QF/dstring.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/sys.h" @@ -94,7 +95,7 @@ static instsurf_t **instsurfs_tail = &instsurfs; static instsurf_t *free_instsurfs; static GLuint bsp_vbo; -static mat4_t bsp_vp; +static mat4f_t bsp_vp; static GLuint skybox_tex; static qboolean skybox_loaded; @@ -430,9 +431,9 @@ glsl_R_RegisterTextures (model_t **models, int num_models) mod_brush_t *brush; glsl_R_ClearTextures (); - glsl_R_InitSurfaceChains (&r_worldentity.model->brush); + glsl_R_InitSurfaceChains (&r_worldentity.renderer.model->brush); glsl_R_AddTexture (r_notexture_mip); - register_textures (&r_worldentity.model->brush); + register_textures (&r_worldentity.renderer.model->brush); for (i = 0; i < num_models; i++) { m = models[i]; if (!m) @@ -441,7 +442,7 @@ glsl_R_RegisterTextures (model_t **models, int num_models) if (*m->path == '*') continue; // world has already been done, not interested in non-brush models - if (m == r_worldentity.model || m->type != mod_brush) + if (m == r_worldentity.renderer.model || m->type != mod_brush) continue; brush = &m->brush; brush->numsubmodels = 1; // no support for submodels in non-world model @@ -486,7 +487,7 @@ build_surf_displist (model_t **models, msurface_t *fa, int base, if (fa->ec_index < 0) { brush = &models[-fa->ec_index - 1]->brush; } else { - brush = &r_worldentity.model->brush; + brush = &r_worldentity.renderer.model->brush; } vertices = brush->vertexes; edges = brush->edges; @@ -585,7 +586,7 @@ glsl_R_BuildDisplayLists (model_t **models, int num_models) } surf = brush->surfaces + j; surf->ec_index = dm - brush->submodels; - if (!surf->ec_index && m != r_worldentity.model) + if (!surf->ec_index && m != r_worldentity.renderer.model) surf->ec_index = -1 - i; // instanced model tex = surf->texinfo->texture->render; CHAIN_SURF_F2B (surf, tex->tex_chain); @@ -662,9 +663,12 @@ R_DrawBrushModel (entity_t *e) vec3_t mins, maxs, org; mod_brush_t *brush; - model = e->model; + model = e->renderer.model; brush = &model->brush; - if (e->transform[0] != 1 || e->transform[5] != 1 || e->transform[10] != 1) { + mat4f_t mat; + Transform_GetWorldMatrix (e->transform, mat); + memcpy (e->renderer.full_transform, mat, sizeof (mat));//FIXME + if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { rotated = true; radius = model->radius; if (R_CullSphere (e->origin, radius)) @@ -679,12 +683,11 @@ R_DrawBrushModel (entity_t *e) VectorSubtract (r_refdef.vieworg, e->origin, org); if (rotated) { - vec3_t temp; + vec4f_t temp = { org[0], org[1], org[2], 0 }; - VectorCopy (org, temp); - org[0] = DotProduct (temp, e->transform + 0); - org[1] = DotProduct (temp, e->transform + 4); - org[2] = DotProduct (temp, e->transform + 8); + org[0] = dotf (temp, mat[0])[0]; + org[1] = dotf (temp, mat[1])[0]; + org[2] = dotf (temp, mat[2])[0]; } // calculate dynamic lighting for bmodel if it's not an instanced model @@ -713,7 +716,8 @@ R_DrawBrushModel (entity_t *e) // enqueue the polygon if (((surf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(surf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - chain_surface (brush, surf, e->transform, e->colormod); + chain_surface (brush, surf, e->renderer.full_transform, + e->renderer.colormod); } } } @@ -842,10 +846,10 @@ draw_elechain (elechain_t *ec, int matloc, int vertloc, int tlstloc, } } if (ec->transform) { - Mat4Mult (bsp_vp, ec->transform, mat); + Mat4Mult (&bsp_vp[0][0], ec->transform, mat);//FIXME qfeglUniformMatrix4fv (matloc, 1, false, mat); } else { - qfeglUniformMatrix4fv (matloc, 1, false, bsp_vp); + qfeglUniformMatrix4fv (matloc, 1, false, &bsp_vp[0][0]); } for (el = ec->elements; el; el = el->next) { if (!el->list->size) @@ -873,7 +877,7 @@ bsp_begin (void) QuatCopy (default_color, last_color); qfeglVertexAttrib4fv (quake_bsp.color.location, default_color); - Mat4Mult (glsl_projection, glsl_view, bsp_vp); + mmulf (bsp_vp, glsl_projection, glsl_view); qfeglUseProgram (quake_bsp.program); qfeglEnableVertexAttribArray (quake_bsp.vertex.location); @@ -928,7 +932,7 @@ turb_begin (void) QuatCopy (default_color, last_color); qfeglVertexAttrib4fv (quake_bsp.color.location, default_color); - Mat4Mult (glsl_projection, glsl_view, bsp_vp); + mmulf (bsp_vp, glsl_projection, glsl_view); qfeglUseProgram (quake_turb.program); qfeglEnableVertexAttribArray (quake_turb.vertex.location); @@ -1001,7 +1005,7 @@ sky_begin (void) QuatCopy (default_color, last_color); qfeglVertexAttrib4fv (quake_bsp.color.location, default_color); - Mat4Mult (glsl_projection, glsl_view, bsp_vp); + mmulf (bsp_vp, glsl_projection, glsl_view); if (skybox_loaded) { sky_params.mvp_matrix = &quake_skybox.mvp_matrix; @@ -1127,15 +1131,15 @@ glsl_R_DrawWorld (void) clear_texture_chains (); // do this first for water and skys memset (&worldent, 0, sizeof (worldent)); - worldent.model = r_worldentity.model; + worldent.renderer.model = r_worldentity.renderer.model; currententity = &worldent; - R_VisitWorldNodes (&worldent.model->brush); + R_VisitWorldNodes (&worldent.renderer.model->brush); if (r_drawentities->int_val) { entity_t *ent; for (ent = r_ent_queue; ent; ent = ent->next) { - if (ent->model->type != mod_brush) + if (ent->renderer.model->type != mod_brush) continue; currententity = ent; diff --git a/libs/video/renderer/glsl/glsl_iqm.c b/libs/video/renderer/glsl/glsl_iqm.c index ce2c2f31d..76a9ae85e 100644 --- a/libs/video/renderer/glsl/glsl_iqm.c +++ b/libs/video/renderer/glsl/glsl_iqm.c @@ -43,6 +43,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/skin.h" #include "QF/sys.h" @@ -137,7 +138,7 @@ static struct va_attr_s { {&iqm_shader.vcolor, 4, GL_UNSIGNED_BYTE, 1}, }; -static mat4_t iqm_vp; +static mat4f_t iqm_vp; void glsl_R_InitIQM (void) @@ -207,28 +208,31 @@ glsl_R_DrawIQM (void) { static quat_t color = { 1, 1, 1, 1}; entity_t *ent = currententity; - model_t *model = ent->model; + model_t *model = ent->renderer.model; iqm_t *iqm = (iqm_t *) model->aliashdr; glsliqm_t *glsl = (glsliqm_t *) iqm->extra_data; dlight_t *lights[MAX_IQM_LIGHTS]; int i; vec_t norm_mat[9]; - mat4_t mvp_mat; + mat4f_t mvp_mat; float blend; iqmframe_t *frame; - R_LightPoint (&r_worldentity.model->brush, ent->origin);//FIXME min_light? + R_LightPoint (&r_worldentity.renderer.model->brush, ent->origin);//FIXME min_light? VectorScale (ambientcolor, 1/255.0, ambientcolor); R_FindNearLights (ent->origin, MAX_IQM_LIGHTS, lights); // we need only the rotation for normals. - VectorCopy (ent->transform + 0, norm_mat + 0); - VectorCopy (ent->transform + 4, norm_mat + 3); - VectorCopy (ent->transform + 8, norm_mat + 6); - Mat4Mult (iqm_vp, ent->transform, mvp_mat); + mat4f_t mat; + Transform_GetWorldMatrix (ent->transform, mat); + VectorCopy (mat[0], norm_mat + 0); + VectorCopy (mat[1], norm_mat + 3); + VectorCopy (mat[2], norm_mat + 6); + mmulf (mvp_mat, iqm_vp, mat); blend = R_IQMGetLerpedFrames (ent, iqm); - frame = R_IQMBlendFrames (iqm, ent->pose1, ent->pose2, blend, 0); + frame = R_IQMBlendFrames (iqm, ent->animation.pose1, ent->animation.pose2, + blend, 0); qfeglUniform3fv (iqm_shader.ambient.location, 1, ambientcolor); for (i = 0; i < MAX_IQM_LIGHTS; i++) { @@ -249,7 +253,8 @@ glsl_R_DrawIQM (void) qfeglBindBuffer (GL_ARRAY_BUFFER, glsl->vertex_array); qfeglBindBuffer (GL_ELEMENT_ARRAY_BUFFER, glsl->element_array); - qfeglUniformMatrix4fv (iqm_shader.mvp_matrix.location, 1, false, mvp_mat); + qfeglUniformMatrix4fv (iqm_shader.mvp_matrix.location, 1, false, + &mvp_mat[0][0]); qfeglUniformMatrix3fv (iqm_shader.norm_matrix.location, 1, false, norm_mat); qfeglUniformMatrix4fv (iqm_shader.bonemats.location, iqm->num_joints, @@ -274,7 +279,7 @@ glsl_R_IQMBegin (void) quat_t fog; // pre-multiply the view and projection matricies - Mat4Mult (glsl_projection, glsl_view, iqm_vp); + mmulf (iqm_vp, glsl_projection, glsl_view); qfeglUseProgram (iqm_shader.program); diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index 32688b2ae..ba8c2dce7 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -60,15 +60,15 @@ #include "r_internal.h" #include "vid_gl.h" -mat4_t glsl_projection; -mat4_t glsl_view; +mat4f_t glsl_projection; +mat4f_t glsl_view; void glsl_R_ViewChanged (float aspect) { double xmin, xmax, ymin, ymax; float fovx, fovy, neard, fard; - vec_t *proj = glsl_projection; + vec4f_t *proj = glsl_projection; fovx = r_refdef.fov_x; fovy = r_refdef.fov_y; @@ -80,25 +80,30 @@ glsl_R_ViewChanged (float aspect) xmax = neard * tan (fovx * M_PI / 360); // fov_2 / 2 xmin = -xmax; - proj[0] = (2 * neard) / (xmax - xmin); - proj[4] = 0; - proj[8] = (xmax + xmin) / (xmax - xmin); - proj[12] = 0; - - proj[1] = 0; - proj[5] = (2 * neard) / (ymax - ymin); - proj[9] = (ymax + ymin) / (ymax - ymin); - proj[13] = 0; - - proj[2] = 0; - proj[6] = 0; - proj[10] = (fard + neard) / (neard - fard); - proj[14] = (2 * fard * neard) / (neard - fard); - - proj[3] = 0; - proj[7] = 0; - proj[11] = -1; - proj[15] = 0; + proj[0] = (vec4f_t) { + (2 * neard) / (xmax - xmin), + 0, + 0, + 0 + }; + proj[1] = (vec4f_t) { + 0, + (2 * neard) / (ymax - ymin), + 0, + 0 + }; + proj[2] = (vec4f_t) { + (xmax + xmin) / (xmax - xmin), + (ymax + ymin) / (ymax - ymin), + (fard + neard) / (neard - fard), + -1 + }; + proj[3] = (vec4f_t) { + 0, + 0, + (2 * fard * neard) / (neard - fard), + 0 + }; } void @@ -110,22 +115,24 @@ glsl_R_SetupFrame (void) VectorCopy (r_refdef.vieworg, r_origin); AngleVectors (r_refdef.viewangles, vpn, vright, vup); + R_SetFrustum (); - r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.model); + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.renderer.model); } static void R_SetupView (void) { float x, y, w, h; - mat4_t mat; - static mat4_t z_up = { - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1, + static mat4f_t z_up = { + { 0, 0, -1, 0}, + {-1, 0, 0, 0}, + { 0, 1, 0, 0}, + { 0, 0, 0, 1}, }; + vec4f_t rotation; + vec4f_t offset = { 0, 0, 0, 1 }; x = r_refdef.vrect.x; y = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)); @@ -133,17 +140,12 @@ R_SetupView (void) h = r_refdef.vrect.height; qfeglViewport (x, y, w, h); - Mat4Zero (mat); - VectorCopy (vpn, mat + 0); - VectorNegate (vright, mat + 4); // we want vleft - VectorCopy (vup, mat + 8); - mat[15] = 1; - Mat4Transpose (mat, mat);//AngleVectors gives the transpose of what we want - Mat4Mult (z_up, mat, glsl_view); - - Mat4Identity (mat); - VectorNegate (r_refdef.vieworg, mat + 12); - Mat4Mult (glsl_view, mat, glsl_view); + AngleQuat (r_refdef.viewangles, &rotation[0]); + rotation = qconjf (rotation); + mat4fquat (glsl_view, rotation); + mmulf (glsl_view, z_up, glsl_view); + VectorNegate (r_refdef.vieworg, offset); + glsl_view[3] = mvmulf (glsl_view, offset); qfeglEnable (GL_CULL_FACE); qfeglEnable (GL_DEPTH_TEST); @@ -161,7 +163,7 @@ R_RenderEntities (void) do { \ begun = 0; \ for (ent = r_ent_queue; ent; ent = ent->next) { \ - if (ent->model->type != mod_##type_name) \ + if (ent->renderer.model->type != mod_##type_name) \ continue; \ if (!begun) { \ glsl_R_##Type##Begin (); \ @@ -186,7 +188,7 @@ R_DrawViewModel (void) if (vr_data.inhibit_viewmodel || !r_drawviewmodel->int_val || !r_drawentities->int_val - || !currententity->model) + || !currententity->renderer.model) return; // hack the depth range to prevent view model from poking into walls @@ -273,7 +275,7 @@ glsl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) d_lightstylevalue[i] = 264; // normal light value memset (&r_worldentity, 0, sizeof (r_worldentity)); - r_worldentity.model = worldmodel; + r_worldentity.renderer.model = worldmodel; // Force a vis update r_viewleaf = NULL; diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index 139423bb7..eb7eccb6d 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -313,7 +313,7 @@ glsl_R_ReadPointFile_f (void) vec3_t org; QFile *f; - mapname = strdup (r_worldentity.model->path); + mapname = strdup (r_worldentity.renderer.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); @@ -1568,10 +1568,10 @@ draw_qf_particles (void) particle_t *part; vec3_t up_scale, right_scale, up_right_scale, down_right_scale; partvert_t *VA; - mat4_t vp_mat; + mat4f_t vp_mat; quat_t fog; - Mat4Mult (glsl_projection, glsl_view, vp_mat); + mmulf (vp_mat, glsl_projection, glsl_view); qfeglDepthMask (GL_FALSE); qfeglUseProgram (quake_part.program); @@ -1583,7 +1583,8 @@ draw_qf_particles (void) fog[3] = glsl_Fog_GetDensity () / 64.0; qfeglUniform4fv (quake_part.fog.location, 1, fog); - qfeglUniformMatrix4fv (quake_part.mvp_matrix.location, 1, false, vp_mat); + qfeglUniformMatrix4fv (quake_part.mvp_matrix.location, 1, false, + &vp_mat[0][0]); qfeglUniform1i (quake_part.texture.location, 0); qfeglActiveTexture (GL_TEXTURE0 + 0); @@ -1712,10 +1713,10 @@ draw_id_particles (void) float minparticledist; particle_t *part; partvert_t *VA; - mat4_t vp_mat; + mat4f_t vp_mat; quat_t fog; - Mat4Mult (glsl_projection, glsl_view, vp_mat); + mmulf (vp_mat, glsl_projection, glsl_view); // LordHavoc: particles should not affect zbuffer qfeglDepthMask (GL_FALSE); @@ -1723,7 +1724,8 @@ draw_id_particles (void) qfeglEnableVertexAttribArray (quake_point.vertex.location); qfeglEnableVertexAttribArray (quake_point.color.location); - qfeglUniformMatrix4fv (quake_point.mvp_matrix.location, 1, false, vp_mat); + qfeglUniformMatrix4fv (quake_point.mvp_matrix.location, 1, false, + &vp_mat[0][0]); glsl_Fog_GetColor (fog); fog[3] = glsl_Fog_GetDensity () / 64.0; diff --git a/libs/video/renderer/glsl/glsl_sprite.c b/libs/video/renderer/glsl/glsl_sprite.c index c0acdc078..7582e9db3 100644 --- a/libs/video/renderer/glsl/glsl_sprite.c +++ b/libs/video/renderer/glsl/glsl_sprite.c @@ -42,6 +42,7 @@ #endif #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/draw.h" #include "QF/dstring.h" #include "QF/quakefs.h" @@ -131,7 +132,7 @@ static void R_GetSpriteFrames (entity_t *ent, msprite_t *sprite, mspriteframe_t **frame1, mspriteframe_t **frame2, float *blend) { - int framenum = currententity->frame; + int framenum = currententity->animation.frame; int pose; int i, numframes; float *intervals; @@ -153,7 +154,7 @@ R_GetSpriteFrames (entity_t *ent, msprite_t *sprite, mspriteframe_t **frame1, numframes = group->numframes; fullinterval = intervals[numframes - 1]; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; targettime = time - ((int) (time / fullinterval)) * fullinterval; for (i = 0; i < numframes - 1; i++) { @@ -170,17 +171,17 @@ R_GetSpriteFrames (entity_t *ent, msprite_t *sprite, mspriteframe_t **frame1, //group frames. *blend = R_EntityBlend (ent, pose, frame_interval); if (group) { - *frame1 = group->frames[ent->pose1]; - *frame2 = group->frames[ent->pose2]; + *frame1 = group->frames[ent->animation.pose1]; + *frame2 = group->frames[ent->animation.pose2]; } else { - *frame1 = sprite->frames[ent->pose1].frameptr; - *frame2 = sprite->frames[ent->pose2].frameptr; + *frame1 = sprite->frames[ent->animation.pose1].frameptr; + *frame2 = sprite->frames[ent->animation.pose2].frameptr; } } static void -make_quad (mspriteframe_t *frame, const vec3_t vpn, const vec3_t vright, - const vec3_t vup, float verts[6][3]) +make_quad (mspriteframe_t *frame, vec4f_t vpn, vec4f_t vright, + vec4f_t vup, float verts[6][3]) { vec3_t left, up, right, down; vec3_t ul, ur, ll, lr; @@ -209,11 +210,11 @@ void R_DrawSprite (void) { entity_t *ent = currententity; - msprite_t *sprite = (msprite_t *) ent->model->cache.data; + msprite_t *sprite = (msprite_t *) ent->renderer.model->cache.data; mspriteframe_t *frame1, *frame2; float blend, sr, cr, dot, angle; vec3_t tvec; - vec3_t svpn, svright, svup; + vec4f_t svpn = {}, svright = {}, svup = {}; static quat_t color = { 1, 1, 1, 1}; float vertsa[6][3], vertsb[6][3]; static float uvab[6][4] = { @@ -242,7 +243,7 @@ R_DrawSprite (void) VectorSet (0, 0, 1, svup); // CrossProduct (svup, -r_origin, svright) VectorSet (tvec[1], -tvec[0], 0, svright); - VectorNormalize (svright); + svright /= vsqrtf (dotf (svright, svright)); // CrossProduct (svright, svup, svpn); VectorSet (-svright[1], svright[0], 0, svpn); break; @@ -267,16 +268,16 @@ R_DrawSprite (void) VectorSet (0, 0, 1, svup); // CrossProduct (svup, -r_origin, svright) VectorSet (vpn[1], -vpn[0], 0, svright); - VectorNormalize (svright); + svright /= vsqrtf (dotf (svright, svright)); // CrossProduct (svright, svup, svpn); VectorSet (-svright[1], svright[0], 0, svpn); break; case SPR_ORIENTED: // generate the prite's axes according to the sprite's world // orientation - VectorCopy (currententity->transform + 0, svpn); - VectorNegate (currententity->transform + 4, svright); - VectorCopy (currententity->transform + 8, svup); + svup = Transform_Up (currententity->transform); + svright = Transform_Right (currententity->transform); + svpn = Transform_Forward (currententity->transform); break; case SPR_VP_PARALLEL_ORIENTED: // generate the sprite's axes parallel to the viewplane, but @@ -324,7 +325,7 @@ R_DrawSprite (void) void R_SpriteBegin (void) { - mat4_t mat; + mat4f_t mat; quat_t fog; qfeglUseProgram (quake_sprite.program); @@ -352,8 +353,8 @@ R_SpriteBegin (void) qfeglEnable (GL_TEXTURE_2D); qfeglBindTexture (GL_TEXTURE_2D, glsl_palette); - Mat4Mult (glsl_projection, glsl_view, mat); - qfeglUniformMatrix4fv (quake_sprite.matrix.location, 1, false, mat); + mmulf (mat, glsl_projection, glsl_view); + qfeglUniformMatrix4fv (quake_sprite.matrix.location, 1, false, &mat[0][0]); } void diff --git a/libs/video/renderer/r_alias.c b/libs/video/renderer/r_alias.c index aa1541ca2..b956f0500 100644 --- a/libs/video/renderer/r_alias.c +++ b/libs/video/renderer/r_alias.c @@ -63,7 +63,7 @@ R_AliasGetSkindesc (int skinnum, aliashdr_t *ahdr) numskins = paliasskingroup->numskins; fullskininterval = pskinintervals[numskins - 1]; - skintime = vr_data.realtime + currententity->syncbase; + skintime = vr_data.realtime + currententity->animation.syncbase; // when loading in Mod_LoadAliasSkinGroup, we guaranteed all interval // values are positive, so we don't have to worry about division by 0 @@ -118,7 +118,7 @@ alias_get_frame (int framenum, aliashdr_t *hdr, float *frame_interval) numframes = group->numframes; fullinterval = intervals[numframes - 1]; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; // when loading in Mod_LoadAliasGroup, we guaranteed all interval values // are positive, so we don't have to worry about division by 0 @@ -148,6 +148,6 @@ R_AliasGetLerpedFrames (entity_t *ent, aliashdr_t *hdr) maliasframedesc_t *frame; float interval; - frame = alias_get_frame (ent->frame, hdr, &interval); + frame = alias_get_frame (ent->animation.frame, hdr, &interval); return R_EntityBlend (ent, frame->firstpose, interval); } diff --git a/libs/video/renderer/r_bsp.c b/libs/video/renderer/r_bsp.c index 47b78a643..03af6696b 100644 --- a/libs/video/renderer/r_bsp.c +++ b/libs/video/renderer/r_bsp.c @@ -54,7 +54,7 @@ R_MarkLeaves (void) mleaf_t *leaf; mnode_t *node; msurface_t **mark; - mod_brush_t *brush = &r_worldentity.model->brush; + mod_brush_t *brush = &r_worldentity.renderer.model->brush; if (r_oldviewleaf == r_viewleaf && !r_novis->int_val) return; @@ -70,7 +70,7 @@ R_MarkLeaves (void) vis = solid; memset (solid, 0xff, (brush->numleafs + 7) >> 3); } else - vis = Mod_LeafPVS (r_viewleaf, r_worldentity.model); + vis = Mod_LeafPVS (r_viewleaf, r_worldentity.renderer.model); for (i = 0; (int) i < brush->numleafs; i++) { if (vis[i >> 3] & (1 << (i & 7))) { @@ -105,7 +105,7 @@ R_TextureAnimation (msurface_t *surf) texture_t *base = surf->texinfo->texture; int count, relative; - if (currententity->frame) { + if (currententity->animation.frame) { if (base->alternate_anims) base = base->alternate_anims; } diff --git a/libs/video/renderer/r_efrag.c b/libs/video/renderer/r_efrag.c index cbfd0d2c8..86d494b6d 100644 --- a/libs/video/renderer/r_efrag.c +++ b/libs/video/renderer/r_efrag.c @@ -101,7 +101,7 @@ R_RemoveEfrags (entity_t *ent) { efrag_t *ef, *old, *walk, **prev; - ef = ent->efrag; + ef = ent->visibility.efrag; while (ef) { prev = &ef->leaf->efrags; @@ -124,7 +124,7 @@ R_RemoveEfrags (entity_t *ent) r_free_efrags = old; } - ent->efrag = 0; + ent->visibility.efrag = 0; } static void @@ -143,15 +143,15 @@ R_SplitEntityOnNode (mod_brush_t *brush, entity_t *ent, node_stack = alloca ((brush->depth + 2) * sizeof (mnode_t *)); node_ptr = node_stack; - lastlink = &ent->efrag; + lastlink = &ent->visibility.efrag; *node_ptr++ = 0; while (node) { // add an efrag if the node is a leaf if (__builtin_expect (node->contents < 0, 0)) { - if (!ent->topnode) { - ent->topnode = node; + if (!ent->visibility.topnode) { + ent->visibility.topnode = node; } leaf = (mleaf_t *) node; @@ -177,8 +177,8 @@ R_SplitEntityOnNode (mod_brush_t *brush, entity_t *ent, if (sides == 3) { // split on this plane // if this is the first splitter of this bmodel, remember it - if (!ent->topnode) { - ent->topnode = node; + if (!ent->visibility.topnode) { + ent->visibility.topnode = node; } } // recurse down the contacted sides @@ -202,18 +202,18 @@ R_AddEfrags (mod_brush_t *brush, entity_t *ent) model_t *entmodel; vec3_t emins, emaxs; - if (!ent->model || !r_worldentity.model) + if (!ent->renderer.model || !r_worldentity.renderer.model) return; if (ent == &r_worldentity) return; // never add the world - entmodel = ent->model; + entmodel = ent->renderer.model; VectorAdd (ent->origin, entmodel->mins, emins); VectorAdd (ent->origin, entmodel->maxs, emaxs); - ent->topnode = 0; + ent->visibility.topnode = 0; R_SplitEntityOnNode (brush, ent, emins, emaxs); } @@ -225,17 +225,17 @@ R_StoreEfrags (const efrag_t *efrag) while (efrag) { ent = efrag->entity; - model = ent->model; + model = ent->renderer.model; switch (model->type) { case mod_alias: case mod_brush: case mod_sprite: case mod_iqm: - if (ent->visframe != r_framecount) { + if (ent->visibility.visframe != r_framecount) { R_EnqueueEntity (ent); // mark that we've recorded this entity for this frame - ent->visframe = r_framecount; + ent->visibility.visframe = r_framecount; } efrag = efrag->leafnext; break; diff --git a/libs/video/renderer/r_ent.c b/libs/video/renderer/r_ent.c index e72d10399..5a20bcb1f 100644 --- a/libs/video/renderer/r_ent.c +++ b/libs/video/renderer/r_ent.c @@ -38,6 +38,7 @@ #include #include +#include "QF/entity.h" #include "QF/model.h" #include "QF/msg.h" #include "QF/render.h" @@ -70,6 +71,7 @@ R_AllocEntity (void) if ((ent = free_entities)) { free_entities = ent->next; ent->next = 0; + ent->transform = 0; return ent; } @@ -78,9 +80,12 @@ R_AllocEntity (void) *entpool_tail = pool; entpool_tail = &pool->next; - for (ent = pool->entities, i = 0; i < ENT_POOL_SIZE - 1; i++, ent++) + for (ent = pool->entities, i = 0; i < ENT_POOL_SIZE - 1; i++, ent++) { ent->next = ent + 1; + ent->transform = 0; + } ent->next = 0; + ent->transform = 0; free_entities = pool->entities; return R_AllocEntity (); @@ -94,9 +99,18 @@ R_FreeAllEntities (void) int i; for (pool = entity_pools; pool; pool = pool->next) { - for (ent = pool->entities, i = 0; i < ENT_POOL_SIZE - 1; i++, ent++) + for (ent = pool->entities, i = 0; i < ENT_POOL_SIZE - 1; i++, ent++) { ent->next = ent + 1; + if (ent->transform) { + Transform_Delete (ent->transform); + ent->transform = 0; + } + } ent->next = pool->next ? pool->next->entities : 0; + if (ent->transform) { + Transform_Delete (ent->transform); + ent->transform = 0; + } } free_entities = entity_pools ? entity_pools->entities : 0; } @@ -121,27 +135,27 @@ R_EntityBlend (entity_t *ent, int pose, float interval) { float blend; - if (ent->pose_model != ent->model) { - ent->pose_model = ent->model; - ent->pose1 = pose; - ent->pose2 = pose; + if (ent->animation.nolerp) { + ent->animation.nolerp = 0; + ent->animation.pose1 = pose; + ent->animation.pose2 = pose; return 0.0; } - ent->frame_interval = interval; - if (ent->pose2 != pose) { - ent->frame_start_time = vr_data.realtime; - if (ent->pose2 == -1) { - ent->pose1 = pose; + ent->animation.frame_interval = interval; + if (ent->animation.pose2 != pose) { + ent->animation.frame_start_time = vr_data.realtime; + if (ent->animation.pose2 == -1) { + ent->animation.pose1 = pose; } else { - ent->pose1 = ent->pose2; + ent->animation.pose1 = ent->animation.pose2; } - ent->pose2 = pose; + ent->animation.pose2 = pose; blend = 0.0; } else if (vr_data.paused) { blend = 1.0; } else { - blend = (vr_data.realtime - ent->frame_start_time) - / ent->frame_interval; + blend = (vr_data.realtime - ent->animation.frame_start_time) + / ent->animation.frame_interval; blend = min (blend, 1.0); } return blend; diff --git a/libs/video/renderer/r_iqm.c b/libs/video/renderer/r_iqm.c index 224182a79..71dc47b3a 100644 --- a/libs/video/renderer/r_iqm.c +++ b/libs/video/renderer/r_iqm.c @@ -49,7 +49,7 @@ float R_IQMGetLerpedFrames (entity_t *ent, iqm_t *iqm) { - int frame = ent->frame; + int frame = ent->animation.frame; float time, fullinterval; iqmanim *anim; @@ -62,7 +62,7 @@ R_IQMGetLerpedFrames (entity_t *ent, iqm_t *iqm) } anim = &iqm->anims[frame]; fullinterval = anim->num_frames / anim->framerate; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; time -= ((int) (time / fullinterval)) * fullinterval; frame = (int) (time * anim->framerate) + anim->first_frame; return R_EntityBlend (ent, frame, 1.0 / anim->framerate); diff --git a/libs/video/renderer/r_light.c b/libs/video/renderer/r_light.c index 8d3294c37..96899621e 100644 --- a/libs/video/renderer/r_light.c +++ b/libs/video/renderer/r_light.c @@ -328,7 +328,7 @@ R_PushDlights (const vec3_t entorigin) if (l->die < vr_data.realtime || !l->radius) continue; VectorSubtract (l->origin, entorigin, lightorigin); - R_MarkLights (lightorigin, l, i, r_worldentity.model); + R_MarkLights (lightorigin, l, i, r_worldentity.renderer.model); } } diff --git a/libs/video/renderer/sw/sw_ralias.c b/libs/video/renderer/sw/sw_ralias.c index d28e41b04..1fcd1ce12 100644 --- a/libs/video/renderer/sw/sw_ralias.c +++ b/libs/video/renderer/sw/sw_ralias.c @@ -30,6 +30,7 @@ #include +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/skin.h" @@ -94,8 +95,8 @@ R_AliasCheckBBox (void) int minz; // expand, rotate, and translate points into worldspace - currententity->trivial_accept = 0; - pmodel = currententity->model; + currententity->visibility.trivial_accept = 0; + pmodel = currententity->renderer.model; if (!(pahdr = pmodel->aliashdr)) pahdr = Cache_Get (&pmodel->cache); pmdl = (mdl_t *) ((byte *) pahdr + pahdr->model); @@ -103,7 +104,7 @@ R_AliasCheckBBox (void) R_AliasSetUpTransform (0); // construct the base bounding box for this frame - frame = currententity->frame; + frame = currententity->animation.frame; // TODO: don't repeat this check when drawing? if ((frame >= pmdl->numframes) || (frame < 0)) { Sys_MaskPrintf (SYS_DEV, "No such frame %d %s\n", frame, pmodel->path); @@ -218,11 +219,11 @@ R_AliasCheckBBox (void) return false; // trivial reject off one side } - currententity->trivial_accept = !anyclip & !zclipped; + currententity->visibility.trivial_accept = !anyclip & !zclipped; - if (currententity->trivial_accept) { + if (currententity->visibility.trivial_accept) { if (minz > (r_aliastransition + (pmdl->size * r_resfudge))) { - currententity->trivial_accept |= 2; + currententity->visibility.trivial_accept |= 2; } } @@ -355,10 +356,12 @@ R_AliasSetUpTransform (int trivial_accept) float rotationmatrix[3][4], t2matrix[3][4]; static float tmatrix[3][4]; static float viewmatrix[3][4]; + mat4f_t mat; - VectorCopy (currententity->transform + 0, alias_forward); - VectorNegate (currententity->transform + 4, alias_right); - VectorCopy (currententity->transform + 8, alias_up); + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], alias_forward); + VectorNegate (mat[1], alias_right); + VectorCopy (mat[2], alias_up); tmatrix[0][0] = pmdl->scale[0]; tmatrix[1][1] = pmdl->scale[1]; @@ -542,7 +545,7 @@ R_AliasSetupSkin (void) { int skinnum; - skinnum = currententity->skinnum; + skinnum = currententity->renderer.skinnum; if ((skinnum >= pmdl->numskins) || (skinnum < 0)) { Sys_MaskPrintf (SYS_DEV, "R_AliasSetupSkin: no such skin # %d\n", skinnum); @@ -559,16 +562,16 @@ R_AliasSetupSkin (void) r_affinetridesc.skinheight = pmdl->skinheight; acolormap = vid.colormap8; - if (currententity->skin) { + if (currententity->renderer.skin) { tex_t *base; - base = currententity->skin->texels; + base = currententity->renderer.skin->texels; if (base) { r_affinetridesc.pskin = base->data; r_affinetridesc.skinwidth = base->width; r_affinetridesc.skinheight = base->height; } - acolormap = currententity->skin->colormap; + acolormap = currententity->renderer.skin->colormap; } } @@ -611,7 +614,7 @@ R_AliasSetupFrame (void) { maliasframedesc_t *frame; - frame = R_AliasGetFramedesc (currententity->frame, paliashdr); + frame = R_AliasGetFramedesc (currententity->animation.frame, paliashdr); r_apverts = (trivertx_t *) ((byte *) paliashdr + frame->frame); } @@ -624,8 +627,8 @@ R_AliasDrawModel (alight_t *plighting) r_amodels_drawn++; - if (!(paliashdr = currententity->model->aliashdr)) - paliashdr = Cache_Get (¤tentity->model->cache); + if (!(paliashdr = currententity->renderer.model->aliashdr)) + paliashdr = Cache_Get (¤tentity->renderer.model->cache); pmdl = (mdl_t *) ((byte *) paliashdr + paliashdr->model); size = (CACHE_SIZE - 1) @@ -641,12 +644,12 @@ R_AliasDrawModel (alight_t *plighting) pauxverts = (auxvert_t *) &pfinalverts[pmdl->numverts + 1]; R_AliasSetupSkin (); - R_AliasSetUpTransform (currententity->trivial_accept); + R_AliasSetUpTransform (currententity->visibility.trivial_accept); R_AliasSetupLighting (plighting); R_AliasSetupFrame (); - r_affinetridesc.drawtype = (currententity->trivial_accept == 3) && - r_recursiveaffinetriangles; + r_affinetridesc.drawtype = ((currententity->visibility.trivial_accept == 3) + && r_recursiveaffinetriangles); if (!acolormap) acolormap = vid.colormap8; @@ -664,11 +667,14 @@ R_AliasDrawModel (alight_t *plighting) else ziscale = (float) 0x8000 *(float) 0x10000 *3.0; - if (currententity->trivial_accept && pmdl->ident != HEADER_MDL16) + if (currententity->visibility.trivial_accept + && pmdl->ident != HEADER_MDL16) { R_AliasPrepareUnclippedPoints (); - else + } else { R_AliasPreparePoints (); + } - if (!currententity->model->aliashdr) - Cache_Release (¤tentity->model->cache); + if (!currententity->renderer.model->aliashdr) { + Cache_Release (¤tentity->renderer.model->cache); + } } diff --git a/libs/video/renderer/sw/sw_rbsp.c b/libs/video/renderer/sw/sw_rbsp.c index 7cf001b87..e9b3fde8a 100644 --- a/libs/video/renderer/sw/sw_rbsp.c +++ b/libs/video/renderer/sw/sw_rbsp.c @@ -33,6 +33,7 @@ #include "qfalloca.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -77,9 +78,11 @@ R_EntityRotate (vec3_t vec) void R_RotateBmodel (void) { - VectorCopy (currententity->transform + 0, entity_rotation[0]); - VectorCopy (currententity->transform + 4, entity_rotation[1]); - VectorCopy (currententity->transform + 8, entity_rotation[2]); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], entity_rotation[0]); + VectorCopy (mat[1], entity_rotation[1]); + VectorCopy (mat[2], entity_rotation[2]); // rotate modelorg and the transformation matrix R_EntityRotate (modelorg); @@ -297,7 +300,8 @@ R_DrawSolidClippedSubmodelPolygons (model_t *model) pbedge[j - 1].pnext = NULL; // mark end of edges - R_RecursiveClipBPoly (pbedge, currententity->topnode, psurf); + R_RecursiveClipBPoly (pbedge, + currententity->visibility.topnode, psurf); } else { Sys_Error ("no edges in bmodel"); } @@ -330,7 +334,7 @@ R_DrawSubmodelPolygons (model_t *model, int clipflags) // draw the polygon if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - r_currentkey = ((mleaf_t *) currententity->topnode)->key; + r_currentkey = ((mleaf_t *) currententity->visibility.topnode)->key; // FIXME: use bounding-box-based frustum clipping info? R_RenderFace (psurf, clipflags); @@ -511,7 +515,7 @@ R_RenderWorld (void) currententity = &r_worldentity; VectorCopy (r_origin, modelorg); - brush = ¤tentity->model->brush; + brush = ¤tentity->renderer.model->brush; r_pcurrentvertbase = brush->vertexes; R_VisitWorldNodes (brush, 15); diff --git a/libs/video/renderer/sw/sw_rdraw.c b/libs/video/renderer/sw/sw_rdraw.c index 3f460643d..67c298187 100644 --- a/libs/video/renderer/sw/sw_rdraw.c +++ b/libs/video/renderer/sw/sw_rdraw.c @@ -353,7 +353,7 @@ R_RenderFace (msurface_t *fa, int clipflags) vec3_t p_normal; medge_t *pedges, tedge; clipplane_t *pclip; - mod_brush_t *brush = ¤tentity->model->brush; + mod_brush_t *brush = ¤tentity->renderer.model->brush; // skip out if no more surfs if ((surface_p) >= surf_max) { @@ -624,7 +624,7 @@ R_RenderPoly (msurface_t *fa, int clipflags) polyvert_t pverts[100]; // FIXME: do real number, safely int vertpage, newverts, newpage, lastvert; qboolean visible; - mod_brush_t *brush = ¤tentity->model->brush; + mod_brush_t *brush = ¤tentity->renderer.model->brush; // FIXME: clean this up and make it faster // FIXME: guard against running out of vertices diff --git a/libs/video/renderer/sw/sw_riqm.c b/libs/video/renderer/sw/sw_riqm.c index 285342b3f..8674e3ca6 100644 --- a/libs/video/renderer/sw/sw_riqm.c +++ b/libs/video/renderer/sw/sw_riqm.c @@ -40,6 +40,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/skin.h" @@ -231,9 +232,12 @@ R_IQMSetupLighting (entity_t *ent, alight_t *plighting) r_shadelight *= VID_GRADES; // rotate the lighting vector into the model's frame of reference - r_plightvec[0] = DotProduct (plighting->plightvec, ent->transform + 0); - r_plightvec[1] = DotProduct (plighting->plightvec, ent->transform + 4); - r_plightvec[2] = DotProduct (plighting->plightvec, ent->transform + 8); + mat4f_t mat; + Transform_GetWorldMatrix (ent->transform, mat); + //FIXME vectorize + r_plightvec[0] = DotProduct (plighting->plightvec, mat[0]); + r_plightvec[1] = DotProduct (plighting->plightvec, mat[1]); + r_plightvec[2] = DotProduct (plighting->plightvec, mat[2]); } static void @@ -244,9 +248,11 @@ R_IQMSetUpTransform (int trivial_accept) static float viewmatrix[3][4]; vec3_t forward, left, up; - VectorCopy (currententity->transform + 0, forward); - VectorCopy (currententity->transform + 4, left); - VectorCopy (currententity->transform + 8, up); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], forward); + VectorCopy (mat[1], left); + VectorCopy (mat[2], up); // TODO: can do this with simple matrix rearrangement @@ -293,7 +299,7 @@ void R_IQMDrawModel (alight_t *plighting) { entity_t *ent = currententity; - model_t *model = ent->model; + model_t *model = ent->renderer.model; iqm_t *iqm = (iqm_t *) model->aliashdr; swiqm_t *sw = (swiqm_t *) iqm->extra_data; int size; @@ -304,18 +310,19 @@ R_IQMDrawModel (alight_t *plighting) + sizeof (finalvert_t) * (iqm->num_verts + 1) + sizeof (auxvert_t) * iqm->num_verts; blend = R_IQMGetLerpedFrames (ent, iqm); - frame = R_IQMBlendPalette (iqm, ent->pose1, ent->pose2, blend, size, - sw->blend_palette, sw->palette_size); + frame = R_IQMBlendPalette (iqm, ent->animation.pose1, ent->animation.pose2, + blend, size, sw->blend_palette, + sw->palette_size); pfinalverts = (finalvert_t *) &frame[sw->palette_size]; pfinalverts = (finalvert_t *) (((intptr_t) &pfinalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); pauxverts = (auxvert_t *) &pfinalverts[iqm->num_verts + 1]; - R_IQMSetUpTransform (ent->trivial_accept); + R_IQMSetUpTransform (ent->visibility.trivial_accept); R_IQMSetupLighting (ent, plighting); - r_affinetridesc.drawtype = (ent->trivial_accept == 3) && + r_affinetridesc.drawtype = (ent->visibility.trivial_accept == 3) && r_recursiveaffinetriangles; //if (!acolormap) @@ -326,7 +333,7 @@ R_IQMDrawModel (alight_t *plighting) else ziscale = (float) 0x8000 *(float) 0x10000 *3.0; - if (ent->trivial_accept) + if (ent->visibility.trivial_accept) R_IQMPrepareUnclippedPoints (iqm, sw, frame); else R_IQMPreparePoints (iqm, sw, frame); diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 573827bda..7cf5416c0 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -42,6 +42,7 @@ #include "QF/cmd.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/locs.h" #include "QF/mathlib.h" #include "QF/render.h" @@ -167,7 +168,7 @@ R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) mod_brush_t *brush = &worldmodel->brush; memset (&r_worldentity, 0, sizeof (r_worldentity)); - r_worldentity.model = worldmodel; + r_worldentity.renderer.model = worldmodel; R_FreeAllEntities (); @@ -362,7 +363,7 @@ R_DrawEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; - switch (currententity->model->type) { + switch (currententity->renderer.model->type) { case mod_sprite: VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); @@ -374,15 +375,16 @@ R_DrawEntitiesOnList (void) VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); - minlight = max (currententity->model->min_light, currententity->min_light); + minlight = max (currententity->renderer.model->min_light, + currententity->renderer.min_light); // see if the bounding box lets us trivially reject, also // sets trivial accept status - currententity->trivial_accept = 0; //FIXME - if (currententity->model->type == mod_iqm//FIXME + currententity->visibility.trivial_accept = 0; //FIXME + if (currententity->renderer.model->type == mod_iqm//FIXME || R_AliasCheckBBox ()) { // 128 instead of 255 due to clamping below - j = max (R_LightPoint (&r_worldentity.model->brush, + j = max (R_LightPoint (&r_worldentity.renderer.model->brush, currententity->origin), minlight * 128); lighting.ambientlight = j; @@ -407,7 +409,7 @@ R_DrawEntitiesOnList (void) if (lighting.ambientlight + lighting.shadelight > 192) lighting.shadelight = 192 - lighting.ambientlight; - if (currententity->model->type == mod_iqm) + if (currententity->renderer.model->type == mod_iqm) R_IQMDrawModel (&lighting); else R_AliasDrawModel (&lighting); @@ -439,7 +441,7 @@ R_DrawViewModel (void) return; currententity = vr_data.view_model; - if (!currententity->model) + if (!currententity->renderer.model) return; VectorCopy (currententity->origin, r_entorigin); @@ -448,9 +450,10 @@ R_DrawViewModel (void) VectorCopy (vup, viewlightvec); VectorNegate (viewlightvec, viewlightvec); - minlight = max (currententity->min_light, currententity->model->min_light); + minlight = max (currententity->renderer.min_light, + currententity->renderer.model->min_light); - j = max (R_LightPoint (&r_worldentity.model->brush, + j = max (R_LightPoint (&r_worldentity.renderer.model->brush, currententity->origin), minlight * 128); r_viewlighting.ambientlight = j; @@ -489,11 +492,12 @@ R_BmodelCheckBBox (model_t *clmodel, float *minmaxs) int i, *pindex, clipflags; vec3_t acceptpt, rejectpt; double d; + mat4f_t mat; clipflags = 0; - if (currententity->transform[0] != 1 || currententity->transform[5] != 1 - || currententity->transform[10] != 1) { + Transform_GetWorldMatrix (currententity->transform, mat); + if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { for (i = 0; i < 4; i++) { d = DotProduct (currententity->origin, view_clipplanes[i].normal); d -= view_clipplanes[i].dist; @@ -556,9 +560,9 @@ R_DrawBEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; - switch (currententity->model->type) { + switch (currententity->renderer.model->type) { case mod_brush: - clmodel = currententity->model; + clmodel = currententity->renderer.model; // see if the bounding box lets us trivially reject, also // sets trivial accept status @@ -606,8 +610,9 @@ R_DrawBEntitiesOnList (void) if (r_drawpolys | r_drawculledpolys) { R_ZDrawSubmodelPolys (clmodel); } else { - if (currententity->topnode) { - mnode_t *topnode = currententity->topnode; + if (currententity->visibility.topnode) { + mnode_t *topnode + = currententity->visibility.topnode; if (topnode->contents >= 0) { // not a leaf; has to be clipped to the world @@ -756,7 +761,7 @@ R_RenderView_ (void) // done in screen.c R_LowFPPrecision (); - if (!r_worldentity.model) + if (!r_worldentity.renderer.model) Sys_Error ("R_RenderView: NULL worldmodel"); if (!r_dspeeds->int_val) { diff --git a/libs/video/renderer/sw/sw_rmisc.c b/libs/video/renderer/sw/sw_rmisc.c index b2272ff14..dee5c780e 100644 --- a/libs/video/renderer/sw/sw_rmisc.c +++ b/libs/video/renderer/sw/sw_rmisc.c @@ -244,7 +244,7 @@ R_SetupFrame (void) R_SetFrustum (); // current viewleaf - r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.model); + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.renderer.model); r_dowarpold = r_dowarp; r_dowarp = r_waterwarp->int_val && (r_viewleaf->contents <= diff --git a/libs/video/renderer/sw/sw_rpart.c b/libs/video/renderer/sw/sw_rpart.c index a5be06453..d154ad739 100644 --- a/libs/video/renderer/sw/sw_rpart.c +++ b/libs/video/renderer/sw/sw_rpart.c @@ -83,7 +83,7 @@ R_ReadPointFile_f (void) const char *name; char *mapname; - mapname = strdup (r_worldentity.model->path); + mapname = strdup (r_worldentity.renderer.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); diff --git a/libs/video/renderer/sw/sw_rsprite.c b/libs/video/renderer/sw/sw_rsprite.c index 4ee5d74c3..8eb4151e7 100644 --- a/libs/video/renderer/sw/sw_rsprite.c +++ b/libs/video/renderer/sw/sw_rsprite.c @@ -37,6 +37,7 @@ #include +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -246,7 +247,7 @@ R_GetSpriteframe (msprite_t *psprite) int i, numframes, frame; float *pintervals, fullinterval, targettime, time; - frame = currententity->frame; + frame = currententity->animation.frame; if ((frame >= psprite->numframes) || (frame < 0)) { Sys_Printf ("R_DrawSprite: no such frame %d\n", frame); @@ -261,7 +262,7 @@ R_GetSpriteframe (msprite_t *psprite) numframes = pspritegroup->numframes; fullinterval = pintervals[numframes - 1]; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; // when loading in Mod_LoadSpriteGroup, we guaranteed all interval // values are positive, so we don't have to worry about division by 0 @@ -287,7 +288,7 @@ R_DrawSprite (void) vec3_t tvec; float dot, angle, sr, cr; - psprite = currententity->model->cache.data; + psprite = currententity->renderer.model->cache.data; r_spritedesc.pspriteframe = R_GetSpriteframe (psprite); @@ -361,9 +362,11 @@ R_DrawSprite (void) } else if (psprite->type == SPR_ORIENTED) { // generate the sprite's axes, according to the sprite's world // orientation - VectorCopy (currententity->transform + 0, r_spritedesc.vpn); - VectorNegate (currententity->transform + 4, r_spritedesc.vright); - VectorCopy (currententity->transform + 8, r_spritedesc.vup); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], r_spritedesc.vpn); + VectorNegate (mat[1], r_spritedesc.vright); + VectorCopy (mat[2], r_spritedesc.vup); } else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) { // generate the sprite's axes, parallel to the viewplane, but rotated // in that plane around the center according to the sprite entity's diff --git a/libs/video/renderer/sw/sw_rsurf.c b/libs/video/renderer/sw/sw_rsurf.c index 5133118cb..1dded8c00 100644 --- a/libs/video/renderer/sw/sw_rsurf.c +++ b/libs/video/renderer/sw/sw_rsurf.c @@ -154,7 +154,7 @@ R_BuildLightMap (void) size = smax * tmax; lightmap = surf->samples; - if (!r_worldentity.model->brush.lightdata) { + if (!r_worldentity.renderer.model->brush.lightdata) { for (i = 0; i < size; i++) blocklights[i] = 0; return; diff --git a/libs/video/renderer/sw32/sw32_ralias.c b/libs/video/renderer/sw32/sw32_ralias.c index 4ead8055a..1dacb5bc7 100644 --- a/libs/video/renderer/sw32/sw32_ralias.c +++ b/libs/video/renderer/sw32/sw32_ralias.c @@ -31,6 +31,7 @@ #define NH_DEFINE #include "namehack.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/skin.h" @@ -97,8 +98,8 @@ sw32_R_AliasCheckBBox (void) int minz; // expand, rotate, and translate points into worldspace - currententity->trivial_accept = 0; - pmodel = currententity->model; + currententity->visibility.trivial_accept = 0; + pmodel = currententity->renderer.model; if (!(pahdr = pmodel->aliashdr)) pahdr = Cache_Get (&pmodel->cache); pmdl = (mdl_t *) ((byte *) pahdr + pahdr->model); @@ -106,7 +107,7 @@ sw32_R_AliasCheckBBox (void) sw32_R_AliasSetUpTransform (0); // construct the base bounding box for this frame - frame = currententity->frame; + frame = currententity->animation.frame; // TODO: don't repeat this check when drawing? if ((frame >= pmdl->numframes) || (frame < 0)) { Sys_MaskPrintf (SYS_DEV, "No such frame %d %s\n", frame, pmodel->path); @@ -221,11 +222,11 @@ sw32_R_AliasCheckBBox (void) return false; // trivial reject off one side } - currententity->trivial_accept = !anyclip & !zclipped; + currententity->visibility.trivial_accept = !anyclip & !zclipped; - if (currententity->trivial_accept) { + if (currententity->visibility.trivial_accept) { if (minz > (sw32_r_aliastransition + (pmdl->size * sw32_r_resfudge))) { - currententity->trivial_accept |= 2; + currententity->visibility.trivial_accept |= 2; } } @@ -366,9 +367,11 @@ sw32_R_AliasSetUpTransform (int trivial_accept) static float tmatrix[3][4]; static float viewmatrix[3][4]; - VectorCopy (currententity->transform + 0, alias_forward); - VectorNegate (currententity->transform + 4, alias_right); - VectorCopy (currententity->transform + 8, alias_up); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], alias_forward); + VectorNegate (mat[1], alias_right); + VectorCopy (mat[2], alias_up); tmatrix[0][0] = pmdl->scale[0]; tmatrix[1][1] = pmdl->scale[1]; @@ -543,7 +546,7 @@ R_AliasSetupSkin (void) { int skinnum; - skinnum = currententity->skinnum; + skinnum = currententity->renderer.skinnum; if ((skinnum >= pmdl->numskins) || (skinnum < 0)) { Sys_MaskPrintf (SYS_DEV, "R_AliasSetupSkin: no such skin # %d\n", skinnum); @@ -559,16 +562,16 @@ R_AliasSetupSkin (void) sw32_r_affinetridesc.skinheight = pmdl->skinheight; sw32_acolormap = vid.colormap8; - if (currententity->skin) { + if (currententity->renderer.skin) { tex_t *base; - base = currententity->skin->texels; + base = currententity->renderer.skin->texels; if (base) { sw32_r_affinetridesc.pskin = base->data; sw32_r_affinetridesc.skinwidth = base->width; sw32_r_affinetridesc.skinheight = base->height; } - sw32_acolormap = currententity->skin->colormap; + sw32_acolormap = currententity->renderer.skin->colormap; } } @@ -611,7 +614,7 @@ R_AliasSetupFrame (void) { maliasframedesc_t *frame; - frame = R_AliasGetFramedesc (currententity->frame, paliashdr); + frame = R_AliasGetFramedesc (currententity->animation.frame, paliashdr); sw32_r_apverts = (trivertx_t *) ((byte *) paliashdr + frame->frame); } @@ -624,8 +627,8 @@ sw32_R_AliasDrawModel (alight_t *plighting) sw32_r_amodels_drawn++; - if (!(paliashdr = currententity->model->aliashdr)) - paliashdr = Cache_Get (¤tentity->model->cache); + if (!(paliashdr = currententity->renderer.model->aliashdr)) + paliashdr = Cache_Get (¤tentity->renderer.model->cache); pmdl = (mdl_t *) ((byte *) paliashdr + paliashdr->model); size = (CACHE_SIZE - 1) @@ -641,7 +644,7 @@ sw32_R_AliasDrawModel (alight_t *plighting) sw32_pauxverts = (auxvert_t *) &pfinalverts[pmdl->numverts + 1]; R_AliasSetupSkin (); - sw32_R_AliasSetUpTransform (currententity->trivial_accept); + sw32_R_AliasSetUpTransform (currententity->visibility.trivial_accept); R_AliasSetupLighting (plighting); R_AliasSetupFrame (); @@ -663,11 +666,13 @@ sw32_R_AliasDrawModel (alight_t *plighting) else sw32_ziscale = (float) 0x8000 *(float) 0x10000 *3.0; - if (currententity->trivial_accept) + if (currententity->visibility.trivial_accept) { R_AliasPrepareUnclippedPoints (); - else + } else { R_AliasPreparePoints (); + } - if (!currententity->model->aliashdr) - Cache_Release (¤tentity->model->cache); + if (!currententity->renderer.model->aliashdr) { + Cache_Release (¤tentity->renderer.model->cache); + } } diff --git a/libs/video/renderer/sw32/sw32_rbsp.c b/libs/video/renderer/sw32/sw32_rbsp.c index 521e70cd5..1f62b381e 100644 --- a/libs/video/renderer/sw32/sw32_rbsp.c +++ b/libs/video/renderer/sw32/sw32_rbsp.c @@ -36,6 +36,7 @@ #include "qfalloca.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -80,9 +81,11 @@ R_EntityRotate (vec3_t vec) void sw32_R_RotateBmodel (void) { - VectorCopy (currententity->transform + 0, entity_rotation[0]); - VectorCopy (currententity->transform + 4, entity_rotation[1]); - VectorCopy (currententity->transform + 8, entity_rotation[2]); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], entity_rotation[0]); + VectorCopy (mat[1], entity_rotation[1]); + VectorCopy (mat[2], entity_rotation[2]); // rotate modelorg and the transformation matrix R_EntityRotate (modelorg); @@ -300,7 +303,9 @@ sw32_R_DrawSolidClippedSubmodelPolygons (model_t *model) pbedge[j - 1].pnext = NULL; // mark end of edges - R_RecursiveClipBPoly (pbedge, currententity->topnode, psurf); + R_RecursiveClipBPoly (pbedge, + currententity->visibility.topnode, + psurf); } else { Sys_Error ("no edges in bmodel"); } @@ -333,7 +338,8 @@ sw32_R_DrawSubmodelPolygons (model_t *model, int clipflags) // draw the polygon if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - sw32_r_currentkey = ((mleaf_t *) currententity->topnode)->key; + sw32_r_currentkey + = ((mleaf_t *) currententity->visibility.topnode)->key; // FIXME: use bounding-box-based frustum clipping info? sw32_R_RenderFace (psurf, clipflags); @@ -514,7 +520,7 @@ sw32_R_RenderWorld (void) currententity = &r_worldentity; VectorCopy (r_origin, modelorg); - brush = ¤tentity->model->brush; + brush = ¤tentity->renderer.model->brush; r_pcurrentvertbase = brush->vertexes; R_VisitWorldNodes (brush, 15); diff --git a/libs/video/renderer/sw32/sw32_rdraw.c b/libs/video/renderer/sw32/sw32_rdraw.c index b106ab63a..7c1e696be 100644 --- a/libs/video/renderer/sw32/sw32_rdraw.c +++ b/libs/video/renderer/sw32/sw32_rdraw.c @@ -349,7 +349,7 @@ sw32_R_RenderFace (msurface_t *fa, int clipflags) vec3_t p_normal; medge_t *pedges, tedge; clipplane_t *pclip; - mod_brush_t *brush = ¤tentity->model->brush; + mod_brush_t *brush = ¤tentity->renderer.model->brush; // skip out if no more surfs if ((sw32_surface_p) >= sw32_surf_max) { @@ -622,7 +622,7 @@ sw32_R_RenderPoly (msurface_t *fa, int clipflags) polyvert_t pverts[100]; // FIXME: do real number, safely int vertpage, newverts, newpage, lastvert; qboolean visible; - mod_brush_t *brush = ¤tentity->model->brush; + mod_brush_t *brush = ¤tentity->renderer.model->brush; // FIXME: clean this up and make it faster // FIXME: guard against running out of vertices diff --git a/libs/video/renderer/sw32/sw32_riqm.c b/libs/video/renderer/sw32/sw32_riqm.c index b53186bd9..1db5fbbdc 100644 --- a/libs/video/renderer/sw32/sw32_riqm.c +++ b/libs/video/renderer/sw32/sw32_riqm.c @@ -43,6 +43,7 @@ #include "namehack.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/skin.h" @@ -222,9 +223,12 @@ R_IQMSetupLighting (entity_t *ent, alight_t *plighting) r_shadelight *= VID_GRADES; // rotate the lighting vector into the model's frame of reference - r_plightvec[0] = DotProduct (plighting->plightvec, ent->transform + 0); - r_plightvec[1] = DotProduct (plighting->plightvec, ent->transform + 4); - r_plightvec[2] = DotProduct (plighting->plightvec, ent->transform + 8); + mat4f_t mat; + Transform_GetWorldMatrix (ent->transform, mat); + //FIXME vectorize + r_plightvec[0] = DotProduct (plighting->plightvec, mat[0]); + r_plightvec[1] = DotProduct (plighting->plightvec, mat[1]); + r_plightvec[2] = DotProduct (plighting->plightvec, mat[2]); } static void @@ -235,9 +239,11 @@ R_IQMSetUpTransform (int trivial_accept) static float viewmatrix[3][4]; vec3_t forward, left, up; - VectorCopy (currententity->transform + 0, forward); - VectorCopy (currententity->transform + 4, left); - VectorCopy (currententity->transform + 8, up); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], forward); + VectorCopy (mat[1], left); + VectorCopy (mat[2], up); // TODO: can do this with simple matrix rearrangement @@ -284,7 +290,7 @@ void sw32_R_IQMDrawModel (alight_t *plighting) { entity_t *ent = currententity; - model_t *model = ent->model; + model_t *model = ent->renderer.model; iqm_t *iqm = (iqm_t *) model->aliashdr; swiqm_t *sw = (swiqm_t *) iqm->extra_data; int size; @@ -295,7 +301,8 @@ sw32_R_IQMDrawModel (alight_t *plighting) + sizeof (finalvert_t) * (iqm->num_verts + 1) + sizeof (auxvert_t) * iqm->num_verts; blend = R_IQMGetLerpedFrames (ent, iqm); - frame = R_IQMBlendPalette (iqm, ent->pose1, ent->pose2, blend, size, + frame = R_IQMBlendPalette (iqm, ent->animation.pose1, ent->animation.pose2, + blend, size, sw->blend_palette, sw->palette_size); pfinalverts = (finalvert_t *) &frame[sw->palette_size]; @@ -303,7 +310,7 @@ sw32_R_IQMDrawModel (alight_t *plighting) (((intptr_t) &pfinalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); pauxverts = (auxvert_t *) &pfinalverts[iqm->num_verts + 1]; - R_IQMSetUpTransform (ent->trivial_accept); + R_IQMSetUpTransform (ent->visibility.trivial_accept); R_IQMSetupLighting (ent, plighting); @@ -315,7 +322,7 @@ sw32_R_IQMDrawModel (alight_t *plighting) else sw32_ziscale = (float) 0x8000 *(float) 0x10000 *3.0; - if (ent->trivial_accept) + if (ent->visibility.trivial_accept) R_IQMPrepareUnclippedPoints (iqm, sw, frame); else R_IQMPreparePoints (iqm, sw, frame); diff --git a/libs/video/renderer/sw32/sw32_rmain.c b/libs/video/renderer/sw32/sw32_rmain.c index 67c59e2f9..812a43205 100644 --- a/libs/video/renderer/sw32/sw32_rmain.c +++ b/libs/video/renderer/sw32/sw32_rmain.c @@ -42,6 +42,7 @@ #include "QF/cmd.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/locs.h" #include "QF/mathlib.h" #include "QF/render.h" @@ -183,7 +184,7 @@ sw32_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) mod_brush_t *brush = &worldmodel->brush; memset (&r_worldentity, 0, sizeof (r_worldentity)); - r_worldentity.model = worldmodel; + r_worldentity.renderer.model = worldmodel; R_FreeAllEntities (); @@ -369,7 +370,7 @@ R_DrawEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; - switch (currententity->model->type) { + switch (currententity->renderer.model->type) { case mod_sprite: VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); @@ -381,15 +382,16 @@ R_DrawEntitiesOnList (void) VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); - minlight = max (currententity->min_light, currententity->model->min_light); + minlight = max (currententity->renderer.min_light, + currententity->renderer.model->min_light); // see if the bounding box lets us trivially reject, also // sets trivial accept status - currententity->trivial_accept = 0; //FIXME - if (currententity->model->type == mod_iqm//FIXME + currententity->visibility.trivial_accept = 0; //FIXME + if (currententity->renderer.model->type == mod_iqm//FIXME || sw32_R_AliasCheckBBox ()) { // 128 instead of 255 due to clamping below - j = max (R_LightPoint (&r_worldentity.model->brush, + j = max (R_LightPoint (&r_worldentity.renderer.model->brush, currententity->origin), minlight * 128); @@ -415,7 +417,7 @@ R_DrawEntitiesOnList (void) if (lighting.ambientlight + lighting.shadelight > 192) lighting.shadelight = 192 - lighting.ambientlight; - if (currententity->model->type == mod_iqm) + if (currententity->renderer.model->type == mod_iqm) sw32_R_IQMDrawModel (&lighting); else sw32_R_AliasDrawModel (&lighting); @@ -446,7 +448,7 @@ R_DrawViewModel (void) return; currententity = vr_data.view_model; - if (!currententity->model) + if (!currententity->renderer.model) return; VectorCopy (currententity->origin, r_entorigin); @@ -455,9 +457,10 @@ R_DrawViewModel (void) VectorCopy (vup, viewlightvec); VectorNegate (viewlightvec, viewlightvec); - minlight = max (currententity->min_light, currententity->model->min_light); + minlight = max (currententity->renderer.min_light, + currententity->renderer.model->min_light); - j = max (R_LightPoint (&r_worldentity.model->brush, + j = max (R_LightPoint (&r_worldentity.renderer.model->brush, currententity->origin), minlight * 128); r_viewlighting.ambientlight = j; @@ -496,11 +499,12 @@ R_BmodelCheckBBox (model_t *clmodel, float *minmaxs) int i, *pindex, clipflags; vec3_t acceptpt, rejectpt; double d; + mat4f_t mat; clipflags = 0; - if (currententity->transform[0] != 1 || currententity->transform[5] != 1 - || currententity->transform[10] != 1) { + Transform_GetWorldMatrix (currententity->transform, mat); + if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { for (i = 0; i < 4; i++) { d = DotProduct (currententity->origin, sw32_view_clipplanes[i].normal); d -= sw32_view_clipplanes[i].dist; @@ -563,9 +567,9 @@ R_DrawBEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; - switch (currententity->model->type) { + switch (currententity->renderer.model->type) { case mod_brush: - clmodel = currententity->model; + clmodel = currententity->renderer.model; // see if the bounding box lets us trivially reject, also // sets trivial accept status @@ -613,8 +617,9 @@ R_DrawBEntitiesOnList (void) if (sw32_r_drawpolys | sw32_r_drawculledpolys) { sw32_R_ZDrawSubmodelPolys (clmodel); } else { - if (currententity->topnode) { - mnode_t *topnode = currententity->topnode; + if (currententity->visibility.topnode) { + mnode_t *topnode + = currententity->visibility.topnode; if (topnode->contents >= 0) { // not a leaf; has to be clipped to the world @@ -759,7 +764,7 @@ R_RenderView_ (void) #endif R_PushDlights (vec3_origin); - if (!r_worldentity.model) + if (!r_worldentity.renderer.model) Sys_Error ("R_RenderView: NULL worldmodel"); if (!r_dspeeds->int_val) { diff --git a/libs/video/renderer/sw32/sw32_rmisc.c b/libs/video/renderer/sw32/sw32_rmisc.c index 1b329b54f..753268993 100644 --- a/libs/video/renderer/sw32/sw32_rmisc.c +++ b/libs/video/renderer/sw32/sw32_rmisc.c @@ -240,7 +240,7 @@ sw32_R_SetupFrame (void) R_SetFrustum (); // current viewleaf - r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.model); + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.renderer.model); sw32_r_dowarpold = sw32_r_dowarp; sw32_r_dowarp = r_waterwarp->int_val && (r_viewleaf->contents <= diff --git a/libs/video/renderer/sw32/sw32_rpart.c b/libs/video/renderer/sw32/sw32_rpart.c index 1364f5d1b..fc640bc8e 100644 --- a/libs/video/renderer/sw32/sw32_rpart.c +++ b/libs/video/renderer/sw32/sw32_rpart.c @@ -88,7 +88,7 @@ sw32_R_ReadPointFile_f (void) const char *name; char *mapname; - mapname = strdup (r_worldentity.model->path); + mapname = strdup (r_worldentity.renderer.model->path); if (!mapname) Sys_Error ("Can't duplicate mapname!"); QFS_StripExtension (mapname, mapname); diff --git a/libs/video/renderer/sw32/sw32_rsprite.c b/libs/video/renderer/sw32/sw32_rsprite.c index 92be9b51e..9c6cb7221 100644 --- a/libs/video/renderer/sw32/sw32_rsprite.c +++ b/libs/video/renderer/sw32/sw32_rsprite.c @@ -40,6 +40,7 @@ #include +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -242,7 +243,7 @@ R_GetSpriteframe (msprite_t *psprite) int i, numframes, frame; float *pintervals, fullinterval, targettime, time; - frame = currententity->frame; + frame = currententity->animation.frame; if ((frame >= psprite->numframes) || (frame < 0)) { Sys_Printf ("R_DrawSprite: no such frame %d\n", frame); @@ -257,7 +258,7 @@ R_GetSpriteframe (msprite_t *psprite) numframes = pspritegroup->numframes; fullinterval = pintervals[numframes - 1]; - time = vr_data.realtime + currententity->syncbase; + time = vr_data.realtime + currententity->animation.syncbase; // when loading in Mod_LoadSpriteGroup, we guaranteed all interval // values are positive, so we don't have to worry about division by 0 @@ -283,7 +284,7 @@ sw32_R_DrawSprite (void) vec3_t tvec; float dot, angle, sr, cr; - psprite = currententity->model->cache.data; + psprite = currententity->renderer.model->cache.data; sw32_r_spritedesc.pspriteframe = R_GetSpriteframe (psprite); @@ -357,9 +358,11 @@ sw32_R_DrawSprite (void) } else if (psprite->type == SPR_ORIENTED) { // generate the sprite's axes, according to the sprite's world // orientation - VectorCopy (currententity->transform + 0, sw32_r_spritedesc.vpn); - VectorNegate (currententity->transform + 4, sw32_r_spritedesc.vright); - VectorCopy (currententity->transform + 8, sw32_r_spritedesc.vup); + mat4f_t mat; + Transform_GetWorldMatrix (currententity->transform, mat); + VectorCopy (mat[0], r_spritedesc.vpn); + VectorNegate (mat[1], r_spritedesc.vright); + VectorCopy (mat[2], r_spritedesc.vup); } else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) { // generate the sprite's axes, parallel to the viewplane, but rotated // in that plane around the center according to the sprite entity's diff --git a/libs/video/renderer/sw32/sw32_rsurf.c b/libs/video/renderer/sw32/sw32_rsurf.c index decd8c3a7..dfc9c31cc 100644 --- a/libs/video/renderer/sw32/sw32_rsurf.c +++ b/libs/video/renderer/sw32/sw32_rsurf.c @@ -172,7 +172,7 @@ R_BuildLightMap (void) size = smax * tmax; lightmap = surf->samples; - if (!r_worldentity.model->brush.lightdata) { + if (!r_worldentity.renderer.model->brush.lightdata) { for (i = 0; i < size; i++) blocklights[i] = 0; return; diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index cc1905c4a..25a2d9d13 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -45,7 +45,7 @@ #include "QF/cvar.h" #include "QF/darray.h" -#include "QF/dstring.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/skin.h" @@ -121,36 +121,41 @@ Vulkan_DrawAlias (entity_t *ent, vulkan_ctx_t *ctx) { aliasctx_t *actx = ctx->alias_context; aliasframe_t *aframe = &actx->frames.a[ctx->curFrame]; - model_t *model = ent->model; + model_t *model = ent->renderer.model; aliashdr_t *hdr; qfv_alias_skin_t *skin; - float vertex_constants[17]; + struct { + mat4f_t mat; + float blend; + } vertex_constants; byte fragment_constants[3][4]; if (!(hdr = model->aliashdr)) { hdr = Cache_Get (&model->cache); } - memcpy (vertex_constants, ent->transform, sizeof (ent->transform)); - vertex_constants[16] = R_AliasGetLerpedFrames (ent, hdr); + Transform_GetWorldMatrix (ent->transform, vertex_constants.mat); + vertex_constants.blend = R_AliasGetLerpedFrames (ent, hdr); if (0/*XXX ent->skin && ent->skin->tex*/) { //skin = ent->skin->tex; } else { maliasskindesc_t *skindesc; - skindesc = R_AliasGetSkindesc (ent->skinnum, hdr); + skindesc = R_AliasGetSkindesc (ent->renderer.skinnum, hdr); skin = (qfv_alias_skin_t *) ((byte *) hdr + skindesc->skin); } - QuatScale (ent->colormod, 255, fragment_constants[0]); + QuatScale (ent->renderer.colormod, 255, fragment_constants[0]); QuatCopy (skin->colora, fragment_constants[1]); QuatCopy (skin->colorb, fragment_constants[2]); - emit_commands (aframe->cmdSet.a[QFV_aliasDepth], ent->pose1, ent->pose2, - 0, vertex_constants, sizeof (vertex_constants), + emit_commands (aframe->cmdSet.a[QFV_aliasDepth], + ent->animation.pose1, ent->animation.pose2, + 0, &vertex_constants, 17 * sizeof (float), fragment_constants, sizeof (fragment_constants), hdr, ctx); - emit_commands (aframe->cmdSet.a[QFV_aliasGBuffer], ent->pose1, ent->pose2, - skin, vertex_constants, sizeof (vertex_constants), + emit_commands (aframe->cmdSet.a[QFV_aliasGBuffer], + ent->animation.pose1, ent->animation.pose2, + skin, &vertex_constants, 17 * sizeof (float), fragment_constants, sizeof (fragment_constants), hdr, ctx); } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 046ba6c0a..38aa57ee9 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -45,7 +45,7 @@ #include "QF/cvar.h" #include "QF/darray.h" -#include "QF/dstring.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/render.h" #include "QF/sys.h" @@ -275,7 +275,7 @@ Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx) { int i; model_t *m; - mod_brush_t *brush = &r_worldentity.model->brush; + mod_brush_t *brush = &r_worldentity.renderer.model->brush; clear_textures (ctx); init_surface_chains (brush, ctx); @@ -289,7 +289,7 @@ Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx) if (*m->path == '*') continue; // world has already been done, not interested in non-brush models - if (m == r_worldentity.model || m->type != mod_brush) + if (m == r_worldentity.renderer.model || m->type != mod_brush) continue; brush = &m->brush; brush->numsubmodels = 1; // no support for submodels in non-world model @@ -343,7 +343,7 @@ build_surf_displist (model_t **models, msurface_t *fa, int base, brush = &models[~fa->ec_index]->brush; } else { // main or sub model - brush = &r_worldentity.model->brush; + brush = &r_worldentity.renderer.model->brush; } vertices = brush->vertexes; edges = brush->edges; @@ -448,7 +448,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx) } surf = brush->surfaces + j; surf->ec_index = dm - brush->submodels; - if (!surf->ec_index && m != r_worldentity.model) + if (!surf->ec_index && m != r_worldentity.renderer.model) surf->ec_index = -1 - i; // instanced model tex = surf->texinfo->texture->render; // append surf to the texture chain @@ -613,9 +613,12 @@ R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) vec3_t mins, maxs, org; mod_brush_t *brush; - model = e->model; + model = e->renderer.model; brush = &model->brush; - if (e->transform[0] != 1 || e->transform[5] != 1 || e->transform[10] != 1) { + mat4f_t mat; + Transform_GetWorldMatrix (e->transform, mat); + memcpy (e->renderer.full_transform, mat, sizeof (mat));//FIXME + if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { rotated = true; radius = model->radius; if (R_CullSphere (e->origin, radius)) @@ -633,9 +636,9 @@ R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) vec3_t temp; VectorCopy (org, temp); - org[0] = DotProduct (temp, e->transform + 0); - org[1] = DotProduct (temp, e->transform + 4); - org[2] = DotProduct (temp, e->transform + 8); + org[0] = DotProduct (temp, mat[0]); + org[1] = DotProduct (temp, mat[1]); + org[2] = DotProduct (temp, mat[2]); } // calculate dynamic lighting for bmodel if it's not an instanced model @@ -664,7 +667,8 @@ R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) // enqueue the polygon if (((surf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(surf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - chain_surface (brush, surf, e->transform, e->colormod, ctx); + chain_surface (brush, surf, e->renderer.full_transform, + e->renderer.colormod, ctx); } } } @@ -1124,10 +1128,10 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) bframe->index_count = 0; memset (&worldent, 0, sizeof (worldent)); - worldent.model = r_worldentity.model; - brush = &r_worldentity.model->brush; + worldent.renderer.model = r_worldentity.renderer.model; + brush = &r_worldentity.renderer.model->brush; - //vulktex_t *tex = r_worldentity.model->skytexture->render; + //vulktex_t *tex = r_worldentity.renderer.model->skytexture->render; //bctx->skysheet_tex = tex->tex; currententity = &worldent; @@ -1136,7 +1140,7 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) if (r_drawentities->int_val) { entity_t *ent; for (ent = r_ent_queue; ent; ent = ent->next) { - if (ent->model->type != mod_brush) + if (ent->renderer.model->type != mod_brush) continue; currententity = ent; diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index 69916682e..e63ff0b03 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -70,7 +70,7 @@ setup_frame (vulkan_ctx_t *ctx) AngleVectors (r_refdef.viewangles, vpn, vright, vup); R_SetFrustum (); - r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.model); + r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.renderer.model); } static void @@ -114,7 +114,7 @@ R_RenderEntities (vulkan_ctx_t *ctx) entity_t *ent; \ int begun = 0; \ for (ent = r_ent_queue; ent; ent = ent->next) { \ - if (ent->model->type != mod_##type_name) \ + if (ent->renderer.model->type != mod_##type_name) \ continue; \ if (!begun) { \ Vulkan_##Type##Begin (ctx); \ @@ -138,7 +138,7 @@ R_DrawViewModel (void) if (vr_data.inhibit_viewmodel || !r_drawviewmodel->int_val || !r_drawentities->int_val - || !currententity->model) + || !currententity->renderer.model) return; // hack the depth range to prevent view model from poking into walls @@ -207,7 +207,7 @@ Vulkan_NewMap (model_t *worldmodel, struct model_s **models, int num_models, } memset (&r_worldentity, 0, sizeof (r_worldentity)); - r_worldentity.model = worldmodel; + r_worldentity.renderer.model = worldmodel; // Force a vis update r_viewleaf = NULL; diff --git a/nq/source/Makemodule.am b/nq/source/Makemodule.am index 2157cd42b..2da0c7fb4 100644 --- a/nq/source/Makemodule.am +++ b/nq/source/Makemodule.am @@ -45,6 +45,7 @@ nq_cl_plugin_LIBS= \ @client_static_plugin_libs@ nq_client_LIBFILES= \ + libs/entity/libQFentity.la \ libs/video/targets/libQFjs.la \ libs/audio/libQFcd.la \ libs/audio/libQFsound.la diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index ce76ebf71..933097913 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -32,6 +32,7 @@ #include "QF/cmd.h" #include "QF/console.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/input.h" #include "QF/keys.h" #include "QF/msg.h" @@ -179,41 +180,40 @@ CL_LerpPoint (void) void CL_TransformEntity (entity_t *ent, const vec3_t angles, qboolean force) { - vec3_t ang; - vec_t *forward, *left, *up; + union { + quat_t q; + vec4f_t v; + } rotation; + vec4f_t position; + vec4f_t scale; + VectorCopy (ent->origin, position); + position[3] = 1; + VectorSet (ent->scale, ent->scale, ent->scale, scale); + scale[3] = 1; if (VectorIsZero (angles)) { - VectorSet (1, 0, 0, ent->transform + 0); - VectorSet (0, 1, 0, ent->transform + 4); - VectorSet (0, 0, 1, ent->transform + 8); - } else if (force || !VectorCompare (angles, ent->angles)) { - forward = ent->transform + 0; - left = ent->transform + 4; - up = ent->transform + 8; + QuatSet (0, 0, 0, 1, rotation.q); + } else { + vec3_t ang; VectorCopy (angles, ang); - if (ent->model && ent->model->type == mod_alias) { + if (ent->renderer.model && ent->renderer.model->type == mod_alias) { // stupid quake bug // why, oh, why, do alias models pitch in the opposite direction // to everything else? ang[PITCH] = -ang[PITCH]; } - AngleVectors (ang, forward, left, up); - VectorNegate (left, left); // AngleVectors is right-handed + AngleQuat (ang, rotation.q); } - VectorCopy (angles, ent->angles); - ent->transform[3] = 0; - ent->transform[7] = 0; - ent->transform[11] = 0; - VectorCopy (ent->origin, ent->transform + 12); - ent->transform[15] = 1; + Transform_SetLocalTransform (ent->transform, scale, rotation.v, position); } static void CL_ModelEffects (entity_t *ent, int num, int glow_color) { dlight_t *dl; - model_t *model = ent->model; + model_t *model = ent->renderer.model; + // add automatic particle trails if (model->flags & EF_ROCKET) { dl = r_funcs->R_AllocDlight (num); if (dl) { @@ -250,11 +250,12 @@ CL_EntityEffects (int num, entity_t *ent, entity_state_t *state) if (state->effects & EF_BRIGHTFIELD) r_funcs->particles->R_EntityParticles (ent); if (state->effects & EF_MUZZLEFLASH) { - vec_t *fv = ent->transform; - dl = r_funcs->R_AllocDlight (num); if (dl) { - VectorMultAdd (ent->origin, 18, fv, dl->origin); + vec4f_t position = Transform_GetWorldPosition (ent->transform); + vec4f_t fv = Transform_Forward (ent->transform); + position += 18 * fv; + VectorCopy (position, dl->origin); dl->origin[2] += 16; dl->radius = 200 + (rand () & 31); dl->die = cl.time + 0.1; @@ -271,19 +272,24 @@ static void set_entity_model (entity_t *ent, int modelindex) { int i = ent - cl_entities; - ent->model = cl.model_precache[modelindex]; + renderer_t *renderer = &ent->renderer; + animation_t *animation = &ent->animation; + renderer->model = cl.model_precache[modelindex]; // automatic animation (torches, etc) can be either all together // or randomized - if (ent->model) { - if (ent->model->synctype == ST_RAND) - ent->syncbase = (float) (rand () & 0x7fff) / 0x7fff; - else - ent->syncbase = 0.0; + if (renderer->model) { + if (renderer->model->synctype == ST_RAND) { + animation->syncbase = (float) (rand () & 0x7fff) / 0x7fff; + } else { + animation->syncbase = 0.0; + } } else { cl_forcelink[i] = true; // hack to make null model players work } - if (i <= cl.maxclients) - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, i); + animation->nolerp = 1; // don't try to lerp when the model has changed + if (i <= cl.maxclients) { + renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, i); + } } void @@ -291,6 +297,8 @@ CL_RelinkEntities (void) { entity_t *ent; entity_state_t *new, *old; + renderer_t *renderer; + animation_t *animation; float bobjrotate, frac, f, d; int i, j; int entvalid; @@ -326,6 +334,9 @@ CL_RelinkEntities (void) new = &nq_entstates.frame[0 + cl.mindex][i]; old = &nq_entstates.frame[1 - cl.mindex][i]; ent = &cl_entities[i]; + renderer = &ent->renderer; + animation = &ent->animation; + // if the object wasn't included in the last packet, remove it entvalid = cl_msgtime[i] == cl.mtime[0]; if (entvalid && !new->modelindex) { @@ -334,10 +345,11 @@ CL_RelinkEntities (void) entvalid = 0; } if (!entvalid) { - ent->model = NULL; - ent->pose1 = ent->pose2 = -1; - if (ent->efrag) + renderer->model = NULL; + animation->pose1 = animation->pose2 = -1; + if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); // just became empty + } continue; } @@ -348,39 +360,43 @@ CL_RelinkEntities (void) old->modelindex = new->modelindex; set_entity_model (ent, new->modelindex); } - ent->frame = new->frame; + animation->frame = new->frame; if (cl_forcelink[i] || new->colormap != old->colormap) { old->colormap = new->colormap; - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, new->colormap); + renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, + new->colormap); } if (cl_forcelink[i] || new->skinnum != old->skinnum) { old->skinnum = new->skinnum; - ent->skinnum = new->skinnum; + renderer->skinnum = new->skinnum; if (i <= cl.maxclients) { - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, i); + renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, + i); mod_funcs->Skin_SetTranslation (i, cl.scores[i - 1].topcolor, cl.scores[i - 1].bottomcolor); } } ent->scale = new->scale / 16.0; - VectorCopy (ent_colormod[new->colormod], ent->colormod); - ent->colormod[3] = ENTALPHA_DECODE (new->alpha); + VectorCopy (ent_colormod[new->colormod], renderer->colormod); + renderer->colormod[3] = ENTALPHA_DECODE (new->alpha); model_flags = 0; - if (ent->model) - model_flags = ent->model->flags; + if (renderer->model) { + model_flags = renderer->model->flags; + } if (cl_forcelink[i]) { // The entity was not updated in the last message so move to the // final spot - ent->pose1 = ent->pose2 = -1; + animation->pose1 = animation->pose2 = -1; VectorCopy (new->origin, ent->origin); if (!(model_flags & EF_ROTATE)) CL_TransformEntity (ent, new->angles, true); if (i != cl.viewentity || chase_active->int_val) { - if (ent->efrag) + if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); + } r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } VectorCopy (ent->origin, ent->old_origin); @@ -395,7 +411,7 @@ CL_RelinkEntities (void) VectorCopy (new->origin, ent->origin); if (!(model_flags & EF_ROTATE)) CL_TransformEntity (ent, new->angles, true); - ent->pose1 = ent->pose2 = -1; + animation->pose1 = animation->pose2 = -1; } else { vec3_t angles, d; // interpolate the origin and angles @@ -413,7 +429,7 @@ CL_RelinkEntities (void) } } if (i != cl.viewentity || chase_active->int_val) { - if (ent->efrag) { + if (ent->visibility.efrag) { if (!VectorCompare (ent->origin, ent->old_origin)) { r_funcs->R_RemoveEfrags (ent); r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index 739e4a61c..f31256138 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -403,12 +403,13 @@ CL_PrintEntities_f (void) for (i = 0, ent = cl_entities; i < cl.num_entities; i++, ent++) { Sys_Printf ("%3i:", i); - if (!ent->model) { + if (!ent->renderer.model) { Sys_Printf ("EMPTY\n"); continue; } Sys_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n", - ent->model->path, ent->frame, VectorExpand (ent->origin), + ent->renderer.model->path, ent->animation.frame, + VectorExpand (ent->origin), VectorExpand (ent->angles)); } } diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index 3b076b43f..10ac2d4f5 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -433,7 +433,7 @@ CL_ParseServerInfo (void) } // local state - cl_entities[0].model = cl.worldmodel = cl.model_precache[1]; + cl_entities[0].renderer.model = cl.worldmodel = cl.model_precache[1]; if (!centerprint) centerprint = dstring_newstr (); else @@ -766,9 +766,9 @@ CL_ParseClientdata (void) cl.stats[STAT_WEAPONFRAME] |= MSG_ReadByte (net_message) << 8; if (bits & SU_WEAPONALPHA) { byte alpha = MSG_ReadByte (net_message); - cl.viewent.colormod[3] = ENTALPHA_DECODE (alpha); + cl.viewent.renderer.colormod[3] = ENTALPHA_DECODE (alpha); } else { - cl.viewent.colormod[3] = 1.0; + cl.viewent.renderer.colormod[3] = 1.0; } } @@ -785,12 +785,12 @@ CL_ParseStatic (int version) // copy it to the current state //FIXME alpha & lerp - ent->model = cl.model_precache[baseline.modelindex]; - ent->frame = baseline.frame; - ent->skin = 0; - ent->skinnum = baseline.skinnum; - VectorCopy (ent_colormod[baseline.colormod], ent->colormod); - ent->colormod[3] = ENTALPHA_DECODE (baseline.alpha); + ent->renderer.model = cl.model_precache[baseline.modelindex]; + ent->animation.frame = baseline.frame; + ent->renderer.skin = 0; + ent->renderer.skinnum = baseline.skinnum; + VectorCopy (ent_colormod[baseline.colormod], ent->renderer.colormod); + ent->renderer.colormod[3] = ENTALPHA_DECODE (baseline.alpha); ent->scale = baseline.scale / 16.0; VectorCopy (baseline.origin, ent->origin); CL_TransformEntity (ent, baseline.angles, true); @@ -1024,7 +1024,9 @@ CL_ParseServerMessage (void) mod_funcs->Skin_SetTranslation (i + 1, top, bot); cl.scores[i].topcolor = top; cl.scores[i].bottomcolor = bot; - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, i + 1); + ent->renderer.skin + = mod_funcs->Skin_SetColormap (ent->renderer.skin, + i + 1); } break; diff --git a/nq/source/cl_tent.c b/nq/source/cl_tent.c index 2286d829a..3a8a1b899 100644 --- a/nq/source/cl_tent.c +++ b/nq/source/cl_tent.c @@ -38,6 +38,7 @@ #include #include +#include "QF/entity.h" #include "QF/model.h" #include "QF/msg.h" #include "QF/sound.h" @@ -132,12 +133,16 @@ CL_TEnts_Init (void) void CL_Init_Entity (entity_t *ent) { + if (ent->transform) { + Transform_Delete (ent->transform); + } memset (ent, 0, sizeof (*ent)); - ent->skin = 0; - QuatSet (1.0, 1.0, 1.0, 1.0, ent->colormod); + ent->transform = Transform_New (0); + ent->renderer.skin = 0; + QuatSet (1.0, 1.0, 1.0, 1.0, ent->renderer.colormod); ent->scale = 1.0; - ent->pose1 = ent->pose2 = -1; + ent->animation.pose1 = ent->animation.pose2 = -1; } static tent_t * @@ -150,8 +155,10 @@ new_temp_entity (void) temp_entities = malloc (TEMP_BATCH * sizeof (tent_t)); for (i = 0; i < TEMP_BATCH - 1; i++) { temp_entities[i].next = &temp_entities[i + 1]; + temp_entities[i].ent.transform = 0; } temp_entities[i].next = 0; + temp_entities[i].ent.transform = 0; } tent = temp_entities; temp_entities = tent->next; @@ -208,7 +215,7 @@ CL_ClearTEnts (void) for (to = cl_beams; to; to = to->next) { for (t = to->to.beam.tents; t; t = t->next) - t->ent.efrag = 0; + t->ent.visibility.efrag = 0; free_temp_entities (to->to.beam.tents); } free_tent_objects (cl_beams); @@ -216,7 +223,7 @@ CL_ClearTEnts (void) for (to = cl_explosions; to; to = to->next) { for (t = to->to.ex.tent; t; t = t->next) - t->ent.efrag = 0; + t->ent.visibility.efrag = 0; free_temp_entities (to->to.ex.tent); } free_tent_objects (cl_explosions); @@ -231,7 +238,7 @@ beam_clear (beam_t *b) for (t = b->tents; t; t = t->next) { r_funcs->R_RemoveEfrags (&t->ent); - t->ent.efrag = 0; + t->ent.visibility.efrag = 0; } free_temp_entities (b->tents); b->tents = 0; @@ -285,7 +292,7 @@ beam_setup (beam_t *b, qboolean transform) VectorMultAdd (org, d, dist, tent->ent.origin); d += 1.0; - tent->ent.model = b->model; + tent->ent.renderer.model = b->model; ang[PITCH] = pitch; ang[YAW] = yaw; if (transform) { @@ -428,7 +435,7 @@ CL_ParseTEnt (void) //FIXME need better model management if (!cl_spr_explod->cache.data) cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); - ex->tent->ent.model = cl_spr_explod; + ex->tent->ent.renderer.model = cl_spr_explod; CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles, true); break; @@ -573,10 +580,10 @@ CL_UpdateExplosions (void) ex = &(*to)->to.ex; ent = &ex->tent->ent; f = 10 * (cl.time - ex->start); - if (f >= ent->model->numframes) { + if (f >= ent->renderer.model->numframes) { tent_obj_t *_to; r_funcs->R_RemoveEfrags (ent); - ent->efrag = 0; + ent->visibility.efrag = 0; free_temp_entities (ex->tent); _to = *to; *to = _to->next; @@ -586,8 +593,8 @@ CL_UpdateExplosions (void) } to = &(*to)->next; - ent->frame = f; - if (!ent->efrag) + ent->animation.frame = f; + if (!ent->visibility.efrag) r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } } diff --git a/nq/source/cl_view.c b/nq/source/cl_view.c index 71383ff08..132df122f 100644 --- a/nq/source/cl_view.c +++ b/nq/source/cl_view.c @@ -614,7 +614,7 @@ V_CalcIntermissionRefdef (void) VectorCopy (origin, r_data->refdef->vieworg); VectorCopy (angles, r_data->refdef->viewangles); - view->model = NULL; + view->renderer.model = NULL; // always idle in intermission old = v_idlescale->value; @@ -699,9 +699,9 @@ V_CalcRefdef (void) else if (r_data->scr_viewsize->int_val == 80) view->origin[2] += 0.5; - view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; - view->frame = cl.stats[STAT_WEAPONFRAME]; - view->skin = 0; + view->renderer.model = cl.model_precache[cl.stats[STAT_WEAPON]]; + view->animation.frame = cl.stats[STAT_WEAPONFRAME]; + view->renderer.skin = 0; // set up the refresh position VectorAdd (r_data->refdef->viewangles, cl.punchangle, diff --git a/qw/source/Makemodule.am b/qw/source/Makemodule.am index 553a32f65..739789020 100644 --- a/qw/source/Makemodule.am +++ b/qw/source/Makemodule.am @@ -87,6 +87,7 @@ qw_cl_plugin_LIBS= \ qw_client_LIBS= \ libs/qw/libqw.a \ libs/net/libnet_chan.la \ + libs/entity/libQFentity.la \ libs/console/libQFconsole.la \ libs/video/targets/libQFjs.la \ libs/audio/libQFcd.la \ diff --git a/qw/source/cl_demo.c b/qw/source/cl_demo.c index 6151b6bd0..d063211d4 100644 --- a/qw/source/cl_demo.c +++ b/qw/source/cl_demo.c @@ -758,17 +758,19 @@ demo_start_recording (int track) for (ent = cl_static_entities; ent; ent = ent->unext) { MSG_WriteByte (&buf, svc_spawnstatic); - for (j = 1; j < cl.nummodels; j++) - if (ent->model == cl.model_precache[j]) + for (j = 1; j < cl.nummodels; j++) { + if (ent->renderer.model == cl.model_precache[j]) { break; + } + } if (j == cl.nummodels) MSG_WriteByte (&buf, 0); else MSG_WriteByte (&buf, j); - MSG_WriteByte (&buf, ent->frame); + MSG_WriteByte (&buf, ent->animation.frame); MSG_WriteByte (&buf, 0); - MSG_WriteByte (&buf, ent->skinnum); + MSG_WriteByte (&buf, ent->renderer.skinnum); MSG_WriteCoordAngleV (&buf, ent->origin, ent->angles); if (buf.cursize > MAX_MSGLEN / 2) { diff --git a/qw/source/cl_entparse.c b/qw/source/cl_entparse.c index 6fc04a4c4..2d130574d 100644 --- a/qw/source/cl_entparse.c +++ b/qw/source/cl_entparse.c @@ -482,7 +482,7 @@ CL_ParsePlayerinfo (void) bits = MSG_ReadByte (net_message); if (bits & PF_ALPHA) { val = MSG_ReadByte (net_message); - ent->colormod[3] = val / 255.0; + ent->renderer.colormod[3] = val / 255.0; } if (bits & PF_SCALE) { val = MSG_ReadByte (net_message); @@ -505,7 +505,7 @@ CL_ParsePlayerinfo (void) g = (float) ((val >> 2) & 7) * (1.0 / 7.0); b = (float) (val & 3) * (1.0 / 3.0); } - VectorSet (r, g, b, ent->colormod); + VectorSet (r, g, b, ent->renderer.colormod); } if (bits & PF_FRAME2) { state->pls.frame |= MSG_ReadByte (net_message) << 8; diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 7c95040ed..d294f9981 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -36,6 +36,7 @@ #endif #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/locs.h" #include "QF/msg.h" #include "QF/render.h" @@ -172,40 +173,38 @@ is_gib (entity_state_t *s1) void CL_TransformEntity (entity_t *ent, const vec3_t angles, qboolean force) { - vec3_t ang; - vec_t *forward, *left, *up; + union { + quat_t q; + vec4f_t v; + } rotation; + vec4f_t position; + vec4f_t scale; + VectorCopy (ent->origin, position); + position[3] = 1; + VectorSet (ent->scale, ent->scale, ent->scale, scale); + scale[3] = 1; if (VectorIsZero (angles)) { - VectorSet (1, 0, 0, ent->transform + 0); - VectorSet (0, 1, 0, ent->transform + 4); - VectorSet (0, 0, 1, ent->transform + 8); - } else if (force || !VectorCompare (angles, ent->angles)) { - forward = ent->transform + 0; - left = ent->transform + 4; - up = ent->transform + 8; + QuatSet (0, 0, 0, 1, rotation.q); + } else { + vec3_t ang; VectorCopy (angles, ang); - if (ent->model && ent->model->type == mod_alias) { + if (ent->renderer.model && ent->renderer.model->type == mod_alias) { // stupid quake bug // why, oh, why, do alias models pitch in the opposite direction // to everything else? ang[PITCH] = -ang[PITCH]; } - AngleVectors (ang, forward, left, up); - VectorNegate (left, left); // AngleVectors is right-handed + AngleQuat (ang, rotation.q); } - VectorCopy (angles, ent->angles); - ent->transform[3] = 0; - ent->transform[7] = 0; - ent->transform[11] = 0; - VectorCopy (ent->origin, ent->transform + 12); - ent->transform[15] = 1; + Transform_SetLocalTransform (ent->transform, scale, rotation.v, position); } static void CL_ModelEffects (entity_t *ent, int num, int glow_color) { dlight_t *dl; - model_t *model = ent->model; + model_t *model = ent->renderer.model; // add automatic particle trails if (model->flags & EF_ROCKET) { @@ -239,14 +238,17 @@ CL_ModelEffects (entity_t *ent, int num, int glow_color) static void set_entity_model (entity_t *ent, int modelindex) { - ent->model = cl.model_precache[modelindex]; + renderer_t *renderer = &ent->renderer; + animation_t *animation = &ent->animation; + renderer->model = cl.model_precache[modelindex]; // automatic animation (torches, etc) can be either all together // or randomized - if (ent->model) { - if (ent->model->synctype == ST_RAND) - ent->syncbase = (float) (rand () & 0x7fff) / 0x7fff; - else - ent->syncbase = 0.0; + if (renderer->model) { + if (renderer->model->synctype == ST_RAND) { + animation->syncbase = (float) (rand () & 0x7fff) / 0x7fff; + } else { + animation->syncbase = 0.0; + } } } @@ -257,6 +259,8 @@ CL_LinkPacketEntities (void) float frac, f; entity_t *ent; entity_state_t *new, *old; + renderer_t *renderer; + animation_t *animation; vec3_t delta; frac = 1; @@ -264,14 +268,17 @@ CL_LinkPacketEntities (void) new = &qw_entstates.frame[cl.link_sequence & UPDATE_MASK][i]; old = &qw_entstates.frame[cl.prev_sequence & UPDATE_MASK][i]; ent = &cl_entities[i]; + renderer = &ent->renderer; + animation = &ent->animation; forcelink = cl_entity_valid[0][i] != cl_entity_valid[1][i]; cl_entity_valid[1][i] = cl_entity_valid[0][i]; // if the object wasn't included in the last packet, remove it if (!cl_entity_valid[0][i]) { - ent->model = NULL; - ent->pose1 = ent->pose2 = -1; - if (ent->efrag) + renderer->model = NULL; + animation->pose1 = animation->pose2 = -1; + if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); // just became empty + } continue; } @@ -283,8 +290,9 @@ CL_LinkPacketEntities (void) if (!new->modelindex || (cl_deadbodyfilter->int_val && is_dead_body (new)) || (cl_gibfilter->int_val && is_gib (new))) { - if (ent->efrag) + if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); + } continue; } @@ -295,46 +303,50 @@ CL_LinkPacketEntities (void) old->modelindex = new->modelindex; set_entity_model (ent, new->modelindex); } - ent->frame = new->frame; + animation->frame = new->frame; if (forcelink || new->colormap != old->colormap || new->skinnum != old->skinnum) { old->skinnum = new->skinnum; - ent->skinnum = new->skinnum; + renderer->skinnum = new->skinnum; old->colormap = new->colormap; if (new->colormap && (new->colormap <= MAX_CLIENTS) && cl.players[new->colormap - 1].name && cl.players[new->colormap - 1].name->value[0] && new->modelindex == cl_playerindex) { player_info_t *player = &cl.players[new->colormap - 1]; - ent->skin = mod_funcs->Skin_SetSkin (ent->skin, new->colormap, - player->skinname->value); - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, - new->colormap); + renderer->skin + = mod_funcs->Skin_SetSkin (renderer->skin, new->colormap, + player->skinname->value); + renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, + new->colormap); } else { - ent->skin = mod_funcs->Skin_SetColormap (ent->skin, 0); + renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, + 0); } } ent->scale = new->scale / 16.0; - VectorCopy (ent_colormod[new->colormod], ent->colormod); - ent->colormod[3] = new->alpha / 255.0; + VectorCopy (ent_colormod[new->colormod], renderer->colormod); + renderer->colormod[3] = new->alpha / 255.0; - ent->min_light = 0; - ent->fullbright = 0; + renderer->min_light = 0; + renderer->fullbright = 0; if (new->modelindex == cl_playerindex) { - ent->min_light = min (cl.fbskins, cl_fb_players->value); - if (ent->min_light >= 1.0) - ent->fullbright = 1; + renderer->min_light = min (cl.fbskins, cl_fb_players->value); + if (renderer->min_light >= 1.0) { + renderer->fullbright = 1; + } } if (forcelink) { - ent->pose1 = ent->pose2 = -1; + animation->pose1 = animation->pose2 = -1; VectorCopy (new->origin, ent->origin); - if (!(ent->model->flags & EF_ROTATE)) + if (!(renderer->model->flags & EF_ROTATE)) CL_TransformEntity (ent, new->angles, true); if (i != cl.viewentity || chase_active->int_val) { - if (ent->efrag) + if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); + } r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } VectorCopy (ent->origin, ent->old_origin); @@ -347,14 +359,15 @@ CL_LinkPacketEntities (void) || fabs (delta[2]) > 100) { // assume a teleportation, not a motion VectorCopy (new->origin, ent->origin); - if (!(ent->model->flags & EF_ROTATE)) + if (!(renderer->model->flags & EF_ROTATE)) { CL_TransformEntity (ent, new->angles, true); - ent->pose1 = ent->pose2 = -1; + } + animation->pose1 = animation->pose2 = -1; } else { vec3_t angles, d; // interpolate the origin and angles VectorMultAdd (old->origin, f, delta, ent->origin); - if (!(ent->model->flags & EF_ROTATE)) { + if (!(renderer->model->flags & EF_ROTATE)) { VectorSubtract (new->angles, old->angles, d); for (j = 0; j < 3; j++) { if (d[j] > 180) @@ -367,7 +380,7 @@ CL_LinkPacketEntities (void) } } if (i != cl.viewentity || chase_active->int_val) { - if (ent->efrag) { + if (ent->visibility.efrag) { if (!VectorCompare (ent->origin, ent->old_origin)) { r_funcs->R_RemoveEfrags (ent); r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); @@ -377,11 +390,12 @@ CL_LinkPacketEntities (void) } } } - if (!ent->efrag) + if (!ent->visibility.efrag) { r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + } // rotate binary objects locally - if (ent->model->flags & EF_ROTATE) { + if (renderer->model->flags & EF_ROTATE) { vec3_t angles; angles[PITCH] = 0; angles[YAW] = anglemod (100 * cl.time); @@ -392,8 +406,9 @@ CL_LinkPacketEntities (void) //CL_NewDlight (i, ent->origin, new->effects, 0, 0); if (VectorDistance_fast (old->origin, ent->origin) > (256 * 256)) VectorCopy (ent->origin, old->origin); - if (ent->model->flags & ~EF_ROTATE) + if (renderer->model->flags & ~EF_ROTATE) { CL_ModelEffects (ent, -new->number, new->glow_color); + } } } @@ -414,36 +429,40 @@ CL_AddFlagModels (entity_t *ent, int team, int key) }; float f; entity_t *fent; - vec_t *v_forward, *v_left; - vec3_t ang; - - if (cl_flagindex == -1) - return; - - f = 14.0; - if (ent->frame >= 29 && ent->frame <= 40) { - f = flag_offsets[ent->frame - 29]; - } else if (ent->frame >= 103 && ent->frame <= 118) { - if (ent->frame <= 106) // 103-104 nailattack - f = 20.0; // 105-106 light - else // 107-112 rocketattack - f = 21.0; // 112-118 shotattack - } fent = &cl_flag_ents[key]; - fent->model = cl.model_precache[cl_flagindex]; - fent->skinnum = team; - v_forward = ent->transform + 0; - v_left = ent->transform + 4; + if (cl_flagindex == -1) { + fent->active = 0; + return; + } - VectorMultAdd (ent->origin, -f, v_forward, fent->origin); - VectorMultAdd (fent->origin, -22, v_left, fent->origin); - fent->origin[2] -= 16.0; + fent->active = 1; + f = 14.0; + if (ent->animation.frame >= 29 && ent->animation.frame <= 40) { + f = flag_offsets[ent->animation.frame - 29]; + } else if (ent->animation.frame >= 103 && ent->animation.frame <= 118) { + if (ent->animation.frame <= 106) { // 103-104 nailattack + f = 20.0; // 105-106 light + } else { // 107-112 rocketattack + f = 21.0; // 112-118 shotattack + } + } - VectorCopy (ent->angles, ang); - ang[2] -= 45.0; - CL_TransformEntity (fent, ang, false); + vec4f_t position = { 22, -f, -16, 1}; + + if (!Transform_GetParent (fent->transform)) { + vec4f_t scale = { 1, 1, 1, 1 }; + // -45 degree roll (x is forward) + vec4f_t rotation = { -0.382683432, 0, 0, 0.923879533 }; + Transform_SetParent (fent->transform, ent->transform); + Transform_SetLocalTransform (fent->transform, scale, rotation, + position); + } else { + Transform_SetLocalPosition (fent->transform, position); + } + fent->renderer.model = cl.model_precache[cl_flagindex]; + fent->renderer.skinnum = team; r_funcs->R_EnqueueEntity (fent);//FIXME should use efrag (needs smarter // handling //in the player code) @@ -477,7 +496,7 @@ CL_LinkPlayers (void) for (j = 0, info = cl.players, state = frame->playerstate; j < MAX_CLIENTS; j++, info++, state++) { ent = &cl_player_ents[j]; - if (ent->efrag) + if (ent->visibility.efrag) r_funcs->R_RemoveEfrags (ent); if (state->messagenum != cl.parsecount) continue; // not present this frame @@ -544,26 +563,27 @@ CL_LinkPlayers (void) } ang[ROLL] = V_CalcRoll (ang, state->pls.velocity) * 4.0; - ent->model = cl.model_precache[state->pls.modelindex]; - ent->frame = state->pls.frame; - ent->skinnum = state->pls.skinnum; + ent->renderer.model = cl.model_precache[state->pls.modelindex]; + ent->animation.frame = state->pls.frame; + ent->renderer.skinnum = state->pls.skinnum; CL_TransformEntity (ent, ang, false); - ent->min_light = 0; - ent->fullbright = 0; + ent->renderer.min_light = 0; + ent->renderer.fullbright = 0; if (state->pls.modelindex == cl_playerindex) { //XXX // use custom skin - ent->skin = info->skin; + ent->renderer.skin = info->skin; - ent->min_light = min (cl.fbskins, cl_fb_players->value); + ent->renderer.min_light = min (cl.fbskins, cl_fb_players->value); - if (ent->min_light >= 1.0) - ent->fullbright = 1; + if (ent->renderer.min_light >= 1.0) { + ent->renderer.fullbright = 1; + } } else { // FIXME no team colors on nonstandard player models - ent->skin = 0; + ent->renderer.skin = 0; } // stuff entity in map diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index f38b30537..2523f8feb 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -979,9 +979,9 @@ CL_ParseStatic (void) cl_static_tail = &ent->unext; // copy it to the current state - ent->model = cl.model_precache[es.modelindex]; - ent->frame = es.frame; - ent->skinnum = es.skinnum; + ent->renderer.model = cl.model_precache[es.modelindex]; + ent->animation.frame = es.frame; + ent->renderer.skinnum = es.skinnum; VectorCopy (es.origin, ent->origin); CL_TransformEntity (ent, es.angles, true); diff --git a/qw/source/cl_tent.c b/qw/source/cl_tent.c index c24f1f0bc..e44ec9b3a 100644 --- a/qw/source/cl_tent.c +++ b/qw/source/cl_tent.c @@ -39,6 +39,7 @@ #include #include "QF/console.h" +#include "QF/entity.h" #include "QF/model.h" #include "QF/msg.h" #include "QF/sound.h" @@ -136,12 +137,16 @@ CL_TEnts_Init (void) void CL_Init_Entity (entity_t *ent) { + if (ent->transform) { + Transform_Delete (ent->transform); + } memset (ent, 0, sizeof (*ent)); - ent->skin = 0; - QuatSet (1.0, 1.0, 1.0, 1.0, ent->colormod); + ent->transform = Transform_New (0); + ent->renderer.skin = 0; + QuatSet (1.0, 1.0, 1.0, 1.0, ent->renderer.colormod); ent->scale = 1.0; - ent->pose1 = ent->pose2 = -1; + ent->animation.pose1 = ent->animation.pose2 = -1; } static tent_t * @@ -154,8 +159,10 @@ new_temp_entity (void) temp_entities = malloc (TEMP_BATCH * sizeof (tent_t)); for (i = 0; i < TEMP_BATCH - 1; i++) { temp_entities[i].next = &temp_entities[i + 1]; + temp_entities[i].ent.transform = 0; } temp_entities[i].next = 0; + temp_entities[i].ent.transform = 0; } tent = temp_entities; temp_entities = tent->next; @@ -211,16 +218,18 @@ CL_ClearTEnts (void) tent_obj_t *to; for (to = cl_beams; to; to = to->next) { - for (t = to->to.beam.tents; t; t = t->next) - t->ent.efrag = 0; + for (t = to->to.beam.tents; t; t = t->next) { + t->ent.visibility.efrag = 0; + } free_temp_entities (to->to.beam.tents); } free_tent_objects (cl_beams); cl_beams = 0; for (to = cl_explosions; to; to = to->next) { - for (t = to->to.ex.tent; t; t = t->next) - t->ent.efrag = 0; + for (t = to->to.ex.tent; t; t = t->next) { + t->ent.visibility.efrag = 0; + } free_temp_entities (to->to.ex.tent); } free_tent_objects (cl_explosions); @@ -235,7 +244,7 @@ beam_clear (beam_t *b) for (t = b->tents; t; t = t->next) { r_funcs->R_RemoveEfrags (&t->ent); - t->ent.efrag = 0; + t->ent.visibility.efrag = 0; } free_temp_entities (b->tents); b->tents = 0; @@ -289,7 +298,7 @@ beam_setup (beam_t *b, qboolean transform) VectorMultAdd (org, d, dist, tent->ent.origin); d += 1.0; - tent->ent.model = b->model; + tent->ent.renderer.model = b->model; ang[PITCH] = pitch; ang[YAW] = yaw; if (transform) { @@ -432,7 +441,7 @@ CL_ParseTEnt (void) //FIXME need better model management if (!cl_spr_explod->cache.data) cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); - ex->tent->ent.model = cl_spr_explod; + ex->tent->ent.renderer.model = cl_spr_explod; CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles, true); break; @@ -580,10 +589,10 @@ CL_UpdateExplosions (void) ex = &(*to)->to.ex; ent = &ex->tent->ent; f = 10 * (cl.time - ex->start); - if (f >= ent->model->numframes) { + if (f >= ent->renderer.model->numframes) { tent_obj_t *_to; r_funcs->R_RemoveEfrags (ent); - ent->efrag = 0; + ent->visibility.efrag = 0; free_temp_entities (ex->tent); _to = *to; *to = _to->next; @@ -593,9 +602,10 @@ CL_UpdateExplosions (void) } to = &(*to)->next; - ent->frame = f; - if (!ent->efrag) + ent->animation.frame = f; + if (!ent->visibility.efrag) { r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + } } } @@ -613,7 +623,7 @@ CL_ClearProjectiles (void) for (tent = cl_projectiles; tent; tent = tent->next) { r_funcs->R_RemoveEfrags (&tent->ent); - tent->ent.efrag = 0; + tent->ent.visibility.efrag = 0; } free_temp_entities (cl_projectiles); cl_projectiles = 0; @@ -648,8 +658,8 @@ CL_ParseProjectiles (qboolean nail2) tail = &tent->next; pr = &tent->ent; - pr->model = cl.model_precache[cl_spikeindex]; - pr->skin = 0; + pr->renderer.model = cl.model_precache[cl_spikeindex]; + pr->renderer.skin = 0; pr->origin[0] = ((bits[0] + ((bits[1] & 15) << 8)) << 1) - 4096; pr->origin[1] = (((bits[1] >> 4) + (bits[2] << 4)) << 1) - 4096; pr->origin[2] = ((bits[3] + ((bits[4] & 15) << 8)) << 1) - 4096; diff --git a/qw/source/cl_view.c b/qw/source/cl_view.c index 4ad5da14f..59e7920cd 100644 --- a/qw/source/cl_view.c +++ b/qw/source/cl_view.c @@ -617,7 +617,7 @@ V_CalcIntermissionRefdef (void) VectorCopy (origin, r_data->refdef->vieworg); VectorCopy (angles, r_data->refdef->viewangles); - view->model = NULL; + view->renderer.model = NULL; // always idle in intermission old = v_idlescale->value; @@ -700,12 +700,13 @@ V_CalcRefdef (void) else if (r_data->scr_viewsize->int_val == 80) view->origin[2] += 0.5; - if (view_message->pls.flags & (PF_GIB | PF_DEAD)) - view->model = NULL; - else - view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; - view->frame = view_message->pls.weaponframe; - view->skin = 0; + if (view_message->pls.flags & (PF_GIB | PF_DEAD)) { + view->renderer.model = NULL; + } else { + view->renderer.model = cl.model_precache[cl.stats[STAT_WEAPON]]; + } + view->animation.frame = view_message->pls.weaponframe; + view->renderer.skin = 0; // set up the refresh position VectorAdd (r_data->refdef->viewangles, cl.punchangle, diff --git a/ruamoko/qwaq/Makemodule.am b/ruamoko/qwaq/Makemodule.am index bcb97af94..781db5c76 100644 --- a/ruamoko/qwaq/Makemodule.am +++ b/ruamoko/qwaq/Makemodule.am @@ -65,6 +65,7 @@ qwaq_cl_plugin_libs= \ @client_static_plugin_libs@ qwaq_client_libs= \ + $(top_builddir)/libs/entity/libQFentity.la \ $(top_builddir)/libs/console/libQFconsole.la \ $(top_builddir)/libs/video/targets/libQFjs.la \ $(top_builddir)/libs/audio/libQFcd.la \ From 098ceed5ff6213e515259ddcee3b5e024aab544f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Mar 2021 18:00:16 +0900 Subject: [PATCH 387/435] [client] Merge nq and qw temp entity handling This finally gets cl_tent merged away. --- include/client/entities.h | 3 + include/client/temp_entities.h | 119 ++++ libs/client/Makemodule.am | 4 +- libs/client/cl_entities.c | 34 + .../client/cl_temp_entities.c | 448 ++++++++----- nq/include/client.h | 10 - nq/source/Makemodule.am | 2 +- nq/source/cl_ents.c | 40 +- nq/source/cl_main.c | 8 +- nq/source/cl_parse.c | 15 +- nq/source/cl_tent.c | 630 ------------------ nq/source/cl_view.c | 2 +- qw/include/Makemodule.am | 1 - qw/include/cl_ents.h | 4 +- qw/include/cl_parse.h | 1 - qw/include/cl_tent.h | 38 -- qw/source/Makemodule.am | 2 +- qw/source/cl_entparse.c | 3 +- qw/source/cl_ents.c | 49 +- qw/source/cl_main.c | 3 +- qw/source/cl_parse.c | 21 +- qw/source/cl_view.c | 2 +- 22 files changed, 482 insertions(+), 957 deletions(-) create mode 100644 include/client/temp_entities.h rename qw/source/cl_tent.c => libs/client/cl_temp_entities.c (54%) delete mode 100644 nq/source/cl_tent.c delete mode 100644 qw/include/cl_tent.h diff --git a/include/client/entities.h b/include/client/entities.h index ae046b8c4..1dba394d6 100644 --- a/include/client/entities.h +++ b/include/client/entities.h @@ -67,4 +67,7 @@ extern entstates_t qw_entstates; extern vec3_t ent_colormod[256]; +struct entity_s; +void CL_TransformEntity (struct entity_s *ent, const vec3_t angles); + #endif//__client_entities_h diff --git a/include/client/temp_entities.h b/include/client/temp_entities.h new file mode 100644 index 000000000..c4dbc0868 --- /dev/null +++ b/include/client/temp_entities.h @@ -0,0 +1,119 @@ +/* + temp_entities.h + + Temporary entity management + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/3/10 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __client_temp_entities_h +#define __client_temp_entities_h + +#include "QF/simd/vec4f.h" + +typedef enum TE_Effect { + TE_NoEffect, // for invalid nq/qw -> qf mapping + TE_Beam, // grappling hook beam + TE_Blood, // bullet hitting body + TE_Explosion, // rocket explosion + TE_Explosion2, // color mapped explosion + TE_Explosion3, // Nehahra colored light explosion + TE_Gunshot1, // NQ gunshot (20 particles) + TE_Gunshot2, // QW gunshot (has particle count) + TE_KnightSpike, // spike hitting wall + TE_LavaSplash, + TE_Lightning1, // lightning bolts + TE_Lightning2, // lightning bolts + TE_Lightning3, // lightning bolts + TE_Lightning4, // Nehahra lightning + TE_LightningBlood, // lightning hitting body + TE_Spike, // spike hitting wall + TE_SuperSpike, // super spike hitting wall + TE_TarExplosion, // tarbaby explosion + TE_Teleport, + TE_WizSpike, // spike hitting wall +} TE_Effect; + +typedef enum TE_nqEffect { + TE_nqSpike, + TE_nqSuperSpike, + TE_nqGunshot, + TE_nqExplosion, + TE_nqTarExplosion, + TE_nqLightning1, + TE_nqLightning2, + TE_nqWizSpike, + TE_nqKnightSpike, + TE_nqLightning3, + TE_nqLavaSplash, + TE_nqTeleport, + TE_nqExplosion2, + TE_nqBeam, + TE_nqExplosion3 = 16, + TE_nqLightning4, +} TE_nqEffect; + +typedef enum TE_qwEffect { + TE_qwSpike, + TE_qwSuperSpike, + TE_qwGunshot, + TE_qwExplosion, + TE_qwTarExplosion, + TE_qwLightning1, + TE_qwLightning2, + TE_qwWizSpike, + TE_qwKnightSpike, + TE_qwLightning3, + TE_qwLavaSplash, + TE_qwTeleport, + TE_qwBlood, + TE_qwLightningBlood, + TE_qwExplosion2 = 16, + TE_qwBeam, +} TE_qwEffect; + +//FIXME find a better way to get this info from the parser +typedef struct TEntContext_s { + vec4f_t simorg; + struct model_s *worldModel; + int playerEntity; +} TEntContext_t; + +struct msg_s; +struct entity_s; + +void CL_TEnts_Init (void); +void CL_Init_Entity (struct entity_s *ent); +void CL_ClearTEnts (void); +void CL_UpdateTEnts (double time, TEntContext_t *ctx); +void CL_ParseTEnt_nq (struct msg_s *net_message, double time, + TEntContext_t *ctx); +void CL_ParseTEnt_qw (struct msg_s *net_message, double time, + TEntContext_t *ctx); +void CL_ParseParticleEffect (struct msg_s *net_message); +void CL_ClearProjectiles (void); +void CL_ParseProjectiles (struct msg_s *net_message, qboolean nail2, + TEntContext_t *ctx); + +#endif//__client_temp_entities_h diff --git a/libs/client/Makemodule.am b/libs/client/Makemodule.am index 962430a4b..9129b9dbd 100644 --- a/libs/client/Makemodule.am +++ b/libs/client/Makemodule.am @@ -3,4 +3,6 @@ noinst_LTLIBRARIES += libs/client/libQFclient.la libs_client_libQFclient_la_LDFLAGS= @STATIC@ libs_client_libQFclient_la_LIBADD= libs/gamecode/libQFgamecode.la libs/util/libQFutil.la libs_client_libQFclient_la_SOURCES= \ - libs/client/cl_entities.c + libs/client/cl_temp_entities.c \ + libs/client/cl_entities.c \ + $e diff --git a/libs/client/cl_entities.c b/libs/client/cl_entities.c index 01397321a..837cfbe60 100644 --- a/libs/client/cl_entities.c +++ b/libs/client/cl_entities.c @@ -31,6 +31,10 @@ # include "config.h" #endif +#include "QF/entity.h" +#include "QF/render.h" //FIXME for entity_t +#include "QF/simd/vec4f.h" + #include "client/entities.h" /* QW has a max of 512 entities and wants 64 frames of data per entity, plus @@ -340,3 +344,33 @@ vec3_t ent_colormod[256] = { {1, 1, 0.666667}, {1, 1, 1} }; + +void +CL_TransformEntity (entity_t *ent, const vec3_t angles) +{ + union { + quat_t q; + vec4f_t v; + } rotation; + vec4f_t position; + vec4f_t scale; + + VectorCopy (ent->origin, position); + position[3] = 1; + VectorSet (ent->scale, ent->scale, ent->scale, scale); + scale[3] = 1; + if (VectorIsZero (angles)) { + QuatSet (0, 0, 0, 1, rotation.q); + } else { + vec3_t ang; + VectorCopy (angles, ang); + if (ent->renderer.model && ent->renderer.model->type == mod_alias) { + // stupid quake bug + // why, oh, why, do alias models pitch in the opposite direction + // to everything else? + ang[PITCH] = -ang[PITCH]; + } + AngleQuat (ang, rotation.q); + } + Transform_SetLocalTransform (ent->transform, scale, rotation.v, position); +} diff --git a/qw/source/cl_tent.c b/libs/client/cl_temp_entities.c similarity index 54% rename from qw/source/cl_tent.c rename to libs/client/cl_temp_entities.c index e44ec9b3a..a0627e42d 100644 --- a/qw/source/cl_tent.c +++ b/libs/client/cl_temp_entities.c @@ -1,9 +1,12 @@ /* - cl_tent.c + cl_temp_entities.c - client side temporary entities + Client side temporary entity management - Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/3/10 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -27,7 +30,6 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif - #ifdef HAVE_STRING_H # include #endif @@ -35,23 +37,16 @@ # include #endif -#include -#include - -#include "QF/console.h" #include "QF/entity.h" -#include "QF/model.h" #include "QF/msg.h" +#include "QF/quakefs.h" +#include "QF/render.h" #include "QF/sound.h" -#include "QF/sys.h" -#include "compat.h" +#include "QF/plugin/vid_render.h" //FIXME -#include "qw/include/cl_ents.h" -#include "qw/include/cl_main.h" -#include "qw/include/cl_parse.h" -#include "qw/include/cl_tent.h" -#include "qw/include/client.h" +#include "client/entities.h" +#include "client/temp_entities.h" typedef struct tent_s { struct tent_s *next; @@ -94,28 +89,29 @@ static tent_t *cl_projectiles; static sfx_t *cl_sfx_wizhit; static sfx_t *cl_sfx_knighthit; static sfx_t *cl_sfx_tink1; -static sfx_t *cl_sfx_ric1; -static sfx_t *cl_sfx_ric2; -static sfx_t *cl_sfx_ric3; static sfx_t *cl_sfx_r_exp3; +static sfx_t *cl_sfx_ric[4]; static model_t *cl_mod_beam; static model_t *cl_mod_bolt; static model_t *cl_mod_bolt2; static model_t *cl_mod_bolt3; static model_t *cl_spr_explod; +static model_t *cl_spike; static void CL_TEnts_Precache (int phase) { - if (!phase) + if (!phase) { return; + } cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav"); cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav"); cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav"); - cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav"); - cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav"); - cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav"); + cl_sfx_ric[3] = S_PrecacheSound ("weapons/ric1.wav"); + cl_sfx_ric[2] = S_PrecacheSound ("weapons/ric2.wav"); + cl_sfx_ric[1] = S_PrecacheSound ("weapons/ric3.wav"); + cl_sfx_ric[0] = cl_sfx_ric[1]; cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav"); cl_mod_bolt = Mod_ForName ("progs/bolt.mdl", true); @@ -123,8 +119,11 @@ CL_TEnts_Precache (int phase) cl_mod_bolt3 = Mod_ForName ("progs/bolt3.mdl", true); cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); cl_mod_beam = Mod_ForName ("progs/beam.mdl", false); - if (!cl_mod_beam) + cl_spike = Mod_ForName ("progs/spike.mdl", false); + + if (!cl_mod_beam) { cl_mod_beam = cl_mod_bolt; + } } void @@ -214,23 +213,23 @@ free_tent_objects (tent_obj_t *tobjs) void CL_ClearTEnts (void) { - tent_t *t; - tent_obj_t *to; + tent_t *tent; + tent_obj_t *tobj; - for (to = cl_beams; to; to = to->next) { - for (t = to->to.beam.tents; t; t = t->next) { - t->ent.visibility.efrag = 0; + for (tobj = cl_beams; tobj; tobj = tobj->next) { + for (tent = tobj->to.beam.tents; tent; tent = tent->next) { + tent->ent.visibility.efrag = 0; } - free_temp_entities (to->to.beam.tents); + free_temp_entities (tobj->to.beam.tents); } free_tent_objects (cl_beams); cl_beams = 0; - for (to = cl_explosions; to; to = to->next) { - for (t = to->to.ex.tent; t; t = t->next) { - t->ent.visibility.efrag = 0; + for (tobj = cl_explosions; tobj; tobj = tobj->next) { + for (tent = tobj->to.ex.tent; tent; tent = tent->next) { + tent->ent.visibility.efrag = 0; } - free_temp_entities (to->to.ex.tent); + free_temp_entities (tobj->to.ex.tent); } free_tent_objects (cl_explosions); cl_explosions = 0; @@ -252,7 +251,7 @@ beam_clear (beam_t *b) } static inline void -beam_setup (beam_t *b, qboolean transform) +beam_setup (beam_t *b, qboolean transform, double time, TEntContext_t *ctx) { tent_t *tent; float forward, pitch, yaw, d; @@ -287,8 +286,7 @@ beam_setup (beam_t *b, qboolean transform) ent_count = ceil (d / 30); d = 0; - seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) % - BEAM_SEED_INTERVAL); + seed = b->seed + ((int) (time * BEAM_SEED_INTERVAL) % BEAM_SEED_INTERVAL); ang[ROLL] = 0; while (ent_count--) { @@ -304,15 +302,15 @@ beam_setup (beam_t *b, qboolean transform) if (transform) { seed = seed * BEAM_SEED_PRIME; ang[ROLL] = seed % 360; - CL_TransformEntity (&tent->ent, ang, true); + CL_TransformEntity (&tent->ent, ang); } VectorCopy (ang, tent->ent.angles); - r_funcs->R_AddEfrags (&cl.worldmodel->brush, &tent->ent); + r_funcs->R_AddEfrags (&ctx->worldModel->brush, &tent->ent); } } static void -CL_ParseBeam (model_t *m) +CL_ParseBeam (qmsg_t *net_message, model_t *m, double time, TEntContext_t *ctx) { tent_obj_t *to; beam_t *b; @@ -326,9 +324,11 @@ CL_ParseBeam (model_t *m) to = 0; if (ent) { - for (to = cl_beams; to; to = to->next) - if (to->to.beam.entity == ent) + for (to = cl_beams; to; to = to->next) { + if (to->to.beam.entity == ent) { break; + } + } } if (!to) { to = new_tent_object (); @@ -341,93 +341,60 @@ CL_ParseBeam (model_t *m) beam_clear (b); b->model = m; - b->endtime = cl.time + 0.2; + b->endtime = time + 0.2; b->seed = rand (); VectorCopy (end, b->end); - if (b->entity != cl.viewentity) { + if (b->entity != ctx->playerEntity) { // this will be done in CL_UpdateBeams VectorCopy (start, b->start); - beam_setup (b, true); + beam_setup (b, true, time, ctx); } } -void -CL_ParseTEnt (void) +static void +parse_tent (qmsg_t *net_message, double time, TEntContext_t *ctx, + TE_Effect type) { - byte type; dlight_t *dl; tent_obj_t *to; explosion_t *ex; int colorStart, colorLength; - int cnt = -1; - vec3_t pos; - sfx_t *spike_sound[] = { - cl_sfx_ric3, cl_sfx_ric3, cl_sfx_ric2, cl_sfx_ric1, - }; + quat_t color; + vec3_t position; + int count; + const char *name; - type = MSG_ReadByte (net_message); switch (type) { - case TE_WIZSPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_WizSpikeEffect (pos); - S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1); + case TE_NoEffect: + // invalid mapping, can't do anything break; - - case TE_KNIGHTSPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_KnightSpikeEffect (pos); - S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1); + case TE_Beam: + CL_ParseBeam (net_message, cl_mod_beam, time, ctx); break; - - case TE_SPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_SpikeEffect (pos); - { - int i; - sfx_t *sound; - - i = (rand () % 20) - 16; - if (i >= 0) - sound = spike_sound[i]; - else - sound = cl_sfx_tink1; - S_StartSound (-1, 0, sound, pos, 1, 1); - } + case TE_Blood: + count = MSG_ReadByte (net_message) * 20; + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_BloodPuffEffect (position, count); break; + case TE_Explosion: + MSG_ReadCoordV (net_message, position); - case TE_SUPERSPIKE: // super spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_SuperSpikeEffect (pos); - { - int i; - sfx_t *sound; - - i = (rand () % 20) - 16; - if (i >= 0) - sound = spike_sound[i]; - else - sound = cl_sfx_tink1; - S_StartSound (-1, 0, sound, pos, 1, 1); - } - break; - - case TE_EXPLOSION: // rocket explosion // particles - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_ParticleExplosion (pos); + r_funcs->particles->R_ParticleExplosion (position); // light dl = r_funcs->R_AllocDlight (0); if (dl) { - VectorCopy (pos, dl->origin); + VectorCopy (position, dl->origin); dl->radius = 350; - dl->die = cl.time + 0.5; + dl->die = time + 0.5; dl->decay = 300; QuatSet (0.86, 0.31, 0.24, 0.7, dl->color); + //FIXME? nq: QuatSet (1.0, 0.5, 0.25, 0.7, dl->color); } // sound - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); + S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1); // sprite to = new_tent_object (); @@ -436,105 +403,201 @@ CL_ParseTEnt (void) ex = &to->to.ex; ex->tent = new_temp_entity (); - VectorCopy (pos, ex->tent->ent.origin); - ex->start = cl.time; + VectorCopy (position, ex->tent->ent.origin); + ex->start = time; //FIXME need better model management - if (!cl_spr_explod->cache.data) + if (!cl_spr_explod->cache.data) { cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); + } ex->tent->ent.renderer.model = cl_spr_explod; - CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles, true); + CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles); break; - - case TE_TAREXPLOSION: // tarbaby explosion - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_BlobExplosion (pos); - - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - break; - - case TE_LIGHTNING1: // lightning bolts - CL_ParseBeam (cl_mod_bolt); - break; - - case TE_LIGHTNING2: // lightning bolts - CL_ParseBeam (cl_mod_bolt2); - break; - - case TE_LIGHTNING3: // lightning bolts - CL_ParseBeam (cl_mod_bolt3); - break; - - // PGM 01/21/97 - case TE_BEAM: // grappling hook beam - CL_ParseBeam (cl_mod_beam); - break; - // PGM 01/21/97 - - case TE_LAVASPLASH: - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_LavaSplash (pos); - break; - - case TE_TELEPORT: - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_TeleportSplash (pos); - break; - - case TE_EXPLOSION2: // color mapped explosion - MSG_ReadCoordV (net_message, pos); + case TE_Explosion2: + MSG_ReadCoordV (net_message, position); colorStart = MSG_ReadByte (net_message); colorLength = MSG_ReadByte (net_message); - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - r_funcs->particles->R_ParticleExplosion2 (pos, colorStart, + S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1); + r_funcs->particles->R_ParticleExplosion2 (position, colorStart, colorLength); dl = r_funcs->R_AllocDlight (0); if (!dl) break; - VectorCopy (pos, dl->origin); + VectorCopy (position, dl->origin); dl->radius = 350; - dl->die = cl.time + 0.5; + dl->die = time + 0.5; dl->decay = 300; colorStart = (colorStart + (rand () % colorLength)) * 3; VectorScale (&r_data->vid->palette[colorStart], 1.0 / 255.0, dl->color); dl->color[3] = 0.7; break; - - case TE_GUNSHOT: // bullet hitting wall - cnt = MSG_ReadByte (net_message) * 20; - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_GunshotEffect (pos, cnt); + case TE_Explosion3: + MSG_ReadCoordV (net_message, position); + MSG_ReadCoordV (net_message, color); // OUCH! + color[3] = 0.7; + r_funcs->particles->R_ParticleExplosion (position); + S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1); + dl = r_funcs->R_AllocDlight (0); + if (dl) { + VectorCopy (position, dl->origin); + dl->radius = 350; + dl->die = time + 0.5; + dl->decay = 300; + QuatCopy (color, dl->color); + } break; - - case TE_BLOOD: // bullet hitting body - cnt = MSG_ReadByte (net_message) * 20; - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_BloodPuffEffect (pos, cnt); + case TE_Gunshot1: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_GunshotEffect (position, 20); break; - - case TE_LIGHTNINGBLOOD: // lightning hitting body - MSG_ReadCoordV (net_message, pos); + case TE_Gunshot2: + count = MSG_ReadByte (net_message) * 20; + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_GunshotEffect (position, count); + break; + case TE_KnightSpike: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_KnightSpikeEffect (position); + S_StartSound (-1, 0, cl_sfx_knighthit, position, 1, 1); + break; + case TE_LavaSplash: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_LavaSplash (position); + break; + case TE_Lightning1: + CL_ParseBeam (net_message, cl_mod_bolt, time, ctx); + break; + case TE_Lightning2: + CL_ParseBeam (net_message, cl_mod_bolt2, time, ctx); + break; + case TE_Lightning3: + CL_ParseBeam (net_message, cl_mod_bolt3, time, ctx); + break; + case TE_Lightning4: + name = MSG_ReadString (net_message); + CL_ParseBeam (net_message, Mod_ForName (name, true), time, ctx); + break; + case TE_LightningBlood: + MSG_ReadCoordV (net_message, position); // light dl = r_funcs->R_AllocDlight (0); if (dl) { - VectorCopy (pos, dl->origin); + VectorCopy (position, dl->origin); dl->radius = 150; - dl->die = cl.time + 0.1; + dl->die = time + 0.1; dl->decay = 200; QuatSet (0.25, 0.40, 0.65, 1, dl->color); } - r_funcs->particles->R_LightningBloodEffect (pos); + r_funcs->particles->R_LightningBloodEffect (position); break; + case TE_Spike: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_SpikeEffect (position); + { + int i; + sfx_t *sound; - default: - Sys_Error ("CL_ParseTEnt: bad type %d", type); + i = (rand () % 20) - 16; + if (i >= 0) { + sound = cl_sfx_ric[i]; + } else { + sound = cl_sfx_tink1; + } + S_StartSound (-1, 0, sound, position, 1, 1); + } + break; + case TE_SuperSpike: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_SuperSpikeEffect (position); + { + int i; + sfx_t *sound; + + i = (rand () % 20) - 16; + if (i >= 0) { + sound = cl_sfx_ric[i]; + } else { + sound = cl_sfx_tink1; + } + S_StartSound (-1, 0, sound, position, 1, 1); + } + break; + case TE_TarExplosion: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_BlobExplosion (position); + + S_StartSound (-1, 0, cl_sfx_r_exp3, position, 1, 1); + break; + case TE_Teleport: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_TeleportSplash (position); + break; + case TE_WizSpike: + MSG_ReadCoordV (net_message, position); + r_funcs->particles->R_WizSpikeEffect (position); + S_StartSound (-1, 0, cl_sfx_wizhit, position, 1, 1); + break; } } +// the effect type is a byte so a max of 256 values +static const TE_Effect nqEffects[256] = { + [TE_nqSpike] = TE_Spike, + [TE_nqSuperSpike] = TE_SuperSpike, + [TE_nqGunshot] = TE_Gunshot1, + [TE_nqExplosion] = TE_Explosion, + [TE_nqTarExplosion] = TE_TarExplosion, + [TE_nqLightning1] = TE_Lightning1, + [TE_nqLightning2] = TE_Lightning2, + [TE_nqWizSpike] = TE_WizSpike, + [TE_nqKnightSpike] = TE_KnightSpike, + [TE_nqLightning3] = TE_Lightning3, + [TE_nqLavaSplash] = TE_LavaSplash, + [TE_nqTeleport] = TE_Teleport, + [TE_nqExplosion2] = TE_Explosion2, + [TE_nqBeam] = TE_Beam, + [TE_nqExplosion3] = TE_Explosion3, + [TE_nqLightning4] = TE_Lightning4, +}; + +void +CL_ParseTEnt_nq (qmsg_t *net_message, double time, TEntContext_t *ctx) +{ + byte type = MSG_ReadByte (net_message); + parse_tent (net_message, time, ctx, nqEffects[type]); +} + +// the effect type is a byte so a max of 256 values +static const TE_Effect qwEffects[256] = { + [TE_qwSpike] = TE_Spike, + [TE_qwSuperSpike] = TE_SuperSpike, + [TE_qwGunshot] = TE_Gunshot2, + [TE_qwExplosion] = TE_Explosion, + [TE_qwTarExplosion] = TE_TarExplosion, + [TE_qwLightning1] = TE_Lightning1, + [TE_qwLightning2] = TE_Lightning2, + [TE_qwWizSpike] = TE_WizSpike, + [TE_qwKnightSpike] = TE_KnightSpike, + [TE_qwLightning3] = TE_Lightning3, + [TE_qwLavaSplash] = TE_LavaSplash, + [TE_qwTeleport] = TE_Teleport, + [TE_qwBlood] = TE_Blood, + [TE_qwLightningBlood] = TE_LightningBlood, + [TE_qwExplosion2] = TE_Explosion2, + [TE_qwBeam] = TE_Beam, +}; + +void +CL_ParseTEnt_qw (qmsg_t *net_message, double time, TEntContext_t *ctx) +{ + byte type = MSG_ReadByte (net_message); + parse_tent (net_message, time, ctx, qwEffects[type]); +} + static void -CL_UpdateBeams (void) +CL_UpdateBeams (double time, TEntContext_t *ctx) { tent_obj_t **to; beam_t *b; @@ -546,7 +609,7 @@ CL_UpdateBeams (void) b = &(*to)->to.beam; if (!b->endtime) continue; - if (!b->model || b->endtime < cl.time) { + if (!b->model || b->endtime < time) { tent_obj_t *_to; b->endtime = 0; beam_clear (b); @@ -559,26 +622,26 @@ CL_UpdateBeams (void) to = &(*to)->next; // if coming from the player, update the start position - if (b->entity == cl.viewentity) { + if (b->entity == ctx->playerEntity) { beam_clear (b); - VectorCopy (cl.simorg, b->start); - beam_setup (b, false); + VectorCopy (ctx->simorg, b->start); + beam_setup (b, false, time, ctx); } - seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) % + seed = b->seed + ((int) (time * BEAM_SEED_INTERVAL) % BEAM_SEED_INTERVAL); // add new entities for the lightning for (t = b->tents; t; t = t->next) { seed = seed * BEAM_SEED_PRIME; t->ent.angles[ROLL] = seed % 360; - CL_TransformEntity (&t->ent, t->ent.angles, true); + CL_TransformEntity (&t->ent, t->ent.angles); } } } static void -CL_UpdateExplosions (void) +CL_UpdateExplosions (double time, TEntContext_t *ctx) { int f; tent_obj_t **to; @@ -588,7 +651,7 @@ CL_UpdateExplosions (void) for (to = &cl_explosions; *to; ) { ex = &(*to)->to.ex; ent = &ex->tent->ent; - f = 10 * (cl.time - ex->start); + f = 10 * (time - ex->start); if (f >= ent->renderer.model->numframes) { tent_obj_t *_to; r_funcs->R_RemoveEfrags (ent); @@ -604,16 +667,39 @@ CL_UpdateExplosions (void) ent->animation.frame = f; if (!ent->visibility.efrag) { - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); + r_funcs->R_AddEfrags (&ctx->worldModel->brush, ent); } } } void -CL_UpdateTEnts (void) +CL_UpdateTEnts (double time, TEntContext_t *ctx) { - CL_UpdateBeams (); - CL_UpdateExplosions (); + CL_UpdateBeams (time, ctx); + CL_UpdateExplosions (time, ctx); +} + +/* + CL_ParseParticleEffect + + Parse an effect out of the server message +*/ +void +CL_ParseParticleEffect (qmsg_t *net_message) +{ + int i, count, color; + vec3_t org, dir; + + MSG_ReadCoordV (net_message, org); + for (i = 0; i < 3; i++) + dir[i] = ((signed char) MSG_ReadByte (net_message)) * (15.0 / 16.0); + count = MSG_ReadByte (net_message); + color = MSG_ReadByte (net_message); + + if (count == 255) + r_funcs->particles->R_ParticleExplosion (org); + else + r_funcs->particles->R_RunParticleEffect (org, dir, color, count); } void @@ -633,7 +719,7 @@ CL_ClearProjectiles (void) Nails are passed as efficient temporary entities */ void -CL_ParseProjectiles (qboolean nail2) +CL_ParseProjectiles (qmsg_t *net_message, qboolean nail2, TEntContext_t *ctx) { tent_t *tent; tent_t *head = 0, **tail = &head; @@ -658,7 +744,7 @@ CL_ParseProjectiles (qboolean nail2) tail = &tent->next; pr = &tent->ent; - pr->renderer.model = cl.model_precache[cl_spikeindex]; + pr->renderer.model = cl_spike; pr->renderer.skin = 0; pr->origin[0] = ((bits[0] + ((bits[1] & 15) << 8)) << 1) - 4096; pr->origin[1] = (((bits[1] >> 4) + (bits[2] << 4)) << 1) - 4096; @@ -666,9 +752,9 @@ CL_ParseProjectiles (qboolean nail2) pr->angles[0] = (bits[4] >> 4) * (360.0 / 16.0); pr->angles[1] = bits[5] * (360.0 / 256.0); pr->angles[2] = 0; - CL_TransformEntity (&tent->ent, tent->ent.angles, true); + CL_TransformEntity (&tent->ent, tent->ent.angles); - r_funcs->R_AddEfrags (&cl.worldmodel->brush, &tent->ent); + r_funcs->R_AddEfrags (&ctx->worldModel->brush, &tent->ent); } *tail = cl_projectiles; diff --git a/nq/include/client.h b/nq/include/client.h index 817bebaf6..07c43ae87 100644 --- a/nq/include/client.h +++ b/nq/include/client.h @@ -304,10 +304,6 @@ void CL_Input_Init (void); void CL_SendCmd (void); void CL_SendMove (usercmd_t *cmd); -void CL_ParseParticleEffect (void); -void CL_ParseTEnt (void); -void CL_UpdateTEnts (void); - void CL_ClearState (void); int CL_ReadFromServer (void); @@ -344,13 +340,7 @@ void V_SetContentsColor (int contents); void V_PrepBlend (void); // cl_tent -void CL_TEnts_Init (void); -void CL_ClearTEnts (void); -void CL_Init_Entity (struct entity_s *ent); -void CL_ParseTEnt (void); void CL_SignonReply (void); -void CL_TransformEntity (struct entity_s *ent, const vec3_t - angles, qboolean force); void CL_RelinkEntities (void); void CL_ClearEnts (void); diff --git a/nq/source/Makemodule.am b/nq/source/Makemodule.am index 2da0c7fb4..6caa9fe32 100644 --- a/nq/source/Makemodule.am +++ b/nq/source/Makemodule.am @@ -70,7 +70,7 @@ nq_server_LIB_DEPS=$(nq_server_LIBFILES) $(nq_common_LIBFILES) nq_source_libnq_client_a_SOURCES= \ nq/source/cl_chase.c nq/source/cl_cmd.c nq/source/cl_demo.c nq/source/cl_ents.c nq/source/cl_input.c nq/source/cl_main.c \ - nq/source/cl_screen.c nq/source/cl_parse.c nq/source/cl_tent.c nq/source/cl_view.c nq/source/sbar.c + nq/source/cl_screen.c nq/source/cl_parse.c nq/source/cl_view.c nq/source/sbar.c nq_source_libnq_server_a_SOURCES= \ nq/source/host.c nq/source/host_cmd.c nq/source/sv_cl_phys.c nq/source/sv_cvar.c nq/source/sv_main.c \ diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index 933097913..3fdd3d0af 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -47,6 +47,8 @@ #include "compat.h" +#include "client/temp_entities.h" + #include "nq/include/chase.h" #include "nq/include/client.h" #include "nq/include/host.h" @@ -177,36 +179,6 @@ CL_LerpPoint (void) return frac; } -void -CL_TransformEntity (entity_t *ent, const vec3_t angles, qboolean force) -{ - union { - quat_t q; - vec4f_t v; - } rotation; - vec4f_t position; - vec4f_t scale; - - VectorCopy (ent->origin, position); - position[3] = 1; - VectorSet (ent->scale, ent->scale, ent->scale, scale); - scale[3] = 1; - if (VectorIsZero (angles)) { - QuatSet (0, 0, 0, 1, rotation.q); - } else { - vec3_t ang; - VectorCopy (angles, ang); - if (ent->renderer.model && ent->renderer.model->type == mod_alias) { - // stupid quake bug - // why, oh, why, do alias models pitch in the opposite direction - // to everything else? - ang[PITCH] = -ang[PITCH]; - } - AngleQuat (ang, rotation.q); - } - Transform_SetLocalTransform (ent->transform, scale, rotation.v, position); -} - static void CL_ModelEffects (entity_t *ent, int num, int glow_color) { @@ -392,7 +364,7 @@ CL_RelinkEntities (void) animation->pose1 = animation->pose2 = -1; VectorCopy (new->origin, ent->origin); if (!(model_flags & EF_ROTATE)) - CL_TransformEntity (ent, new->angles, true); + CL_TransformEntity (ent, new->angles); if (i != cl.viewentity || chase_active->int_val) { if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); @@ -410,7 +382,7 @@ CL_RelinkEntities (void) // assume a teleportation, not a motion VectorCopy (new->origin, ent->origin); if (!(model_flags & EF_ROTATE)) - CL_TransformEntity (ent, new->angles, true); + CL_TransformEntity (ent, new->angles); animation->pose1 = animation->pose2 = -1; } else { vec3_t angles, d; @@ -425,7 +397,7 @@ CL_RelinkEntities (void) d[j] += 360; } VectorMultAdd (old->angles, f, d, angles); - CL_TransformEntity (ent, angles, false); + CL_TransformEntity (ent, angles); } } if (i != cl.viewentity || chase_active->int_val) { @@ -445,7 +417,7 @@ CL_RelinkEntities (void) vec3_t angles; VectorCopy (new->angles, angles); angles[YAW] = bobjrotate; - CL_TransformEntity (ent, angles, false); + CL_TransformEntity (ent, angles); } CL_EntityEffects (i, ent, new); CL_NewDlight (i, ent->origin, new->effects, new->glow_size, diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index f31256138..25ff7bd39 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -52,6 +52,8 @@ #include "clview.h" #include "sbar.h" +#include "client/temp_entities.h" + #include "nq/include/chase.h" #include "nq/include/cl_skin.h" #include "nq/include/client.h" @@ -423,6 +425,10 @@ int CL_ReadFromServer (void) { int ret; + TEntContext_t tentCtx = { + {VectorExpand (cl_entities[cl.viewentity].origin), 1}, + cl.worldmodel, cl.viewentity + }; cl.oldtime = cl.time; cl.time += host_frametime; @@ -442,7 +448,7 @@ CL_ReadFromServer (void) Sys_Printf ("\n"); CL_RelinkEntities (); - CL_UpdateTEnts (); + CL_UpdateTEnts (cl.time, &tentCtx); // bring the links up to date return 0; diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index 10ac2d4f5..260920d13 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -53,6 +53,8 @@ #include "QF/plugin/vid_render.h" +#include "client/temp_entities.h" + #include "compat.h" #include "sbar.h" @@ -591,7 +593,7 @@ CL_ParseUpdate (int bits) //VectorCopy (state->msg_origins[0], state->msg_origins[1]); //VectorCopy (state->msg_origins[0], ent->origin); //VectorCopy (state->msg_angles[0], state->msg_angles[1]); - //CL_TransformEntity (ent, state->msg_angles[0], true); + //CL_TransformEntity (ent, state->msg_angles[0]); //state->forcelink = true; cl_forcelink[num] = true; } @@ -793,7 +795,7 @@ CL_ParseStatic (int version) ent->renderer.colormod[3] = ENTALPHA_DECODE (baseline.alpha); ent->scale = baseline.scale / 16.0; VectorCopy (baseline.origin, ent->origin); - CL_TransformEntity (ent, baseline.angles, true); + CL_TransformEntity (ent, baseline.angles); r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } @@ -835,6 +837,11 @@ CL_ParseServerMessage (void) static dstring_t *stuffbuf; signon_t so; + TEntContext_t tentCtx = { + {VectorExpand (cl_entities[cl.viewentity].origin), 1}, + cl.worldmodel, cl.viewentity + }; + // if recording demos, copy the message out if (cl_shownet->int_val == 1) Sys_Printf ("%i ", net_message->message->cursize); @@ -1031,7 +1038,7 @@ CL_ParseServerMessage (void) break; case svc_particle: - CL_ParseParticleEffect (); + CL_ParseParticleEffect (net_message); break; case svc_damage: @@ -1051,7 +1058,7 @@ CL_ParseServerMessage (void) break; case svc_temp_entity: - CL_ParseTEnt (); + CL_ParseTEnt_nq (net_message, cl.time, &tentCtx); break; case svc_setpause: diff --git a/nq/source/cl_tent.c b/nq/source/cl_tent.c deleted file mode 100644 index 3a8a1b899..000000000 --- a/nq/source/cl_tent.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - cl_tent.c - - client side temporary entities - - Copyright (C) 1996-1997 Id Software, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif - -#include -#include - -#include "QF/entity.h" -#include "QF/model.h" -#include "QF/msg.h" -#include "QF/sound.h" -#include "QF/sys.h" - -#include "QF/plugin/vid_render.h" - -#include "compat.h" - -#include "nq/include/client.h" - -typedef struct tent_s { - struct tent_s *next; - entity_t ent; -} tent_t; - -#define TEMP_BATCH 64 -static tent_t *temp_entities = 0; - -typedef struct { - int entity; - struct model_s *model; - float endtime; - vec3_t start, end; - tent_t *tents; - int seed; -} beam_t; - -#define BEAM_SEED_INTERVAL 72 -#define BEAM_SEED_PRIME 3191 - -typedef struct { - float start; - tent_t *tent; -} explosion_t; - -typedef struct tent_obj_s { - struct tent_obj_s *next; - union { - beam_t beam; - explosion_t ex; - } to; -} tent_obj_t; - -static tent_obj_t *tent_objects; -static tent_obj_t *cl_beams; -static tent_obj_t *cl_explosions; - -static sfx_t *cl_sfx_wizhit; -static sfx_t *cl_sfx_knighthit; -static sfx_t *cl_sfx_tink1; -static sfx_t *cl_sfx_ric1; -static sfx_t *cl_sfx_ric2; -static sfx_t *cl_sfx_ric3; -static sfx_t *cl_sfx_r_exp3; - -static model_t *cl_mod_beam; -static model_t *cl_mod_bolt; -static model_t *cl_mod_bolt2; -static model_t *cl_mod_bolt3; -static model_t *cl_spr_explod; - -static void -CL_TEnts_Precache (int phase) -{ - if (!phase) - return; - cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav"); - cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav"); - cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav"); - cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav"); - cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav"); - cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav"); - cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav"); - - cl_mod_bolt = Mod_ForName ("progs/bolt.mdl", true); - cl_mod_bolt2 = Mod_ForName ("progs/bolt2.mdl", true); - cl_mod_bolt3 = Mod_ForName ("progs/bolt3.mdl", true); - cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); - cl_mod_beam = Mod_ForName ("progs/beam.mdl", false); - if (!cl_mod_beam) - cl_mod_beam = cl_mod_bolt; -} - -void -CL_TEnts_Init (void) -{ - QFS_GamedirCallback (CL_TEnts_Precache); - CL_TEnts_Precache (1); -} - -void -CL_Init_Entity (entity_t *ent) -{ - if (ent->transform) { - Transform_Delete (ent->transform); - } - memset (ent, 0, sizeof (*ent)); - - ent->transform = Transform_New (0); - ent->renderer.skin = 0; - QuatSet (1.0, 1.0, 1.0, 1.0, ent->renderer.colormod); - ent->scale = 1.0; - ent->animation.pose1 = ent->animation.pose2 = -1; -} - -static tent_t * -new_temp_entity (void) -{ - tent_t *tent; - if (!temp_entities) { - int i; - - temp_entities = malloc (TEMP_BATCH * sizeof (tent_t)); - for (i = 0; i < TEMP_BATCH - 1; i++) { - temp_entities[i].next = &temp_entities[i + 1]; - temp_entities[i].ent.transform = 0; - } - temp_entities[i].next = 0; - temp_entities[i].ent.transform = 0; - } - tent = temp_entities; - temp_entities = tent->next; - tent->next = 0; - CL_Init_Entity (&tent->ent); - return tent; -} - -static void -free_temp_entities (tent_t *tents) -{ - tent_t **t = &tents; - - while (*t) - t = &(*t)->next; - *t = temp_entities; - temp_entities = tents; -} - -static tent_obj_t * -new_tent_object (void) -{ - tent_obj_t *tobj; - if (!tent_objects) { - int i; - - tent_objects = malloc (TEMP_BATCH * sizeof (tent_obj_t)); - for (i = 0; i < TEMP_BATCH - 1; i++) - tent_objects[i].next = &tent_objects[i + 1]; - tent_objects[i].next = 0; - } - tobj = tent_objects; - tent_objects = tobj->next; - tobj->next = 0; - return tobj; -} - -static void -free_tent_objects (tent_obj_t *tobjs) -{ - tent_obj_t **t = &tobjs; - - while (*t) - t = &(*t)->next; - *t = tent_objects; - tent_objects = tobjs; -} - -void -CL_ClearTEnts (void) -{ - tent_t *t; - tent_obj_t *to; - - for (to = cl_beams; to; to = to->next) { - for (t = to->to.beam.tents; t; t = t->next) - t->ent.visibility.efrag = 0; - free_temp_entities (to->to.beam.tents); - } - free_tent_objects (cl_beams); - cl_beams = 0; - - for (to = cl_explosions; to; to = to->next) { - for (t = to->to.ex.tent; t; t = t->next) - t->ent.visibility.efrag = 0; - free_temp_entities (to->to.ex.tent); - } - free_tent_objects (cl_explosions); - cl_explosions = 0; -} - -static inline void -beam_clear (beam_t *b) -{ - if (b->tents) { - tent_t *t; - - for (t = b->tents; t; t = t->next) { - r_funcs->R_RemoveEfrags (&t->ent); - t->ent.visibility.efrag = 0; - } - free_temp_entities (b->tents); - b->tents = 0; - } -} - -static inline void -beam_setup (beam_t *b, qboolean transform) -{ - tent_t *tent; - float forward, pitch, yaw, d; - int ent_count; - vec3_t dist, org, ang; - unsigned seed; - - // calculate pitch and yaw - VectorSubtract (b->end, b->start, dist); - - if (dist[1] == 0 && dist[0] == 0) { - yaw = 0; - if (dist[2] > 0) - pitch = 90; - else - pitch = 270; - } else { - yaw = (int) (atan2 (dist[1], dist[0]) * 180 / M_PI); - if (yaw < 0) - yaw += 360; - - forward = sqrt (dist[0] * dist[0] + dist[1] * dist[1]); - pitch = (int) (atan2 (dist[2], forward) * 180 / M_PI); - if (pitch < 0) - pitch += 360; - } - - // add new entities for the lightning - VectorCopy (b->start, org); - d = VectorNormalize (dist); - VectorScale (dist, 30, dist); - ent_count = ceil (d / 30); - d = 0; - - seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) % - BEAM_SEED_INTERVAL); - - ang[ROLL] = 0; - while (ent_count--) { - tent = new_temp_entity (); - tent->next = b->tents; - b->tents = tent; - - VectorMultAdd (org, d, dist, tent->ent.origin); - d += 1.0; - tent->ent.renderer.model = b->model; - ang[PITCH] = pitch; - ang[YAW] = yaw; - if (transform) { - seed = seed * BEAM_SEED_PRIME; - ang[ROLL] = seed % 360; - CL_TransformEntity (&tent->ent, ang, true); - } - VectorCopy (ang, tent->ent.angles); - r_funcs->R_AddEfrags (&cl.worldmodel->brush, &tent->ent); - } -} - -static void -CL_ParseBeam (model_t *m) -{ - tent_obj_t *to; - beam_t *b; - int ent; - vec3_t start, end; - - ent = MSG_ReadShort (net_message); - - MSG_ReadCoordV (net_message, start); - MSG_ReadCoordV (net_message, end); - - to = 0; - if (ent) { - for (to = cl_beams; to; to = to->next) - if (to->to.beam.entity == ent) - break; - } - if (!to) { - to = new_tent_object (); - to->next = cl_beams; - cl_beams = to; - to->to.beam.tents = 0; - to->to.beam.entity = ent; - } - b = &to->to.beam; - - beam_clear (b); - b->model = m; - b->endtime = cl.time + 0.2; - b->seed = rand (); - VectorCopy (end, b->end); - if (b->entity != cl.viewentity) { - // this will be done in CL_UpdateBeams - VectorCopy (start, b->start); - beam_setup (b, true); - } -} - -void -CL_ParseTEnt (void) -{ - byte type; - dlight_t *dl; - tent_obj_t *to; - explosion_t *ex; - int colorStart, colorLength; - quat_t col; - vec3_t pos; - sfx_t *spike_sound[] = { - cl_sfx_ric3, cl_sfx_ric3, cl_sfx_ric2, cl_sfx_ric1, - }; - - type = MSG_ReadByte (net_message); - switch (type) { - case TE_WIZSPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_WizSpikeEffect (pos); - S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1); - break; - - case TE_KNIGHTSPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_KnightSpikeEffect (pos); - S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1); - break; - - case TE_SPIKE: // spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_SpikeEffect (pos); - { - int i; - sfx_t *sound; - - i = (rand () % 20) - 16; - if (i >= 0) - sound = spike_sound[i]; - else - sound = cl_sfx_tink1; - S_StartSound (-1, 0, sound, pos, 1, 1); - } - break; - - case TE_SUPERSPIKE: // super spike hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_SuperSpikeEffect (pos); - { - int i; - sfx_t *sound; - - i = (rand () % 20) - 16; - if (i >= 0) - sound = spike_sound[i]; - else - sound = cl_sfx_tink1; - S_StartSound (-1, 0, sound, pos, 1, 1); - } - break; - - case TE_EXPLOSION: // rocket explosion - // particles - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_ParticleExplosion (pos); - - // light - dl = r_funcs->R_AllocDlight (0); - if (dl) { - VectorCopy (pos, dl->origin); - dl->radius = 350; - dl->die = cl.time + 0.5; - dl->decay = 300; - QuatSet (1.0, 0.5, 0.25, 0.7, dl->color); - } - - // sound - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - - // sprite - to = new_tent_object (); - to->next = cl_explosions; - cl_explosions = to; - ex = &to->to.ex; - ex->tent = new_temp_entity (); - - VectorCopy (pos, ex->tent->ent.origin); - ex->start = cl.time; - //FIXME need better model management - if (!cl_spr_explod->cache.data) - cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); - ex->tent->ent.renderer.model = cl_spr_explod; - CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles, true); - break; - - case TE_TAREXPLOSION: // tarbaby explosion - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_BlobExplosion (pos); - - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - break; - - case TE_LIGHTNING1: // lightning bolts - CL_ParseBeam (cl_mod_bolt); - break; - - case TE_LIGHTNING2: // lightning bolts - CL_ParseBeam (cl_mod_bolt2); - break; - - case TE_LIGHTNING3: // lightning bolts - CL_ParseBeam (cl_mod_bolt3); - break; - - case TE_LIGHTNING4NEH: // Nehahra lightning - CL_ParseBeam (Mod_ForName (MSG_ReadString (net_message), true)); - break; - - // PGM 01/21/97 - case TE_BEAM: // grappling hook beam - CL_ParseBeam (cl_mod_beam); - break; - // PGM 01/21/97 - - case TE_LAVASPLASH: - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_LavaSplash (pos); - break; - - case TE_TELEPORT: - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_TeleportSplash (pos); - break; - - case TE_EXPLOSION2: // color mapped explosion - MSG_ReadCoordV (net_message, pos); - colorStart = MSG_ReadByte (net_message); - colorLength = MSG_ReadByte (net_message); - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - r_funcs->particles->R_ParticleExplosion2 (pos, colorStart, - colorLength); - dl = r_funcs->R_AllocDlight (0); - if (!dl) - break; - VectorCopy (pos, dl->origin); - dl->radius = 350; - dl->die = cl.time + 0.5; - dl->decay = 300; - colorStart = (colorStart + (rand () % colorLength)) * 3; - VectorScale (&r_data->vid->palette[colorStart], 1.0 / 255.0, - dl->color); - dl->color[3] = 0.7; - break; - - case TE_EXPLOSION3: // Nehahra colored light explosion - MSG_ReadCoordV (net_message, pos); - MSG_ReadCoordV (net_message, col); // OUCH! - col[3] = 0.7; - r_funcs->particles->R_ParticleExplosion (pos); - S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); - dl = r_funcs->R_AllocDlight (0); - if (dl) { - VectorCopy (pos, dl->origin); - dl->radius = 350; - dl->die = cl.time + 0.5; - dl->decay = 300; - QuatCopy (col, dl->color); - } - break; - - case TE_GUNSHOT: // bullet hitting wall - MSG_ReadCoordV (net_message, pos); - r_funcs->particles->R_GunshotEffect (pos, 20); - break; - - default: - Sys_Error ("CL_ParseTEnt: bad type %d", type); - } -} - -static void -CL_UpdateBeams (void) -{ - tent_obj_t **to; - beam_t *b; - unsigned seed; - tent_t *t; - - // update lightning - for (to = &cl_beams; *to; ) { - b = &(*to)->to.beam; - if (!b->endtime) - continue; - if (!b->model || b->endtime < cl.time) { - tent_obj_t *_to; - b->endtime = 0; - beam_clear (b); - _to = *to; - *to = _to->next; - _to->next = tent_objects; - tent_objects = _to; - continue; - } - to = &(*to)->next; - - // if coming from the player, update the start position - if (b->entity == cl.viewentity) { - beam_clear (b); - VectorCopy (cl_entities[cl.viewentity].origin, b->start); - beam_setup (b, false); - } - - seed = b->seed + ((int) (cl.time * BEAM_SEED_INTERVAL) % - BEAM_SEED_INTERVAL); - - // add new entities for the lightning - for (t = b->tents; t; t = t->next) { - seed = seed * BEAM_SEED_PRIME; - t->ent.angles[ROLL] = seed % 360; - CL_TransformEntity (&t->ent, t->ent.angles, true); - } - } -} - -static void -CL_UpdateExplosions (void) -{ - int f; - tent_obj_t **to; - explosion_t *ex; - entity_t *ent; - - for (to = &cl_explosions; *to; ) { - ex = &(*to)->to.ex; - ent = &ex->tent->ent; - f = 10 * (cl.time - ex->start); - if (f >= ent->renderer.model->numframes) { - tent_obj_t *_to; - r_funcs->R_RemoveEfrags (ent); - ent->visibility.efrag = 0; - free_temp_entities (ex->tent); - _to = *to; - *to = _to->next; - _to->next = tent_objects; - tent_objects = _to; - continue; - } - to = &(*to)->next; - - ent->animation.frame = f; - if (!ent->visibility.efrag) - r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); - } -} - -void -CL_UpdateTEnts (void) -{ - CL_UpdateBeams (); - CL_UpdateExplosions (); -} - -/* - CL_ParseParticleEffect - - Parse an effect out of the server message -*/ -void -CL_ParseParticleEffect (void) -{ - int i, count, color; - vec3_t org, dir; - - MSG_ReadCoordV (net_message, org); - for (i = 0; i < 3; i++) - dir[i] = ((signed char) MSG_ReadByte (net_message)) * (15.0 / 16.0); - count = MSG_ReadByte (net_message); - color = MSG_ReadByte (net_message); - - if (count == 255) - r_funcs->particles->R_ParticleExplosion (org); - else - r_funcs->particles->R_RunParticleEffect (org, dir, color, count); -} diff --git a/nq/source/cl_view.c b/nq/source/cl_view.c index 132df122f..e6812a263 100644 --- a/nq/source/cl_view.c +++ b/nq/source/cl_view.c @@ -728,7 +728,7 @@ V_CalcRefdef (void) if (cl.chase && chase_active->int_val) Chase_Update (); - CL_TransformEntity (view, view->angles, true); + CL_TransformEntity (view, view->angles); } /* diff --git a/qw/include/Makemodule.am b/qw/include/Makemodule.am index 2f5076b12..c30d5decf 100644 --- a/qw/include/Makemodule.am +++ b/qw/include/Makemodule.am @@ -11,7 +11,6 @@ EXTRA_DIST += \ qw/include/cl_pred.h \ qw/include/cl_skin.h \ qw/include/cl_slist.h \ - qw/include/cl_tent.h \ qw/include/client.h \ qw/include/crudefile.h \ qw/include/game.h \ diff --git a/qw/include/cl_ents.h b/qw/include/cl_ents.h index 275cd04f6..b56e162d9 100644 --- a/qw/include/cl_ents.h +++ b/qw/include/cl_ents.h @@ -34,11 +34,9 @@ void CL_SetSolidPlayers (int playernum); void CL_ClearPredict (void); void CL_SetUpPlayerPrediction(qboolean dopred); -void CL_TransformEntity (struct entity_s * ent, const vec3_t angles, - qboolean force); +void CL_ClearEnts (void); void CL_EmitEntities (void); void CL_ClearProjectiles (void); -void CL_ParseProjectiles (qboolean nail2); void CL_ParsePacketEntities (qboolean delta); void CL_SetSolidEntities (void); void CL_ParsePlayerinfo (void); diff --git a/qw/include/cl_parse.h b/qw/include/cl_parse.h index 4dd3646c6..b624dd0d3 100644 --- a/qw/include/cl_parse.h +++ b/qw/include/cl_parse.h @@ -40,7 +40,6 @@ extern int parsecountmod; extern double parsecounttime; extern int cl_playerindex; extern int cl_flagindex; -extern int cl_spikeindex; extern int viewentity; extern int cl_h_playerindex; extern int cl_gib1index; diff --git a/qw/include/cl_tent.h b/qw/include/cl_tent.h deleted file mode 100644 index 71af54705..000000000 --- a/qw/include/cl_tent.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - client.h - - Client definitions - - Copyright (C) 1996-1997 Id Software, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ - -#ifndef _CL_TENT_H -#define _CL_TENT_H - -void CL_TEnts_Init (void); -void CL_ClearEnts (void); -void CL_ClearTEnts (void); -void CL_Init_Entity (struct entity_s *ent); -void CL_ParseTEnt (void); -void CL_UpdateTEnts (void); - -#endif diff --git a/qw/source/Makemodule.am b/qw/source/Makemodule.am index 739789020..00e30b4bc 100644 --- a/qw/source/Makemodule.am +++ b/qw/source/Makemodule.am @@ -103,7 +103,7 @@ qw_source_libqw_client_a_SOURCES= \ qw/source/cl_cam.c qw/source/cl_chase.c qw/source/cl_chat.c qw/source/cl_cmd.c qw/source/cl_cvar.c qw/source/cl_demo.c \ qw/source/cl_entparse.c qw/source/cl_ents.c qw/source/cl_http.c qw/source/cl_input.c qw/source/cl_main.c qw/source/cl_ngraph.c \ qw/source/cl_parse.c qw/source/cl_pred.c qw/source/cl_rss.c qw/source/cl_screen.c qw/source/cl_skin.c qw/source/cl_slist.c \ - qw/source/cl_tent.c qw/source/cl_view.c \ + qw/source/cl_view.c \ qw/source/locs.c qw/source/sbar.c qw/source/teamplay.c # Software-rendering clients diff --git a/qw/source/cl_entparse.c b/qw/source/cl_entparse.c index 2d130574d..3a3d67264 100644 --- a/qw/source/cl_entparse.c +++ b/qw/source/cl_entparse.c @@ -45,6 +45,8 @@ #include "compat.h" #include "clview.h" +#include "client/temp_entities.h" + #include "qw/msg_ucmd.h" #include "qw/pmove.h" #include "qw/bothdefs.h" @@ -54,7 +56,6 @@ #include "qw/include/cl_main.h" #include "qw/include/cl_parse.h" #include "qw/include/cl_pred.h" -#include "qw/include/cl_tent.h" #include "qw/include/host.h" static struct predicted_player { diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index d294f9981..11acacaf2 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -47,6 +47,8 @@ #include "clview.h" #include "d_iface.h" +#include "client/temp_entities.h" + #include "qw/bothdefs.h" #include "qw/msg_ucmd.h" #include "qw/pmove.h" @@ -57,7 +59,6 @@ #include "qw/include/cl_main.h" #include "qw/include/cl_parse.h" #include "qw/include/cl_pred.h" -#include "qw/include/cl_tent.h" #include "qw/include/host.h" entity_t cl_player_ents[MAX_CLIENTS]; @@ -170,36 +171,6 @@ is_gib (entity_state_t *s1) return 0; } -void -CL_TransformEntity (entity_t *ent, const vec3_t angles, qboolean force) -{ - union { - quat_t q; - vec4f_t v; - } rotation; - vec4f_t position; - vec4f_t scale; - - VectorCopy (ent->origin, position); - position[3] = 1; - VectorSet (ent->scale, ent->scale, ent->scale, scale); - scale[3] = 1; - if (VectorIsZero (angles)) { - QuatSet (0, 0, 0, 1, rotation.q); - } else { - vec3_t ang; - VectorCopy (angles, ang); - if (ent->renderer.model && ent->renderer.model->type == mod_alias) { - // stupid quake bug - // why, oh, why, do alias models pitch in the opposite direction - // to everything else? - ang[PITCH] = -ang[PITCH]; - } - AngleQuat (ang, rotation.q); - } - Transform_SetLocalTransform (ent->transform, scale, rotation.v, position); -} - static void CL_ModelEffects (entity_t *ent, int num, int glow_color) { @@ -342,7 +313,7 @@ CL_LinkPacketEntities (void) animation->pose1 = animation->pose2 = -1; VectorCopy (new->origin, ent->origin); if (!(renderer->model->flags & EF_ROTATE)) - CL_TransformEntity (ent, new->angles, true); + CL_TransformEntity (ent, new->angles); if (i != cl.viewentity || chase_active->int_val) { if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); @@ -360,7 +331,7 @@ CL_LinkPacketEntities (void) // assume a teleportation, not a motion VectorCopy (new->origin, ent->origin); if (!(renderer->model->flags & EF_ROTATE)) { - CL_TransformEntity (ent, new->angles, true); + CL_TransformEntity (ent, new->angles); } animation->pose1 = animation->pose2 = -1; } else { @@ -376,7 +347,7 @@ CL_LinkPacketEntities (void) d[j] += 360; } VectorMultAdd (old->angles, f, d, angles); - CL_TransformEntity (ent, angles, false); + CL_TransformEntity (ent, angles); } } if (i != cl.viewentity || chase_active->int_val) { @@ -400,7 +371,7 @@ CL_LinkPacketEntities (void) angles[PITCH] = 0; angles[YAW] = anglemod (100 * cl.time); angles[ROLL] = 0; - CL_TransformEntity (ent, angles, false); + CL_TransformEntity (ent, angles); } //CL_EntityEffects (i, ent, new); //CL_NewDlight (i, ent->origin, new->effects, 0, 0); @@ -567,7 +538,7 @@ CL_LinkPlayers (void) ent->animation.frame = state->pls.frame; ent->renderer.skinnum = state->pls.skinnum; - CL_TransformEntity (ent, ang, false); + CL_TransformEntity (ent, ang); ent->renderer.min_light = 0; ent->renderer.fullbright = 0; @@ -611,9 +582,13 @@ CL_EmitEntities (void) if (!cl.validsequence) return; + TEntContext_t tentCtx = { + {VectorExpand (cl.simorg), 1}, cl.worldmodel, cl.viewentity + }; + CL_LinkPlayers (); CL_LinkPacketEntities (); - CL_UpdateTEnts (); + CL_UpdateTEnts (cl.time, &tentCtx); if (cl_draw_locs->int_val) { //FIXME custom ent rendering code would be nice dlight_t *dl; diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index 5fcf0364e..656d6eb57 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -96,6 +96,8 @@ #include "compat.h" #include "sbar.h" +#include "client/temp_entities.h" + #include "qw/bothdefs.h" #include "qw/pmove.h" @@ -110,7 +112,6 @@ #include "qw/include/cl_pred.h" #include "qw/include/cl_skin.h" #include "qw/include/cl_slist.h" -#include "qw/include/cl_tent.h" #include "qw/include/client.h" #include "qw/include/game.h" #include "qw/include/host.h" diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 2523f8feb..2266d1029 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -65,6 +65,8 @@ #include "clview.h" #include "sbar.h" +#include "client/temp_entities.h" + #include "qw/bothdefs.h" #include "qw/pmove.h" #include "qw/protocol.h" @@ -77,7 +79,6 @@ #include "qw/include/cl_main.h" #include "qw/include/cl_parse.h" #include "qw/include/cl_skin.h" -#include "qw/include/cl_tent.h" #include "qw/include/client.h" #include "qw/include/host.h" #include "qw/include/map_cfg.h" @@ -161,7 +162,7 @@ int oldparsecountmod; int parsecountmod; double parsecounttime; -int cl_spikeindex, cl_playerindex, cl_flagindex; +int cl_playerindex, cl_flagindex; int cl_h_playerindex, cl_gib1index, cl_gib2index, cl_gib3index; int packet_latency[NET_TIMINGS]; @@ -437,7 +438,6 @@ Sound_NextDownload (void) // done with sounds, request models now memset (cl.model_precache, 0, sizeof (cl.model_precache)); cl_playerindex = -1; - cl_spikeindex = -1; cl_flagindex = -1; cl_h_playerindex = -1; cl_gib1index = cl_gib2index = cl_gib3index = -1; @@ -906,9 +906,7 @@ CL_ParseModellist (void) Host_Error ("Server sent too many model_precache"); strcpy (cl.model_name[cl.nummodels], str); - if (!strcmp (cl.model_name[cl.nummodels], "progs/spike.mdl")) - cl_spikeindex = cl.nummodels; - else if (!strcmp (cl.model_name[cl.nummodels], "progs/player.mdl")) + if (!strcmp (cl.model_name[cl.nummodels], "progs/player.mdl")) cl_playerindex = cl.nummodels; else if (!strcmp (cl.model_name[cl.nummodels], "progs/flag.mdl")) cl_flagindex = cl.nummodels; @@ -984,7 +982,7 @@ CL_ParseStatic (void) ent->renderer.skinnum = es.skinnum; VectorCopy (es.origin, ent->origin); - CL_TransformEntity (ent, es.angles, true); + CL_TransformEntity (ent, es.angles); r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } @@ -1305,6 +1303,9 @@ CL_ParseServerMessage (void) int cmd = 0, i, j; const char *str; static dstring_t *stuffbuf; + TEntContext_t tentCtx = { + {VectorExpand (cl.simorg), 1}, cl.worldmodel, cl.viewentity + }; received_framecount = host_framecount; cl.last_servermessage = realtime; @@ -1507,7 +1508,7 @@ CL_ParseServerMessage (void) break; case svc_temp_entity: - CL_ParseTEnt (); + CL_ParseTEnt_qw (net_message, cl.time, &tentCtx); break; case svc_setpause: @@ -1639,7 +1640,7 @@ CL_ParseServerMessage (void) break; case svc_nails: - CL_ParseProjectiles (false); + CL_ParseProjectiles (net_message, false, &tentCtx); break; case svc_chokecount: // some preceding packets were choked @@ -1690,7 +1691,7 @@ CL_ParseServerMessage (void) break; case svc_nails2: // FIXME from qwex - CL_ParseProjectiles (true); + CL_ParseProjectiles (net_message, true, &tentCtx); break; } } diff --git a/qw/source/cl_view.c b/qw/source/cl_view.c index 59e7920cd..08d4dd501 100644 --- a/qw/source/cl_view.c +++ b/qw/source/cl_view.c @@ -731,7 +731,7 @@ V_CalcRefdef (void) if (cl.chase && chase_active->int_val) Chase_Update (); - CL_TransformEntity (view, view->angles, true); + CL_TransformEntity (view, view->angles); } static void From 693225a16fac7d5e99e87db1ff59d80e50bd293b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Mar 2021 18:05:12 +0900 Subject: [PATCH 388/435] [util] Add a fixme for a comment The code itself is fine, but the comment is rubbish because it's confusing, though essentially correct. --- libs/util/mathlib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/util/mathlib.c b/libs/util/mathlib.c index 2d547f756..33eae277d 100644 --- a/libs/util/mathlib.c +++ b/libs/util/mathlib.c @@ -501,6 +501,8 @@ BoxOnPlaneSide (const vec3_t emins, const vec3_t emaxs, plane_t *p) #endif /* + FIXME these comments are a confused mess (the code is fine) + angles is a left(?) handed system: 'pitch yaw roll' with x (pitch) axis to the right, y (yaw) axis up and z (roll) axis forward. From 56d84ef63ecaf9ae399027e5dad1f680925842b3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Mar 2021 18:35:35 +0900 Subject: [PATCH 389/435] [gl] Fix the compressed sprites Seems to be an ancient bug. --- libs/video/renderer/gl/gl_mod_sprite.c | 40 ++++++++++++++------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/libs/video/renderer/gl/gl_mod_sprite.c b/libs/video/renderer/gl/gl_mod_sprite.c index b6ce25f22..d0dd91444 100644 --- a/libs/video/renderer/gl/gl_mod_sprite.c +++ b/libs/video/renderer/gl/gl_mod_sprite.c @@ -105,7 +105,7 @@ R_DrawSpriteModel_f (entity_t *e) { float modelalpha, color[4]; vec4f_t up = {}, right = {}; - vec4f_t origin, point1, point2; + vec4f_t origin, point; msprite_t *psprite; mspriteframe_t *frame; @@ -140,23 +140,23 @@ R_DrawSpriteModel_f (entity_t *e) qfglColor4fv (color); origin = Transform_GetWorldPosition (e->transform); - point1 = origin + frame->down * up + frame->left * right; - point2 = origin + frame->up * up + frame->left * right; + point = origin + frame->down * up + frame->left * right; qfglTexCoord2f (0, 1); - qfglVertex3fv (&point1[0]); + qfglVertex3fv (&point[0]); + point = origin + frame->up * up + frame->left * right; qfglTexCoord2f (0, 0); - qfglVertex3fv (&point2[0]); + qfglVertex3fv (&point[0]); - point2 += frame->right * right; - point1 += frame->right * right; + point = origin + frame->up * up + frame->right * right; qfglTexCoord2f (1, 0); - qfglVertex3fv (&point2[0]); + qfglVertex3fv (&point[0]); + point = origin + frame->down * up + frame->right * right; qfglTexCoord2f (1, 1); - qfglVertex3fv (&point1[0]); + qfglVertex3fv (&point[0]); qfglEnd (); @@ -169,7 +169,7 @@ R_DrawSpriteModel_VA_f (entity_t *e) { unsigned char modelalpha, color[4]; vec4f_t up = {}, right = {}; - vec4f_t origin, point1, point2; + vec4f_t origin, point; int i; // unsigned int vacount; msprite_t *psprite; @@ -212,16 +212,18 @@ R_DrawSpriteModel_VA_f (entity_t *e) qfglDepthMask (GL_FALSE); origin = Transform_GetWorldPosition (e->transform); - point1 = origin + frame->down * up + frame->left * right; - VectorCopy (point1, VA[0].vertex); - point2 = origin + frame->up * up + frame->left * right; - VectorCopy (point2, VA[1].vertex); + point = origin + frame->down * up + frame->left * right; + VectorCopy (point, VA[0].vertex); - point2 += frame->right * right; - point1 += frame->right * right; - VectorCopy (point2, VA[2].vertex); - VectorCopy (point1, VA[3].vertex); + point = origin + frame->up * up + frame->left * right; + VectorCopy (point, VA[1].vertex); + + point = origin + frame->up * up + frame->right * right; + VectorCopy (point, VA[2].vertex); + + point = origin + frame->down * up + frame->right * right; + VectorCopy (point, VA[3].vertex); // VA += 4; // vacount += 4; @@ -242,7 +244,7 @@ gl_R_InitSprites (void) int i; if (r_init) { - if (gl_va_capable) { // 0 == gl_va_capable + if (gl_va_capable) { gl_R_DrawSpriteModel = R_DrawSpriteModel_VA_f; #if 0 From 169e0192f2f851d4b01044e2a7e460e517c28032 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Mar 2021 19:06:15 +0900 Subject: [PATCH 390/435] [gl] Use the correct value for sqrt(0.5) 707106781 looks right, but isn't quite. --- libs/video/renderer/gl/gl_mod_alias.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/video/renderer/gl/gl_mod_alias.c b/libs/video/renderer/gl/gl_mod_alias.c index 4b90ba54a..8e4670a77 100644 --- a/libs/video/renderer/gl/gl_mod_alias.c +++ b/libs/video/renderer/gl/gl_mod_alias.c @@ -701,10 +701,10 @@ gl_R_DrawAliasModel (entity_t *e) qfglColor4ubv (color_black); } //FIXME fully vectorize - vec4f_t vec = { 707106781, 0, 707106781, 0 }; + vec4f_t vec = { 0.707106781, 0, 0.707106781, 0 }; Transform_GetWorldMatrix (e->transform, shadow_mat); mat4ftranspose (shadow_mat, shadow_mat); - vec = mvmulf (shadow_mat, vec); + vec = m3vmulf (shadow_mat, vec); VectorCopy (vec, shadevector); if (vo->tex_coord) GL_DrawAliasShadowTri (paliashdr, vo); From 5949753579c32b0d477890bb4bb5e88b6e76fd34 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Mar 2021 19:40:19 +0900 Subject: [PATCH 391/435] Make m3vmulf return v[3] unchanged --- include/QF/simd/mat4f.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/simd/mat4f.h b/include/QF/simd/mat4f.h index 719e4c561..658cf582b 100644 --- a/include/QF/simd/mat4f.h +++ b/include/QF/simd/mat4f.h @@ -104,7 +104,7 @@ m3vmulf (const mat4f_t m, vec4f_t v) { vec4f_t w; w = m[0] * v[0] + m[1] * v[1] + m[2] * v[2]; - w[3] = 1; + w[3] = v[3]; return w; } From 62cce7f98c39b41cae345b59afe9f69fee05de7c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Mar 2021 21:15:53 +0900 Subject: [PATCH 392/435] [gl] Remove some more warts seeing ptexels and pixels together is very confusing --- libs/models/gl_model_fullbright.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/libs/models/gl_model_fullbright.c b/libs/models/gl_model_fullbright.c index 60df0d50c..6635cbef5 100644 --- a/libs/models/gl_model_fullbright.c +++ b/libs/models/gl_model_fullbright.c @@ -43,29 +43,28 @@ int Mod_Fullbright (byte *skin, int width, int height, const char *name) { - byte *ptexels; + byte *texels; int pixels; int texnum = 0; pixels = width * height; -// ptexels = Hunk_Alloc(s); - ptexels = malloc (pixels); - SYS_CHECKMEM (ptexels); + texels = malloc (pixels); + SYS_CHECKMEM (texels); // Check for fullbright pixels - if (Mod_CalcFullbright (skin, ptexels, pixels)) { + if (Mod_CalcFullbright (skin, texels, pixels)) { //FIXME black should be transparent for fullbrights (or just fix //fullbright rendering in gl) + Sys_MaskPrintf (SYS_DEV, "FB Model ID: '%s'\n", name); for (int i = 0; i < pixels; i++) { - if (!ptexels[i]) { - ptexels[i] = 255; + if (!texels[i]) { + texels[i] = 255; } } - Sys_MaskPrintf (SYS_DEV, "FB Model ID: '%s'\n", name); - texnum = GL_LoadTexture (name, width, height, ptexels, true, true, 1); + texnum = GL_LoadTexture (name, width, height, texels, true, true, 1); } - free (ptexels); + free (texels); return texnum; } From c05a15dec5caf897e3fa73a5829be0c133f4fb46 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 10 Mar 2021 21:17:34 +0900 Subject: [PATCH 393/435] [glsl] Use vec4f_t in a few more places No idea if it makes a noticeable speed difference, but it makes a huge readability difference. --- libs/video/renderer/glsl/glsl_sprite.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/video/renderer/glsl/glsl_sprite.c b/libs/video/renderer/glsl/glsl_sprite.c index 7582e9db3..63704ebfa 100644 --- a/libs/video/renderer/glsl/glsl_sprite.c +++ b/libs/video/renderer/glsl/glsl_sprite.c @@ -183,20 +183,20 @@ static void make_quad (mspriteframe_t *frame, vec4f_t vpn, vec4f_t vright, vec4f_t vup, float verts[6][3]) { - vec3_t left, up, right, down; - vec3_t ul, ur, ll, lr; + vec4f_t left, up, right, down; + vec4f_t ul, ur, ll, lr; // build the sprite poster in worldspace // first, rotate the sprite axes into world space - VectorScale (vright, frame->right, right); - VectorScale (vup, frame->up, up); - VectorScale (vright, frame->left, left); - VectorScale (vup, frame->down, down); + right = frame->right * vright; + up = frame->up * vup; + left = frame->left * vright; + down = frame->down * vup; // next, build the sprite corners from the axes - VectorAdd (up, left, ul); - VectorAdd (up, right, ur); - VectorAdd (down, left, ll); - VectorAdd (down, right, lr); + ul = up + left; + ur = up + right; + ll = down + left; + lr = down + right; // finally, translate the sprite corners, creating two triangles VectorAdd (currententity->origin, ul, verts[0]); // first triangle VectorAdd (currententity->origin, ur, verts[1]); From 51e86941958a763dc555b556ed57d26accda90ba Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 11 Mar 2021 09:11:08 +0900 Subject: [PATCH 394/435] [qw] Use a dynamic array to track static entities This takes care of another fixme in the cleanup of entity_t. --- include/QF/darray.h | 2 ++ include/QF/render.h | 1 - qw/include/client.h | 3 ++- qw/source/cl_demo.c | 4 +++- qw/source/cl_parse.c | 9 +++------ 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/QF/darray.h b/include/QF/darray.h index 61500256a..e41cd5edb 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -69,6 +69,8 @@ ele_type *a; \ } +#define DARRAY_STATIC_INIT(g) { .grow = g } + /** Allocate a fixed-size array using the given allocator The allocated array is initilized to be ungrowable, and with both size diff --git a/include/QF/render.h b/include/QF/render.h index d6a871865..99fb105a9 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -124,7 +124,6 @@ typedef struct renderer_s { typedef struct entity_s { struct entity_s *next; - struct entity_s *unext; //FIXME this shouldn't be here. for qw demos struct transform_s *transform; animation_t animation; diff --git a/qw/include/client.h b/qw/include/client.h index 23d22e893..3c64c128b 100644 --- a/qw/include/client.h +++ b/qw/include/client.h @@ -28,6 +28,7 @@ #ifndef _CLIENT_H #define _CLIENT_H +#include "QF/entity.h" #include "QF/info.h" #include "QF/quakefs.h" #include "QF/vid.h" @@ -341,7 +342,7 @@ extern struct cvar_s *cl_fb_players; extern client_state_t cl; -extern entity_t *cl_static_entities; +extern entityset_t cl_static_entities; extern entity_t cl_entities[512]; extern byte cl_entity_valid[2][512]; diff --git a/qw/source/cl_demo.c b/qw/source/cl_demo.c index d063211d4..31594d51f 100644 --- a/qw/source/cl_demo.c +++ b/qw/source/cl_demo.c @@ -755,7 +755,9 @@ demo_start_recording (int track) SZ_Clear (&buf); } // spawnstatic - for (ent = cl_static_entities; ent; ent = ent->unext) { + for (size_t staticIndex = 0; staticIndex < cl_static_entities.size; + staticIndex++) { + ent = cl_static_entities.a[staticIndex]; MSG_WriteByte (&buf, svc_spawnstatic); for (j = 1; j < cl.nummodels; j++) { diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 2266d1029..7366b4da0 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -169,8 +169,7 @@ int packet_latency[NET_TIMINGS]; extern cvar_t *hud_scoreboard_uid; -entity_t *cl_static_entities; -static entity_t **cl_static_tail; +entityset_t cl_static_entities = DARRAY_STATIC_INIT (32); static void CL_LoadSky (void) @@ -298,8 +297,7 @@ map_ent (const char *mapname) static void CL_NewMap (const char *mapname) { - cl_static_entities = 0; - cl_static_tail = &cl_static_entities; + cl_static_entities.size = 0; r_funcs->R_NewMap (cl.worldmodel, cl.model_precache, cl.nummodels); Team_NewMap (); Con_NewMap (); @@ -973,8 +971,7 @@ CL_ParseStatic (void) ent = r_funcs->R_AllocEntity (); CL_Init_Entity (ent); - *cl_static_tail = ent; - cl_static_tail = &ent->unext; + DARRAY_APPEND (&cl_static_entities, ent); // copy it to the current state ent->renderer.model = cl.model_precache[es.modelindex]; From b8267f2eddbb8e53c72a5c80c67055ee10f149d7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 11 Mar 2021 11:25:04 +0900 Subject: [PATCH 395/435] [client] Merge nq/qw entity effects code --- include/client/effects.h | 43 ++++++++ libs/client/Makemodule.am | 3 +- libs/client/cl_effects.c | 175 +++++++++++++++++++++++++++++++++ libs/client/cl_temp_entities.c | 1 + nq/source/cl_ents.c | 135 +------------------------ qw/source/cl_ents.c | 112 ++------------------- 6 files changed, 231 insertions(+), 238 deletions(-) create mode 100644 include/client/effects.h create mode 100644 libs/client/cl_effects.c diff --git a/include/client/effects.h b/include/client/effects.h new file mode 100644 index 000000000..1f1259274 --- /dev/null +++ b/include/client/effects.h @@ -0,0 +1,43 @@ +/* + effects.h + + Effect management + + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/3/11 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifndef __client_effects_h +#define __client_effects_h + +struct entity_s; +struct entity_state_s; + +void CL_NewDlight (int key, vec3_t org, int effects, byte glow_size, + byte glow_color, double time); +void CL_ModelEffects (struct entity_s *ent, int num, int glow_color, + double time); +void CL_EntityEffects (int num, struct entity_s *ent, + struct entity_state_s *state, double time); + +#endif//__client_effects_h diff --git a/libs/client/Makemodule.am b/libs/client/Makemodule.am index 9129b9dbd..943f6bf9e 100644 --- a/libs/client/Makemodule.am +++ b/libs/client/Makemodule.am @@ -3,6 +3,7 @@ noinst_LTLIBRARIES += libs/client/libQFclient.la libs_client_libQFclient_la_LDFLAGS= @STATIC@ libs_client_libQFclient_la_LIBADD= libs/gamecode/libQFgamecode.la libs/util/libQFutil.la libs_client_libQFclient_la_SOURCES= \ - libs/client/cl_temp_entities.c \ + libs/client/cl_effects.c \ libs/client/cl_entities.c \ + libs/client/cl_temp_entities.c \ $e diff --git a/libs/client/cl_effects.c b/libs/client/cl_effects.c new file mode 100644 index 000000000..3030431a8 --- /dev/null +++ b/libs/client/cl_effects.c @@ -0,0 +1,175 @@ +/* + cl_effect.c + + Client side effect management + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 2021 Bill Currie + + Author: Bill Currie + Date: 2021/3/11 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/entity.h" +#include "QF/render.h" + +#include "QF/plugin/vid_render.h" //FIXME + +#include "client/entities.h" +#include "client/effects.h" + +void +CL_NewDlight (int key, vec3_t org, int effects, byte glow_size, + byte glow_color, double time) +{ + float radius; + dlight_t *dl; + static quat_t normal = {0.4, 0.2, 0.05, 0.7}; + static quat_t red = {0.5, 0.05, 0.05, 0.7}; + static quat_t blue = {0.05, 0.05, 0.5, 0.7}; + static quat_t purple = {0.5, 0.05, 0.5, 0.7}; + + effects &= EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT; + if (!effects) { + if (!glow_size) + return; + } + + dl = r_funcs->R_AllocDlight (key); + if (!dl) + return; + VectorCopy (org, dl->origin); + + if (effects & (EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT)) { + radius = 200 + (rand () & 31); + if (effects & EF_BRIGHTLIGHT) { + radius += 200; + dl->origin[2] += 16; + } + if (effects & EF_DIMLIGHT) + if (effects & ~EF_DIMLIGHT) + radius -= 100; + dl->radius = radius; + dl->die = time + 0.1; + + switch (effects & (EF_RED | EF_BLUE)) { + case EF_RED | EF_BLUE: + QuatCopy (purple, dl->color); + break; + case EF_RED: + QuatCopy (red, dl->color); + break; + case EF_BLUE: + QuatCopy (blue, dl->color); + break; + default: + QuatCopy (normal, dl->color); + break; + } + } + + if (glow_size) { + dl->radius += glow_size < 128 ? glow_size * 8.0 : + (glow_size - 256) * 8.0; + dl->die = time + 0.1; + if (glow_color) { + if (glow_color == 255) { + dl->color[0] = dl->color[1] = dl->color[2] = 1.0; + } else { + byte *tempcolor; + + tempcolor = (byte *) &d_8to24table[glow_color]; + VectorScale (tempcolor, 1 / 255.0, dl->color); + } + } + } +} + +void +CL_ModelEffects (entity_t *ent, int num, int glow_color, double time) +{ + dlight_t *dl; + model_t *model = ent->renderer.model; + + // add automatic particle trails + if (model->flags & EF_ROCKET) { + dl = r_funcs->R_AllocDlight (num); + if (dl) { + VectorCopy (ent->origin, dl->origin); + dl->radius = 200.0; + dl->die = time + 0.1; + //FIXME VectorCopy (r_firecolor->vec, dl->color); + VectorSet (0.9, 0.7, 0.0, dl->color); + dl->color[3] = 0.7; + } + r_funcs->particles->R_RocketTrail (ent); + } else if (model->flags & EF_GRENADE) + r_funcs->particles->R_GrenadeTrail (ent); + else if (model->flags & EF_GIB) + r_funcs->particles->R_BloodTrail (ent); + else if (model->flags & EF_ZOMGIB) + r_funcs->particles->R_SlightBloodTrail (ent); + else if (model->flags & EF_TRACER) + r_funcs->particles->R_WizTrail (ent); + else if (model->flags & EF_TRACER2) + r_funcs->particles->R_FlameTrail (ent); + else if (model->flags & EF_TRACER3) + r_funcs->particles->R_VoorTrail (ent); + else if (model->flags & EF_GLOWTRAIL) + if (r_funcs->particles->R_GlowTrail) + r_funcs->particles->R_GlowTrail (ent, glow_color); +} + +void +CL_EntityEffects (int num, entity_t *ent, entity_state_t *state, double time) +{ + dlight_t *dl; + + if (state->effects & EF_BRIGHTFIELD) + r_funcs->particles->R_EntityParticles (ent); + if (state->effects & EF_MUZZLEFLASH) { + dl = r_funcs->R_AllocDlight (num); + if (dl) { + vec4f_t position = Transform_GetWorldPosition (ent->transform); + vec4f_t fv = Transform_Forward (ent->transform); + position += 18 * fv; + VectorCopy (position, dl->origin); + dl->origin[2] += 16; + dl->radius = 200 + (rand () & 31); + dl->die = time + 0.1; + dl->minlight = 32; + dl->color[0] = 0.2; + dl->color[1] = 0.1; + dl->color[2] = 0.05; + dl->color[3] = 0.7; + } + } +} diff --git a/libs/client/cl_temp_entities.c b/libs/client/cl_temp_entities.c index a0627e42d..0b6672f0f 100644 --- a/libs/client/cl_temp_entities.c +++ b/libs/client/cl_temp_entities.c @@ -3,6 +3,7 @@ Client side temporary entity management + Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2021 Bill Currie Author: Bill Currie diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index 3fdd3d0af..957cadb6a 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -47,6 +47,7 @@ #include "compat.h" +#include "client/effects.h" #include "client/temp_entities.h" #include "nq/include/chase.h" @@ -75,73 +76,6 @@ CL_ClearEnts (void) CL_Init_Entity (cl_entities + i); } -static void -CL_NewDlight (int key, vec3_t org, int effects, byte glow_size, - byte glow_color) -{ - float radius; - dlight_t *dl; - static quat_t normal = {0.4, 0.2, 0.05, 0.7}; - static quat_t red = {0.5, 0.05, 0.05, 0.7}; - static quat_t blue = {0.05, 0.05, 0.5, 0.7}; - static quat_t purple = {0.5, 0.05, 0.5, 0.7}; - - effects &= EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT; - if (!effects) { - if (!glow_size) - return; - } - - dl = r_funcs->R_AllocDlight (key); - if (!dl) - return; - VectorCopy (org, dl->origin); - - if (effects & (EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT)) { - radius = 200 + (rand () & 31); - if (effects & EF_BRIGHTLIGHT) { - radius += 200; - dl->origin[2] += 16; - } - if (effects & EF_DIMLIGHT) - if (effects & ~EF_DIMLIGHT) - radius -= 100; - dl->radius = radius; - dl->die = cl.time + 0.1; - - switch (effects & (EF_RED | EF_BLUE)) { - case EF_RED | EF_BLUE: - QuatCopy (purple, dl->color); - break; - case EF_RED: - QuatCopy (red, dl->color); - break; - case EF_BLUE: - QuatCopy (blue, dl->color); - break; - default: - QuatCopy (normal, dl->color); - break; - } - } - - if (glow_size) { - dl->radius += glow_size < 128 ? glow_size * 8.0 : - (glow_size - 256) * 8.0; - dl->die = cl.time + 0.1; - if (glow_color) { - if (glow_color == 255) { - dl->color[0] = dl->color[1] = dl->color[2] = 1.0; - } else { - byte *tempcolor; - - tempcolor = (byte *) &d_8to24table[glow_color]; - VectorScale (tempcolor, 1 / 255.0, dl->color); - } - } - } -} - /* CL_LerpPoint @@ -179,67 +113,6 @@ CL_LerpPoint (void) return frac; } -static void -CL_ModelEffects (entity_t *ent, int num, int glow_color) -{ - dlight_t *dl; - model_t *model = ent->renderer.model; - - // add automatic particle trails - if (model->flags & EF_ROCKET) { - dl = r_funcs->R_AllocDlight (num); - if (dl) { - VectorCopy (ent->origin, dl->origin); - dl->radius = 200.0; - dl->die = cl.time + 0.1; - //FIXME VectorCopy (r_firecolor->vec, dl->color); - VectorSet (0.9, 0.7, 0.0, dl->color); - dl->color[3] = 0.7; - } - r_funcs->particles->R_RocketTrail (ent); - } else if (model->flags & EF_GRENADE) - r_funcs->particles->R_GrenadeTrail (ent); - else if (model->flags & EF_GIB) - r_funcs->particles->R_BloodTrail (ent); - else if (model->flags & EF_ZOMGIB) - r_funcs->particles->R_SlightBloodTrail (ent); - else if (model->flags & EF_TRACER) - r_funcs->particles->R_WizTrail (ent); - else if (model->flags & EF_TRACER2) - r_funcs->particles->R_FlameTrail (ent); - else if (model->flags & EF_TRACER3) - r_funcs->particles->R_VoorTrail (ent); - else if (model->flags & EF_GLOWTRAIL) - if (r_funcs->particles->R_GlowTrail) - r_funcs->particles->R_GlowTrail (ent, glow_color); -} - -static void -CL_EntityEffects (int num, entity_t *ent, entity_state_t *state) -{ - dlight_t *dl; - - if (state->effects & EF_BRIGHTFIELD) - r_funcs->particles->R_EntityParticles (ent); - if (state->effects & EF_MUZZLEFLASH) { - dl = r_funcs->R_AllocDlight (num); - if (dl) { - vec4f_t position = Transform_GetWorldPosition (ent->transform); - vec4f_t fv = Transform_Forward (ent->transform); - position += 18 * fv; - VectorCopy (position, dl->origin); - dl->origin[2] += 16; - dl->radius = 200 + (rand () & 31); - dl->die = cl.time + 0.1; - dl->minlight = 32; - dl->color[0] = 0.2; - dl->color[1] = 0.1; - dl->color[2] = 0.05; - dl->color[3] = 0.7; - } - } -} - static void set_entity_model (entity_t *ent, int modelindex) { @@ -419,13 +292,13 @@ CL_RelinkEntities (void) angles[YAW] = bobjrotate; CL_TransformEntity (ent, angles); } - CL_EntityEffects (i, ent, new); + CL_EntityEffects (i, ent, new, cl.time); CL_NewDlight (i, ent->origin, new->effects, new->glow_size, - new->glow_color); + new->glow_color, cl.time); if (VectorDistance_fast (old->origin, ent->origin) > (256 * 256)) VectorCopy (ent->origin, old->origin); if (model_flags & ~EF_ROTATE) - CL_ModelEffects (ent, i, new->glow_color); + CL_ModelEffects (ent, i, new->glow_color, cl.time); cl_forcelink[i] = false; } diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 11acacaf2..0cf0f835e 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -47,6 +47,7 @@ #include "clview.h" #include "d_iface.h" +#include "client/effects.h" #include "client/temp_entities.h" #include "qw/bothdefs.h" @@ -82,73 +83,6 @@ CL_ClearEnts (void) CL_Init_Entity (&cl_player_ents[i]); } -static void -CL_NewDlight (int key, vec3_t org, int effects, byte glow_size, - byte glow_color) -{ - float radius; - dlight_t *dl; - static quat_t normal = {0.4, 0.2, 0.05, 0.7}; - static quat_t red = {0.5, 0.05, 0.05, 0.7}; - static quat_t blue = {0.05, 0.05, 0.5, 0.7}; - static quat_t purple = {0.5, 0.05, 0.5, 0.7}; - - effects &= EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT; - if (!effects) { - if (!glow_size) - return; - } - - dl = r_funcs->R_AllocDlight (key); - if (!dl) - return; - VectorCopy (org, dl->origin); - - if (effects & (EF_BLUE | EF_RED | EF_BRIGHTLIGHT | EF_DIMLIGHT)) { - radius = 200 + (rand () & 31); - if (effects & EF_BRIGHTLIGHT) { - radius += 200; - dl->origin[2] += 16; - } - if (effects & EF_DIMLIGHT) - if (effects & ~EF_DIMLIGHT) - radius -= 100; - dl->radius = radius; - dl->die = cl.time + 0.1; - - switch (effects & (EF_RED | EF_BLUE)) { - case EF_RED | EF_BLUE: - QuatCopy (purple, dl->color); - break; - case EF_RED: - QuatCopy (red, dl->color); - break; - case EF_BLUE: - QuatCopy (blue, dl->color); - break; - default: - QuatCopy (normal, dl->color); - break; - } - } - - if (glow_size) { - dl->radius += glow_size < 128 ? glow_size * 8.0 : - (glow_size - 256) * 8.0; - dl->die = cl.time + 0.1; - if (glow_color) { - if (glow_color == 255) { - dl->color[0] = dl->color[1] = dl->color[2] = 1.0; - } else { - byte *tempcolor; - - tempcolor = (byte *) &d_8to24table[glow_color]; - VectorScale (tempcolor, 1 / 255.0, dl->color); - } - } - } -} - // Hack hack hack static inline int is_dead_body (entity_state_t *s1) @@ -171,41 +105,6 @@ is_gib (entity_state_t *s1) return 0; } -static void -CL_ModelEffects (entity_t *ent, int num, int glow_color) -{ - dlight_t *dl; - model_t *model = ent->renderer.model; - - // add automatic particle trails - if (model->flags & EF_ROCKET) { - dl = r_funcs->R_AllocDlight (num); - if (dl) { - VectorCopy (ent->origin, dl->origin); - dl->radius = 200.0; - dl->die = cl.time + 0.1; - //FIXME VectorCopy (r_firecolor->vec, dl->color); - VectorSet (0.9, 0.7, 0.0, dl->color); - dl->color[3] = 0.7; - } - r_funcs->particles->R_RocketTrail (ent); - } else if (model->flags & EF_GRENADE) - r_funcs->particles->R_GrenadeTrail (ent); - else if (model->flags & EF_GIB) - r_funcs->particles->R_BloodTrail (ent); - else if (model->flags & EF_ZOMGIB) - r_funcs->particles->R_SlightBloodTrail (ent); - else if (model->flags & EF_TRACER) - r_funcs->particles->R_WizTrail (ent); - else if (model->flags & EF_TRACER2) - r_funcs->particles->R_FlameTrail (ent); - else if (model->flags & EF_TRACER3) - r_funcs->particles->R_VoorTrail (ent); - else if (model->flags & EF_GLOWTRAIL) - if (r_funcs->particles->R_GlowTrail) - r_funcs->particles->R_GlowTrail (ent, glow_color); -} - static void set_entity_model (entity_t *ent, int modelindex) { @@ -221,6 +120,7 @@ set_entity_model (entity_t *ent, int modelindex) animation->syncbase = 0.0; } } + animation->nolerp = 1; // don't try to lerp when the model has changed } static void @@ -255,7 +155,7 @@ CL_LinkPacketEntities (void) // spawn light flashes, even ones coming from invisible objects CL_NewDlight (i, new->origin, new->effects, new->glow_size, - new->glow_color); + new->glow_color, cl.time); // if set to invisible, skip if (!new->modelindex @@ -374,11 +274,11 @@ CL_LinkPacketEntities (void) CL_TransformEntity (ent, angles); } //CL_EntityEffects (i, ent, new); - //CL_NewDlight (i, ent->origin, new->effects, 0, 0); + //CL_NewDlight (i, ent->origin, new->effects, 0, 0, cl.time); if (VectorDistance_fast (old->origin, ent->origin) > (256 * 256)) VectorCopy (ent->origin, old->origin); if (renderer->model->flags & ~EF_ROTATE) { - CL_ModelEffects (ent, -new->number, new->glow_color); + CL_ModelEffects (ent, -new->number, new->glow_color, cl.time); } } } @@ -492,7 +392,7 @@ CL_LinkPlayers (void) QuatSet (0.0, 1.0, 0.0, 1.0, dl->color); } else { CL_NewDlight (j + 1, org, state->pls.effects, state->pls.glow_size, - state->pls.glow_color); + state->pls.glow_color, cl.time); } // Draw player? From abaccbec538ae18f9d9eb710c1d4815a9d69e6e1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 11 Mar 2021 11:38:33 +0900 Subject: [PATCH 396/435] [client] Move qw's loc code into client This makes the location code available to nq (not used yet) but more importantly moves some definitely client-side code into the right place. --- include/Makemodule.am | 3 ++ include/QF/Makemodule.am | 1 - include/{QF => client}/locs.h | 1 + libs/client/Makemodule.am | 1 + {qw/source => libs/client}/locs.c | 44 +++++++++++++++++++++++++-- libs/video/renderer/gl/gl_mod_alias.c | 1 - libs/video/renderer/gl/gl_rmain.c | 1 - libs/video/renderer/sw/sw_rmain.c | 1 - libs/video/renderer/sw32/sw32_rmain.c | 1 - qw/source/Makemodule.am | 2 +- qw/source/cl_entparse.c | 1 - qw/source/cl_ents.c | 32 ++----------------- qw/source/teamplay.c | 3 +- 13 files changed, 51 insertions(+), 41 deletions(-) rename include/{QF => client}/locs.h (97%) rename {qw/source => libs/client}/locs.c (84%) diff --git a/include/Makemodule.am b/include/Makemodule.am index 9fd003768..645a820bf 100644 --- a/include/Makemodule.am +++ b/include/Makemodule.am @@ -76,7 +76,10 @@ EXTRA_DIST += \ include/vregset.h \ include/winquake.h \ include/world.h \ + include/client/effects.h \ include/client/entities.h \ + include/client/temp_entities.h \ + include/client/locs.h \ include/qw/bothdefs.h \ include/qw/msg_backbuf.h \ include/qw/msg_ucmd.h \ diff --git a/include/QF/Makemodule.am b/include/QF/Makemodule.am index 5282d5230..aefd432f7 100644 --- a/include/QF/Makemodule.am +++ b/include/QF/Makemodule.am @@ -25,7 +25,6 @@ include_qf = \ include/QF/keys.h \ include/QF/link.h \ include/QF/llist.h \ - include/QF/locs.h \ include/QF/mathlib.h \ include/QF/mdfour.h \ include/QF/mersenne.h \ diff --git a/include/QF/locs.h b/include/client/locs.h similarity index 97% rename from include/QF/locs.h rename to include/client/locs.h index 4f7dc9b5c..8786c6532 100644 --- a/include/QF/locs.h +++ b/include/client/locs.h @@ -46,5 +46,6 @@ int locs_nearest (const vec3_t loc) __attribute__((pure)); void locs_reset (void); void locs_save (const char *filename, qboolean gz); void map_to_loc (const char *mapname, char *filename); +void locs_draw (vec3_t simorg); #endif//__QF_locs_h diff --git a/libs/client/Makemodule.am b/libs/client/Makemodule.am index 943f6bf9e..074daea58 100644 --- a/libs/client/Makemodule.am +++ b/libs/client/Makemodule.am @@ -6,4 +6,5 @@ libs_client_libQFclient_la_SOURCES= \ libs/client/cl_effects.c \ libs/client/cl_entities.c \ libs/client/cl_temp_entities.c \ + libs/client/locs.c \ $e diff --git a/qw/source/locs.c b/libs/client/locs.c similarity index 84% rename from qw/source/locs.c rename to libs/client/locs.c index ab92ec4c2..dd6a17d9f 100644 --- a/qw/source/locs.c +++ b/libs/client/locs.c @@ -41,15 +41,19 @@ #include -#include "QF/locs.h" +#include "QF/mathlib.h" +#include "QF/render.h" #include "QF/qtypes.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/va.h" -#include "compat.h" +#include "QF/plugin/vid_render.h" //FIXME -#include "qw/include/client.h" +#include "compat.h" +#include "d_iface.h" //FIXME part_tex_smoke and part_tex_dot + +#include "client/locs.h" #define LOCATION_BLOCK 128 // 128 locations per block. @@ -276,3 +280,37 @@ map_to_loc (const char *mapname, char *filename) t1++; strcpy (t1, "loc"); } + +void +locs_draw (vec3_t simorg) +{ + //FIXME custom ent rendering code would be nice + dlight_t *dl; + location_t *nearloc; + vec3_t trueloc; + int i; + + nearloc = locs_find (simorg); + if (nearloc) { + dl = r_funcs->R_AllocDlight (4096); + if (dl) { + VectorCopy (nearloc->loc, dl->origin); + dl->radius = 200; + dl->die = r_data->realtime + 0.1; + dl->color[0] = 0; + dl->color[1] = 1; + dl->color[2] = 0; + dl->color[3] = 0.7; + } + VectorCopy (nearloc->loc, trueloc); + r_funcs->particles->R_Particle_New (pt_smokecloud, part_tex_smoke, + trueloc, 2.0, + vec3_origin, r_data->realtime + 9.0, 254, + 0.25 + qfrandom (0.125), 0.0); + for (i = 0; i < 15; i++) + r_funcs->particles->R_Particle_NewRandom (pt_fallfade, + part_tex_dot, trueloc, 12, + 0.7, 96, r_data->realtime + 5.0, + 104 + (rand () & 7), 1.0, 0.0); + } +} diff --git a/libs/video/renderer/gl/gl_mod_alias.c b/libs/video/renderer/gl/gl_mod_alias.c index 8e4670a77..92c67038d 100644 --- a/libs/video/renderer/gl/gl_mod_alias.c +++ b/libs/video/renderer/gl/gl_mod_alias.c @@ -44,7 +44,6 @@ #include "QF/cvar.h" #include "QF/entity.h" -#include "QF/locs.h" #include "QF/mathlib.h" #include "QF/qargs.h" #include "QF/render.h" diff --git a/libs/video/renderer/gl/gl_rmain.c b/libs/video/renderer/gl/gl_rmain.c index 23d7f7be4..8079b790b 100644 --- a/libs/video/renderer/gl/gl_rmain.c +++ b/libs/video/renderer/gl/gl_rmain.c @@ -45,7 +45,6 @@ #include "QF/cvar.h" #include "QF/draw.h" #include "QF/entity.h" -#include "QF/locs.h" #include "QF/mathlib.h" #include "QF/qargs.h" #include "QF/render.h" diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 7cf5416c0..8ab480bcc 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -43,7 +43,6 @@ #include "QF/cmd.h" #include "QF/cvar.h" #include "QF/entity.h" -#include "QF/locs.h" #include "QF/mathlib.h" #include "QF/render.h" #include "QF/screen.h" diff --git a/libs/video/renderer/sw32/sw32_rmain.c b/libs/video/renderer/sw32/sw32_rmain.c index 812a43205..36d94fd2a 100644 --- a/libs/video/renderer/sw32/sw32_rmain.c +++ b/libs/video/renderer/sw32/sw32_rmain.c @@ -43,7 +43,6 @@ #include "QF/cmd.h" #include "QF/cvar.h" #include "QF/entity.h" -#include "QF/locs.h" #include "QF/mathlib.h" #include "QF/render.h" #include "QF/screen.h" diff --git a/qw/source/Makemodule.am b/qw/source/Makemodule.am index 00e30b4bc..bad7bd189 100644 --- a/qw/source/Makemodule.am +++ b/qw/source/Makemodule.am @@ -104,7 +104,7 @@ qw_source_libqw_client_a_SOURCES= \ qw/source/cl_entparse.c qw/source/cl_ents.c qw/source/cl_http.c qw/source/cl_input.c qw/source/cl_main.c qw/source/cl_ngraph.c \ qw/source/cl_parse.c qw/source/cl_pred.c qw/source/cl_rss.c qw/source/cl_screen.c qw/source/cl_skin.c qw/source/cl_slist.c \ qw/source/cl_view.c \ - qw/source/locs.c qw/source/sbar.c qw/source/teamplay.c + qw/source/sbar.c qw/source/teamplay.c # Software-rendering clients diff --git a/qw/source/cl_entparse.c b/qw/source/cl_entparse.c index 3a3d67264..ac7f0ae21 100644 --- a/qw/source/cl_entparse.c +++ b/qw/source/cl_entparse.c @@ -36,7 +36,6 @@ #endif #include "QF/cvar.h" -#include "QF/locs.h" #include "QF/msg.h" #include "QF/render.h" #include "QF/skin.h" diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 0cf0f835e..757cc7e56 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -37,7 +37,6 @@ #include "QF/cvar.h" #include "QF/entity.h" -#include "QF/locs.h" #include "QF/msg.h" #include "QF/render.h" #include "QF/skin.h" @@ -48,6 +47,7 @@ #include "d_iface.h" #include "client/effects.h" +#include "client/locs.h" #include "client/temp_entities.h" #include "qw/bothdefs.h" @@ -490,35 +490,7 @@ CL_EmitEntities (void) CL_LinkPacketEntities (); CL_UpdateTEnts (cl.time, &tentCtx); if (cl_draw_locs->int_val) { - //FIXME custom ent rendering code would be nice - dlight_t *dl; - location_t *nearloc; - vec3_t trueloc; - int i; - - nearloc = locs_find (cl.simorg); - if (nearloc) { - dl = r_funcs->R_AllocDlight (4096); - if (dl) { - VectorCopy (nearloc->loc, dl->origin); - dl->radius = 200; - dl->die = r_data->realtime + 0.1; - dl->color[0] = 0; - dl->color[1] = 1; - dl->color[2] = 0; - dl->color[3] = 0.7; - } - VectorCopy (nearloc->loc, trueloc); - r_funcs->particles->R_Particle_New (pt_smokecloud, part_tex_smoke, - trueloc, 2.0, - vec3_origin, r_data->realtime + 9.0, 254, - 0.25 + qfrandom (0.125), 0.0); - for (i = 0; i < 15; i++) - r_funcs->particles->R_Particle_NewRandom (pt_fallfade, - part_tex_dot, trueloc, 12, - 0.7, 96, r_data->realtime + 5.0, - 104 + (rand () & 7), 1.0, 0.0); - } + locs_draw (cl.simorg); } } diff --git a/qw/source/teamplay.c b/qw/source/teamplay.c index e8a38606d..75e6aefe3 100644 --- a/qw/source/teamplay.c +++ b/qw/source/teamplay.c @@ -43,7 +43,6 @@ #include "QF/cmd.h" #include "QF/cvar.h" #include "QF/gib.h" -#include "QF/locs.h" #include "QF/model.h" #include "QF/va.h" #include "QF/skin.h" @@ -52,6 +51,8 @@ #include "compat.h" +#include "client/locs.h" + #include "qw/bothdefs.h" #include "qw/include/cl_input.h" #include "qw/include/client.h" From c9bbc2971aea47af43c88b8383607ea38934d6f0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 11 Mar 2021 12:47:08 +0900 Subject: [PATCH 397/435] [qw] Rename view_message to view_state Makes more sense to me. --- qw/source/cl_view.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/qw/source/cl_view.c b/qw/source/cl_view.c index 08d4dd501..763de6767 100644 --- a/qw/source/cl_view.c +++ b/qw/source/cl_view.c @@ -82,7 +82,7 @@ cvar_t *v_idlescale; float v_dmg_time, v_dmg_roll, v_dmg_pitch; frame_t *view_frame; -player_state_t *view_message; +player_state_t *view_state; cshift_t cshift_empty = { {130, 80, 50}, 0}; cshift_t cshift_water = { {130, 80, 50}, 128}; @@ -189,7 +189,7 @@ V_DriftPitch (void) int frameno = (cls.netchan.outgoing_sequence - 1) & UPDATE_MASK; usercmd_t *cmd = &cl.frames[frameno].cmd; - if (view_message->onground == -1 || cls.demoplayback) { + if (view_state->onground == -1 || cls.demoplayback) { cl.driftmove = 0; cl.pitchvel = 0; return; @@ -600,7 +600,7 @@ V_CalcViewRoll (void) v_dmg_time -= host_frametime; } - if (view_message->pls.flags & PF_DEAD) // PF_GIB will also set PF_DEAD + if (view_state->pls.flags & PF_DEAD) // PF_GIB will also set PF_DEAD r_data->refdef->viewangles[ROLL] = 80; // dead view angle } @@ -700,12 +700,12 @@ V_CalcRefdef (void) else if (r_data->scr_viewsize->int_val == 80) view->origin[2] += 0.5; - if (view_message->pls.flags & (PF_GIB | PF_DEAD)) { + if (view_state->pls.flags & (PF_GIB | PF_DEAD)) { view->renderer.model = NULL; } else { view->renderer.model = cl.model_precache[cl.stats[STAT_WEAPON]]; } - view->animation.frame = view_message->pls.weaponframe; + view->animation.frame = view_state->pls.weaponframe; view->renderer.skin = 0; // set up the refresh position @@ -755,11 +755,11 @@ V_RenderView (void) return; view_frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK]; - view_message = &view_frame->playerstate[cl.playernum]; + view_state = &view_frame->playerstate[cl.playernum]; - if (view_message->pls.flags & PF_GIB) + if (view_state->pls.flags & PF_GIB) cl.viewheight = 8; // gib view height - else if (view_message->pls.flags & PF_DEAD) + else if (view_state->pls.flags & PF_DEAD) cl.viewheight = -16; // corpse view height else { cl.viewheight = DEFAULT_VIEWHEIGHT; // view height From ca38f9b616b802e8b0e783a3860d56cc2a42b7a0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 11 Mar 2021 14:27:36 +0900 Subject: [PATCH 398/435] [qw] Use entity_state_t as a base for player_state_t This will, in the long run, help clean up a lot of the differences in the handling of entities in the clients. --- include/client/entities.h | 6 +- include/qw/protocol.h | 19 +---- qtv/source/client.c | 60 +++++++-------- qtv/source/sv_parse.c | 46 ++++++------ qw/source/cl_cam.c | 32 ++++---- qw/source/cl_entparse.c | 61 ++++++++-------- qw/source/cl_ents.c | 34 ++++----- qw/source/cl_main.c | 4 +- qw/source/cl_pred.c | 41 ++++++----- qw/source/cl_view.c | 10 +-- qw/source/sv_ents.c | 150 +++++++++++++++++++------------------- 11 files changed, 225 insertions(+), 238 deletions(-) diff --git a/include/client/entities.h b/include/client/entities.h index 1dba394d6..45420cbb7 100644 --- a/include/client/entities.h +++ b/include/client/entities.h @@ -40,9 +40,11 @@ typedef struct entity_state_s { unsigned flags; // nolerp, etc vec3_t origin; + vec3_t velocity; vec3_t angles; - unsigned short modelindex; - unsigned short frame; + uint16_t modelindex; + uint16_t frame; + int weaponframe; int effects; byte colormap; byte skinnum; diff --git a/include/qw/protocol.h b/include/qw/protocol.h index 76f2c625d..9fb818d37 100644 --- a/include/qw/protocol.h +++ b/include/qw/protocol.h @@ -320,26 +320,9 @@ typedef struct usercmd_s { } usercmd_t; typedef struct plent_state_s { - int number; - - unsigned int flags; - vec3_t origin; + entity_state_t es; usercmd_t cmd; - vec3_t velocity; - int modelindex; - int frame; - int skinnum; - int effects; - int weaponframe; - byte msec; - - // QSG 2 - byte alpha; - byte scale; - byte glow_size; - byte glow_color; - byte colormod; } plent_state_t; typedef struct { diff --git a/qtv/source/client.c b/qtv/source/client.c index c55e57bd2..6da363953 100644 --- a/qtv/source/client.c +++ b/qtv/source/client.c @@ -446,9 +446,9 @@ spectator_move (client_t *cl, usercmd_t *ucmd) AngleVectors (cl->state.cmd.angles, forward, right, up); - speed = DotProduct (cl->state.velocity, cl->state.velocity); + speed = DotProduct (cl->state.es.velocity, cl->state.es.velocity); if (speed < 1) { - VectorZero (cl->state.velocity); + VectorZero (cl->state.es.velocity); } else { speed = sqrt (speed); drop = 0; @@ -462,7 +462,7 @@ spectator_move (client_t *cl, usercmd_t *ucmd) newspeed = 0; newspeed /= speed; - VectorScale (cl->state.velocity, newspeed, cl->state.velocity); + VectorScale (cl->state.es.velocity, newspeed, cl->state.es.velocity); } fmove = ucmd->forwardmove; @@ -484,7 +484,7 @@ spectator_move (client_t *cl, usercmd_t *ucmd) wishspeed = sv->movevars.spectatormaxspeed; } - currentspeed = DotProduct (cl->state.velocity, wishdir); + currentspeed = DotProduct (cl->state.es.velocity, wishdir); addspeed = wishspeed - currentspeed; if (addspeed <= 0) return; @@ -492,10 +492,10 @@ spectator_move (client_t *cl, usercmd_t *ucmd) if (accelspeed > addspeed) accelspeed = addspeed; - VectorMultAdd (cl->state.velocity, accelspeed, wishdir, - cl->state.velocity); - VectorMultAdd (cl->state.origin, frametime, cl->state.velocity, - cl->state.origin); + VectorMultAdd (cl->state.es.velocity, accelspeed, wishdir, + cl->state.es.velocity); + VectorMultAdd (cl->state.es.origin, frametime, cl->state.es.velocity, + cl->state.es.origin); } static void @@ -612,7 +612,7 @@ client_parse_message (client_t *cl) break; case clc_tmove: MSG_ReadCoordV (net_message, o); - VectorCopy (o, cl->state.origin); + VectorCopy (o, cl->state.es.origin); break; case clc_upload: size = MSG_ReadShort (net_message); @@ -627,18 +627,18 @@ static void write_player (int num, plent_state_t *pl, server_t *sv, sizebuf_t *msg) { int i; - int pflags = (pl->flags & (PF_GIB | PF_DEAD)) + int pflags = (pl->es.flags & (PF_GIB | PF_DEAD)) | PF_MSEC | PF_COMMAND; int qf_bits = 0; - if (pl->modelindex != sv->playermodel) + if (pl->es.modelindex != sv->playermodel) pflags |= PF_MODEL; for (i = 0; i < 3; i++) - if (pl->velocity[i]) + if (pl->es.velocity[i]) pflags |= PF_VELOCITY1 << i; - if (pl->effects & 0xff) + if (pl->es.effects & 0xff) pflags |= PF_EFFECTS; - if (pl->skinnum) + if (pl->es.skinnum) pflags |= PF_SKINNUM; qf_bits = 0; @@ -670,21 +670,21 @@ write_player (int num, plent_state_t *pl, server_t *sv, sizebuf_t *msg) // } else if (ent == clent) { // // don't send a lot of data on personal entity // pflags &= ~(PF_MSEC | PF_COMMAND); -// if (pl->weaponframe) +// if (pl->es.weaponframe) // pflags |= PF_WEAPONFRAME; // } // if (client->spec_track && client->spec_track - 1 == j -// && pl->weaponframe) +// && pl->es.weaponframe) // pflags |= PF_WEAPONFRAME; MSG_WriteByte (msg, svc_playerinfo); MSG_WriteByte (msg, num); MSG_WriteShort (msg, pflags); - MSG_WriteCoordV (msg, pl->origin); + MSG_WriteCoordV (msg, pl->es.origin); - MSG_WriteByte (msg, pl->frame); + MSG_WriteByte (msg, pl->es.frame); if (pflags & PF_MSEC) { //msec = 1000 * (sv.time - cl->localtime); @@ -699,36 +699,36 @@ write_player (int num, plent_state_t *pl, server_t *sv, sizebuf_t *msg) for (i = 0; i < 3; i++) if (pflags & (PF_VELOCITY1 << i)) - MSG_WriteShort (msg, pl->velocity[i]); + MSG_WriteShort (msg, pl->es.velocity[i]); if (pflags & PF_MODEL) - MSG_WriteByte (msg, pl->modelindex); + MSG_WriteByte (msg, pl->es.modelindex); if (pflags & PF_SKINNUM) - MSG_WriteByte (msg, pl->skinnum); + MSG_WriteByte (msg, pl->es.skinnum); if (pflags & PF_EFFECTS) - MSG_WriteByte (msg, pl->effects); + MSG_WriteByte (msg, pl->es.effects); if (pflags & PF_WEAPONFRAME) - MSG_WriteByte (msg, pl->weaponframe); + MSG_WriteByte (msg, pl->es.weaponframe); if (pflags & PF_QF) { MSG_WriteByte (msg, qf_bits); if (qf_bits & PF_ALPHA) - MSG_WriteByte (msg, pl->alpha); + MSG_WriteByte (msg, pl->es.alpha); if (qf_bits & PF_SCALE) - MSG_WriteByte (msg, pl->scale); + MSG_WriteByte (msg, pl->es.scale); if (qf_bits & PF_EFFECTS2) - MSG_WriteByte (msg, pl->effects >> 8); + MSG_WriteByte (msg, pl->es.effects >> 8); if (qf_bits & PF_GLOWSIZE) - MSG_WriteByte (msg, pl->scale); + MSG_WriteByte (msg, pl->es.glow_size); if (qf_bits & PF_GLOWCOLOR) - MSG_WriteByte (msg, pl->glow_color); + MSG_WriteByte (msg, pl->es.glow_color); if (qf_bits & PF_COLORMOD) - MSG_WriteByte (msg, pl->colormod); + MSG_WriteByte (msg, pl->es.colormod); if (qf_bits & PF_FRAME2) - MSG_WriteByte (msg, pl->frame >> 8); + MSG_WriteByte (msg, pl->es.frame >> 8); } } #if 0 diff --git a/qtv/source/sv_parse.c b/qtv/source/sv_parse.c index 493aa613a..268e9999d 100644 --- a/qtv/source/sv_parse.c +++ b/qtv/source/sv_parse.c @@ -514,9 +514,9 @@ parse_player_delta (qmsg_t *msg, plent_state_t *from, plent_state_t *to) int i; int flags; - flags = to->flags = MSG_ReadShort (msg); - MSG_ReadCoordV (msg, to->origin); - to->frame = (to->frame & 0xff00) | MSG_ReadByte (msg); + flags = to->es.flags = MSG_ReadShort (msg); + MSG_ReadCoordV (msg, to->es.origin); + to->es.frame = (to->es.frame & 0xff00) | MSG_ReadByte (msg); if (flags & PF_MSEC) to->msec = MSG_ReadByte (msg); // qtv_printf ("%02x\n", msg->message->data[msg->readcount]); @@ -524,36 +524,36 @@ parse_player_delta (qmsg_t *msg, plent_state_t *from, plent_state_t *to) MSG_ReadDeltaUsercmd (msg, &from->cmd, &to->cmd); for (i = 0; i < 3; i++) { if (flags & (PF_VELOCITY1 << i)) - to->velocity[i] = (short) MSG_ReadShort (msg); + to->es.velocity[i] = (short) MSG_ReadShort (msg); } if (flags & PF_MODEL) - to->modelindex = MSG_ReadByte (msg); + to->es.modelindex = MSG_ReadByte (msg); if (flags & PF_SKINNUM) - to->skinnum = MSG_ReadByte (msg); + to->es.skinnum = MSG_ReadByte (msg); if (flags & PF_EFFECTS) - to->effects = (to->effects & 0xff00) | MSG_ReadByte (msg); + to->es.effects = (to->es.effects & 0xff00) | MSG_ReadByte (msg); if (flags & PF_WEAPONFRAME) - to->weaponframe = MSG_ReadByte (msg); + to->es.weaponframe = MSG_ReadByte (msg); if (flags & PF_QF) { int bits; bits = MSG_ReadByte (msg); if (bits & PF_ALPHA) - to->alpha = MSG_ReadByte (msg); + to->es.alpha = MSG_ReadByte (msg); if (bits & PF_SCALE) - to->scale = MSG_ReadByte (msg); + to->es.scale = MSG_ReadByte (msg); if (bits & PF_EFFECTS2) - to->effects = (to->effects & 0x00ff) - | (MSG_ReadByte (msg) << 8); + to->es.effects = (to->es.effects & 0x00ff) + | (MSG_ReadByte (msg) << 8); if (bits & PF_GLOWSIZE) - to->glow_size = MSG_ReadByte (msg); + to->es.glow_size = MSG_ReadByte (msg); if (bits & PF_GLOWCOLOR) - to->glow_color = MSG_ReadByte (msg); + to->es.glow_color = MSG_ReadByte (msg); if (bits & PF_COLORMOD) - to->colormod = MSG_ReadByte (msg); + to->es.colormod = MSG_ReadByte (msg); if (bits & PF_FRAME2) - to->frame = (to->frame & 0xff) - | (MSG_ReadByte (msg) << 8); + to->es.frame = (to->es.frame & 0xff) + | (MSG_ReadByte (msg) << 8); } } @@ -567,12 +567,12 @@ sv_playerinfo (server_t *sv, qmsg_t *msg) int fromind, toind; static plent_state_t null_player_state; - if (!null_player_state.alpha) { - null_player_state.alpha = 255; - null_player_state.scale = 16; - null_player_state.glow_size = 0; - null_player_state.glow_color = 254; - null_player_state.colormod = 255; + if (!null_player_state.es.alpha) { + null_player_state.es.alpha = 255; + null_player_state.es.scale = 16; + null_player_state.es.glow_size = 0; + null_player_state.es.glow_color = 254; + null_player_state.es.colormod = 255; } fromind = MSG_ReadByte (msg); toind = sv->netchan.incoming_sequence & UPDATE_MASK; diff --git a/qw/source/cl_cam.c b/qw/source/cl_cam.c index 5a7f0d486..91e7a44eb 100644 --- a/qw/source/cl_cam.c +++ b/qw/source/cl_cam.c @@ -218,23 +218,23 @@ Cam_TryFlyby (player_state_t * self, player_state_t * player, vec3_t vec, vectoangles (vec, v); VectorCopy (v, pmove.angles); VectorNormalize (vec); - VectorMultAdd (player->pls.origin, 800, vec, v); + VectorMultAdd (player->pls.es.origin, 800, vec, v); // v is endpos // fake a player move - trace = Cam_DoTrace (player->pls.origin, v); + trace = Cam_DoTrace (player->pls.es.origin, v); if ( /* trace.inopen || */ trace.inwater) return 9999; VectorCopy (trace.endpos, vec); - len = VectorDistance (trace.endpos, player->pls.origin); + len = VectorDistance (trace.endpos, player->pls.es.origin); if (len < 32 || len > 800) return 9999; if (checkvis) { - trace = Cam_DoTrace (self->pls.origin, vec); + trace = Cam_DoTrace (self->pls.es.origin, vec); if (trace.fraction != 1 || trace.inwater) return 9999; - len = VectorDistance (trace.endpos, self->pls.origin); + len = VectorDistance (trace.endpos, self->pls.es.origin); } return len; @@ -248,11 +248,11 @@ Cam_IsVisible (player_state_t * player, vec3_t vec) trace_t trace; vec3_t v; - trace = Cam_DoTrace (player->pls.origin, vec); + trace = Cam_DoTrace (player->pls.es.origin, vec); if (trace.fraction != 1 || /* trace.inopen || */ trace.inwater) return false; // check distance, don't let the player get too far away or too close - VectorSubtract (player->pls.origin, vec, v); + VectorSubtract (player->pls.es.origin, vec, v); d = VectorLength (v); return (d > 16.0); @@ -440,22 +440,22 @@ Cam_Track (usercmd_t *cmd) cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; VectorCopy (player->viewangles, cl.viewangles); - VectorCopy (player->pls.origin, desired_position); - if (memcmp (&desired_position, &self->pls.origin, + VectorCopy (player->pls.es.origin, desired_position); + if (memcmp (&desired_position, &self->pls.es.origin, sizeof (desired_position)) != 0) { if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_tmove); MSG_WriteCoordV (&cls.netchan.message, desired_position); } // move there locally immediately - VectorCopy (desired_position, self->pls.origin); + VectorCopy (desired_position, self->pls.es.origin); } - self->pls.weaponframe = player->pls.weaponframe; + self->pls.es.weaponframe = player->pls.es.weaponframe; } else { // Ok, move to our desired position and set our angles to view // the player - VectorSubtract (desired_position, self->pls.origin, vec); + VectorSubtract (desired_position, self->pls.es.origin, vec); len = VectorLength (vec); cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; if (len > 16) { // close enough? @@ -465,9 +465,9 @@ Cam_Track (usercmd_t *cmd) } } // move there locally immediately - VectorCopy (desired_position, self->pls.origin); + VectorCopy (desired_position, self->pls.es.origin); - VectorSubtract (player->pls.origin, desired_position, vec); + VectorSubtract (player->pls.es.origin, desired_position, vec); vectoangles (vec, cl.viewangles); cl.viewangles[0] = -cl.viewangles[0]; } @@ -520,7 +520,7 @@ Cam_SetView (void) player = frame->playerstate + spec_track; self = frame->playerstate + cl.playernum; - VectorSubtract (player->pls.origin, cl.simorg, vec); + VectorSubtract (player->pls.es.origin, cl.simorg, vec); if (cam_forceview) { cam_forceview = false; vectoangles (vec, cam_viewangles); @@ -560,7 +560,7 @@ Cam_FinishMove (usercmd_t *cmd) player = frame->playerstate + spec_track; self = frame->playerstate + cl.playernum; - VectorSubtract (player->pls.origin, self->pls.origin, vec); + VectorSubtract (player->pls.es.origin, self->pls.es.origin, vec); if (cam_forceview) { cam_forceview = false; vectoangles (vec, cam_viewangles); diff --git a/qw/source/cl_entparse.c b/qw/source/cl_entparse.c index ac7f0ae21..b1b5d3386 100644 --- a/qw/source/cl_entparse.c +++ b/qw/source/cl_entparse.c @@ -360,7 +360,7 @@ CL_ParseDemoPlayerinfo (int num) info = &cl.players[num]; state = &cl.frames[parsecountmod].playerstate[num]; - state->pls.number = num; + state->pls.es.number = num; if (info->prevcount > cl.parsecount || !cl.parsecount) { prevstate = &dummy; @@ -383,25 +383,25 @@ CL_ParseDemoPlayerinfo (int num) memcpy (state, prevstate, sizeof (player_state_t)); flags = MSG_ReadShort (net_message); - state->pls.flags = TranslateFlags (flags); + state->pls.es.flags = TranslateFlags (flags); state->messagenum = cl.parsecount; state->pls.cmd.msec = 0; - state->pls.frame = MSG_ReadByte (net_message); + state->pls.es.frame = MSG_ReadByte (net_message); state->state_time = parsecounttime; for (i=0; i <3; i++) if (flags & (DF_ORIGIN << i)) - state->pls.origin[i] = MSG_ReadCoord (net_message); + state->pls.es.origin[i] = MSG_ReadCoord (net_message); for (i=0; i <3; i++) if (flags & (DF_ANGLES << i)) state->pls.cmd.angles[i] = MSG_ReadAngle16 (net_message); if (flags & DF_MODEL) - state->pls.modelindex = MSG_ReadByte (net_message); + state->pls.es.modelindex = MSG_ReadByte (net_message); if (flags & DF_SKINNUM) - state->pls.skinnum = MSG_ReadByte (net_message); + state->pls.es.skinnum = MSG_ReadByte (net_message); if (flags & DF_EFFECTS) - state->pls.effects = MSG_ReadByte (net_message); + state->pls.es.effects = MSG_ReadByte (net_message); if (flags & DF_WEAPONFRAME) - state->pls.weaponframe = MSG_ReadByte (net_message); + state->pls.es.weaponframe = MSG_ReadByte (net_message); VectorCopy (state->pls.cmd.angles, state->viewangles); } @@ -422,14 +422,14 @@ CL_ParsePlayerinfo (void) state = &cl.frames[parsecountmod].playerstate[num]; - state->pls.number = num; + state->pls.es.number = num; - flags = state->pls.flags = MSG_ReadShort (net_message); + flags = state->pls.es.flags = MSG_ReadShort (net_message); state->messagenum = cl.parsecount; - MSG_ReadCoordV (net_message, state->pls.origin); + MSG_ReadCoordV (net_message, state->pls.es.origin); - state->pls.frame = MSG_ReadByte (net_message); + state->pls.es.frame = MSG_ReadByte (net_message); // the other player's last move was likely some time // before the packet was sent out, so accurately track @@ -445,30 +445,30 @@ CL_ParsePlayerinfo (void) for (i = 0; i < 3; i++) { if (flags & (PF_VELOCITY1 << i)) - state->pls.velocity[i] = (short) MSG_ReadShort (net_message); + state->pls.es.velocity[i] = (short) MSG_ReadShort (net_message); else - state->pls.velocity[i] = 0; + state->pls.es.velocity[i] = 0; } if (flags & PF_MODEL) i = MSG_ReadByte (net_message); else i = cl_playerindex; - state->pls.modelindex = i; + state->pls.es.modelindex = i; if (flags & PF_SKINNUM) - state->pls.skinnum = MSG_ReadByte (net_message); + state->pls.es.skinnum = MSG_ReadByte (net_message); else - state->pls.skinnum = 0; + state->pls.es.skinnum = 0; if (flags & PF_EFFECTS) - state->pls.effects = MSG_ReadByte (net_message); + state->pls.es.effects = MSG_ReadByte (net_message); else - state->pls.effects = 0; + state->pls.es.effects = 0; if (flags & PF_WEAPONFRAME) - state->pls.weaponframe = MSG_ReadByte (net_message); + state->pls.es.weaponframe = MSG_ReadByte (net_message); else - state->pls.weaponframe = 0; + state->pls.es.weaponframe = 0; VectorCopy (state->pls.cmd.angles, state->viewangles); @@ -489,13 +489,13 @@ CL_ParsePlayerinfo (void) ent->scale = val / 16.0; } if (bits & PF_EFFECTS2) { - state->pls.effects |= MSG_ReadByte (net_message) << 8; + state->pls.es.effects |= MSG_ReadByte (net_message) << 8; } if (bits & PF_GLOWSIZE) { - state->pls.glow_size = MSG_ReadByte (net_message); + state->pls.es.glow_size = MSG_ReadByte (net_message); } if (bits & PF_GLOWCOLOR) { - state->pls.glow_color = MSG_ReadByte (net_message); + state->pls.es.glow_color = MSG_ReadByte (net_message); } if (bits & PF_COLORMOD) { float r = 1.0, g = 1.0, b = 1.0; @@ -508,7 +508,7 @@ CL_ParsePlayerinfo (void) VectorSet (r, g, b, ent->renderer.colormod); } if (bits & PF_FRAME2) { - state->pls.frame |= MSG_ReadByte (net_message) << 8; + state->pls.es.frame |= MSG_ReadByte (net_message) << 8; } } } @@ -599,22 +599,23 @@ CL_SetUpPlayerPrediction (qboolean dopred) if (state->messagenum != cl.parsecount) continue; // not present this frame - if (!state->pls.modelindex) + if (!state->pls.es.modelindex) continue; pplayer->active = true; - pplayer->flags = state->pls.flags; + pplayer->flags = state->pls.es.flags; // note that the local player is special, since he moves locally // we use his last predicted postition if (j == cl.playernum) { VectorCopy (cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK]. - playerstate[cl.playernum].pls.origin, pplayer->origin); + playerstate[cl.playernum].pls.es.origin, + pplayer->origin); } else { // predict only half the move to minimize overruns msec = 500 * (playertime - state->state_time); if (msec <= 0 || !dopred) { - VectorCopy (state->pls.origin, pplayer->origin); + VectorCopy (state->pls.es.origin, pplayer->origin); // Sys_MaskPrintf (SYS_DEV, "nopredict\n"); } else { // predict players movement @@ -622,7 +623,7 @@ CL_SetUpPlayerPrediction (qboolean dopred) // Sys_MaskPrintf (SYS_DEV, "predict: %i\n", msec); CL_PredictUsercmd (state, &exact, &state->pls.cmd, false); - VectorCopy (exact.pls.origin, pplayer->origin); + VectorCopy (exact.pls.es.origin, pplayer->origin); } } } diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 757cc7e56..1e8ab80d9 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -349,7 +349,7 @@ static void CL_LinkPlayers (void) { double playertime; - int msec, oldphysent, i, j; + int msec, oldphysent, j; entity_t *ent; frame_t *frame; player_info_t *info; @@ -381,7 +381,7 @@ CL_LinkPlayers (void) r_data->player_entity = &cl_player_ents[j]; clientplayer = true; } else { - VectorCopy (state->pls.origin, org); + VectorCopy (state->pls.es.origin, org); clientplayer = false; } if (info->chat && info->chat->value[0] != '0') { @@ -391,28 +391,28 @@ CL_LinkPlayers (void) dl->die = cl.time + 0.1; QuatSet (0.0, 1.0, 0.0, 1.0, dl->color); } else { - CL_NewDlight (j + 1, org, state->pls.effects, state->pls.glow_size, - state->pls.glow_color, cl.time); + CL_NewDlight (j + 1, org, state->pls.es.effects, + state->pls.es.glow_size, state->pls.es.glow_color, + cl.time); } // Draw player? if (!Cam_DrawPlayer (j)) continue; - if (!state->pls.modelindex) + if (!state->pls.es.modelindex) continue; // Hack hack hack if (cl_deadbodyfilter->int_val - && state->pls.modelindex == cl_playerindex - && ((i = state->pls.frame) == 49 || i == 60 || i == 69 || i == 84 - || i == 93 || i == 102)) + && state->pls.es.modelindex == cl_playerindex + && is_dead_body (&state->pls.es)) continue; // predict only half the move to minimize overruns msec = 500 * (playertime - state->state_time); if (msec <= 0 || (!cl_predict_players->int_val) || cls.demoplayback2) { - VectorCopy (state->pls.origin, ent->origin); + VectorCopy (state->pls.es.origin, ent->origin); } else { // predict players movement state->pls.cmd.msec = msec = min (msec, 255); @@ -420,7 +420,7 @@ CL_LinkPlayers (void) CL_SetSolidPlayers (j); CL_PredictUsercmd (state, &exact, &state->pls.cmd, clientplayer); pmove.numphysent = oldphysent; - VectorCopy (exact.pls.origin, ent->origin); + VectorCopy (exact.pls.es.origin, ent->origin); } // angles @@ -432,18 +432,18 @@ CL_LinkPlayers (void) ang[PITCH] = -state->viewangles[PITCH] / 3.0; ang[YAW] = state->viewangles[YAW]; } - ang[ROLL] = V_CalcRoll (ang, state->pls.velocity) * 4.0; + ang[ROLL] = V_CalcRoll (ang, state->pls.es.velocity) * 4.0; - ent->renderer.model = cl.model_precache[state->pls.modelindex]; - ent->animation.frame = state->pls.frame; - ent->renderer.skinnum = state->pls.skinnum; + ent->renderer.model = cl.model_precache[state->pls.es.modelindex]; + ent->animation.frame = state->pls.es.frame; + ent->renderer.skinnum = state->pls.es.skinnum; CL_TransformEntity (ent, ang); ent->renderer.min_light = 0; ent->renderer.fullbright = 0; - if (state->pls.modelindex == cl_playerindex) { //XXX + if (state->pls.es.modelindex == cl_playerindex) { //XXX // use custom skin ent->renderer.skin = info->skin; @@ -460,9 +460,9 @@ CL_LinkPlayers (void) // stuff entity in map r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); - if (state->pls.effects & EF_FLAG1) + if (state->pls.es.effects & EF_FLAG1) CL_AddFlagModels (ent, 0, j); - else if (state->pls.effects & EF_FLAG2) + else if (state->pls.es.effects & EF_FLAG2) CL_AddFlagModels (ent, 1, j); } } diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index 656d6eb57..ea143c9ae 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -1631,8 +1631,8 @@ Host_Frame (float time) oldself = &cl.frames[(cls.netchan.outgoing_sequence - 1) & UPDATE_MASK].playerstate[cl.playernum]; self->messagenum = cl.parsecount; - VectorCopy (oldself->pls.origin, self->pls.origin); - VectorCopy (oldself->pls.velocity, self->pls.velocity); + VectorCopy (oldself->pls.es.origin, self->pls.es.origin); + VectorCopy (oldself->pls.es.velocity, self->pls.es.velocity); VectorCopy (oldself->viewangles, self->viewangles); CL_ParseClientdata (); diff --git a/qw/source/cl_pred.c b/qw/source/cl_pred.c index 1ac6e5ca1..1fe115949 100644 --- a/qw/source/cl_pred.c +++ b/qw/source/cl_pred.c @@ -51,10 +51,10 @@ CL_PredictUsercmd (player_state_t * from, player_state_t * to, usercmd_t *u, qboolean clientplayer) { if (!clientplayer) { - if (VectorIsZero (from->pls.velocity)) { - VectorCopy (from->pls.origin, to->pls.origin); + if (VectorIsZero (from->pls.es.velocity)) { + VectorCopy (from->pls.es.origin, to->pls.es.origin); VectorCopy (u->angles, to->viewangles); - VectorCopy (from->pls.velocity, to->pls.velocity); + VectorCopy (from->pls.es.velocity, to->pls.es.velocity); return; } } @@ -72,9 +72,9 @@ CL_PredictUsercmd (player_state_t * from, player_state_t * to, usercmd_t *u, return; } - VectorCopy (from->pls.origin, pmove.origin); + VectorCopy (from->pls.es.origin, pmove.origin); VectorCopy (u->angles, pmove.angles); - VectorCopy (from->pls.velocity, pmove.velocity); + VectorCopy (from->pls.es.velocity, pmove.velocity); pmove.oldbuttons = from->oldbuttons; pmove.oldonground = from->oldonground; @@ -92,11 +92,11 @@ CL_PredictUsercmd (player_state_t * from, player_state_t * to, usercmd_t *u, to->waterjumptime = pmove.waterjumptime; to->oldbuttons = pmove.oldbuttons; // Tonik to->oldonground = pmove.oldonground; - VectorCopy (pmove.origin, to->pls.origin); + VectorCopy (pmove.origin, to->pls.es.origin); VectorCopy (pmove.angles, to->viewangles); - VectorCopy (pmove.velocity, to->pls.velocity); + VectorCopy (pmove.velocity, to->pls.es.velocity); to->onground = onground; - to->pls.weaponframe = from->pls.weaponframe; + to->pls.es.weaponframe = from->pls.es.weaponframe; } void @@ -137,8 +137,8 @@ CL_PredictMove (void) from = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK]; if (!cl_predict->int_val) { - VectorCopy (from->playerstate[cl.playernum].pls.velocity, cl.simvel); - VectorCopy (from->playerstate[cl.playernum].pls.origin, cl.simorg); + VectorCopy (from->playerstate[cl.playernum].pls.es.velocity, cl.simvel); + VectorCopy (from->playerstate[cl.playernum].pls.es.origin, cl.simorg); return; } @@ -175,21 +175,22 @@ CL_PredictMove (void) } for (i = 0; i < 3; i++) - if (fabs (from->playerstate[cl.playernum].pls.origin[i] - - to->playerstate[cl.playernum].pls.origin[i]) > 128) { + if (fabs (from->playerstate[cl.playernum].pls.es.origin[i] - + to->playerstate[cl.playernum].pls.es.origin[i]) > 128) { // teleported, so don't lerp - VectorCopy (to->playerstate[cl.playernum].pls.velocity, cl.simvel); - VectorCopy (to->playerstate[cl.playernum].pls.origin, cl.simorg); + VectorCopy (to->playerstate[cl.playernum].pls.es.velocity, + cl.simvel); + VectorCopy (to->playerstate[cl.playernum].pls.es.origin, cl.simorg); return; } for (i = 0; i < 3; i++) { - cl.simorg[i] = from->playerstate[cl.playernum].pls.origin[i] + - f * (to->playerstate[cl.playernum].pls.origin[i] - - from->playerstate[cl.playernum].pls.origin[i]); - cl.simvel[i] = from->playerstate[cl.playernum].pls.velocity[i] + - f * (to->playerstate[cl.playernum].pls.velocity[i] - - from->playerstate[cl.playernum].pls.velocity[i]); + cl.simorg[i] = from->playerstate[cl.playernum].pls.es.origin[i] + + f * (to->playerstate[cl.playernum].pls.es.origin[i] - + from->playerstate[cl.playernum].pls.es.origin[i]); + cl.simvel[i] = from->playerstate[cl.playernum].pls.es.velocity[i] + + f * (to->playerstate[cl.playernum].pls.es.velocity[i] - + from->playerstate[cl.playernum].pls.es.velocity[i]); } } diff --git a/qw/source/cl_view.c b/qw/source/cl_view.c index 763de6767..3b1ca0688 100644 --- a/qw/source/cl_view.c +++ b/qw/source/cl_view.c @@ -600,7 +600,7 @@ V_CalcViewRoll (void) v_dmg_time -= host_frametime; } - if (view_state->pls.flags & PF_DEAD) // PF_GIB will also set PF_DEAD + if (view_state->pls.es.flags & PF_DEAD) // PF_GIB will also set PF_DEAD r_data->refdef->viewangles[ROLL] = 80; // dead view angle } @@ -700,12 +700,12 @@ V_CalcRefdef (void) else if (r_data->scr_viewsize->int_val == 80) view->origin[2] += 0.5; - if (view_state->pls.flags & (PF_GIB | PF_DEAD)) { + if (view_state->pls.es.flags & (PF_GIB | PF_DEAD)) { view->renderer.model = NULL; } else { view->renderer.model = cl.model_precache[cl.stats[STAT_WEAPON]]; } - view->animation.frame = view_state->pls.weaponframe; + view->animation.frame = view_state->pls.es.weaponframe; view->renderer.skin = 0; // set up the refresh position @@ -757,9 +757,9 @@ V_RenderView (void) view_frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK]; view_state = &view_frame->playerstate[cl.playernum]; - if (view_state->pls.flags & PF_GIB) + if (view_state->pls.es.flags & PF_GIB) cl.viewheight = 8; // gib view height - else if (view_state->pls.flags & PF_DEAD) + else if (view_state->pls.es.flags & PF_DEAD) cl.viewheight = -16; // corpse view height else { cl.viewheight = DEFAULT_VIEWHEIGHT; // view height diff --git a/qw/source/sv_ents.c b/qw/source/sv_ents.c index a5d6b4db9..50c7a3d97 100644 --- a/qw/source/sv_ents.c +++ b/qw/source/sv_ents.c @@ -400,7 +400,7 @@ write_demoplayer (delta_t *delta, plent_state_t *from, plent_state_t *to, int flags; int j; - flags = to->flags >> 1; // convert PF_(GIB|DEAD) to DF_(GIB|DEAD) + flags = to->es.flags >> 1; // convert PF_(GIB|DEAD) to DF_(GIB|DEAD) flags &= DF_GIB | DF_DEAD; // PF_MSEC and PF_COMMAND aren't wanted if (full) { flags |= DF_ORIGIN | (DF_ORIGIN << 1) | (DF_ORIGIN << 2) @@ -408,55 +408,55 @@ write_demoplayer (delta_t *delta, plent_state_t *from, plent_state_t *to, | DF_EFFECTS | DF_SKINNUM | DF_WEAPONFRAME | DF_MODEL; } else { for (j = 0; j < 3; j++) - if (from->origin[j] != to->origin[j]) + if (from->es.origin[j] != to->es.origin[j]) flags |= DF_ORIGIN << j; for (j = 0; j < 3; j++) if (from->cmd.angles[j] != to->cmd.angles[j]) flags |= DF_ANGLES << j; - if (from->modelindex != to->modelindex) + if (from->es.modelindex != to->es.modelindex) flags |= DF_MODEL; - if ((from->effects & 0xff) != (to->effects & 0xff)) + if ((from->es.effects & 0xff) != (to->es.effects & 0xff)) flags |= DF_EFFECTS; - if (from->skinnum != to->skinnum) + if (from->es.skinnum != to->es.skinnum) flags |= DF_SKINNUM; - if (from->weaponframe != to->weaponframe) + if (from->es.weaponframe != to->es.weaponframe) flags |= DF_WEAPONFRAME; } MSG_WriteByte (msg, svc_playerinfo); - MSG_WriteByte (msg, to->number); + MSG_WriteByte (msg, to->es.number); MSG_WriteShort (msg, flags); - MSG_WriteByte (msg, to->frame); + MSG_WriteByte (msg, to->es.frame); for (j = 0; j < 3; j++) if (flags & (DF_ORIGIN << j)) - MSG_WriteCoord (msg, to->origin[j]); + MSG_WriteCoord (msg, to->es.origin[j]); for (j = 0; j < 3; j++) if (flags & (DF_ANGLES << j)) MSG_WriteAngle16 (msg, to->cmd.angles[j]); if (flags & DF_MODEL) - MSG_WriteByte (msg, to->modelindex); + MSG_WriteByte (msg, to->es.modelindex); if (flags & DF_SKINNUM) - MSG_WriteByte (msg, to->skinnum); + MSG_WriteByte (msg, to->es.skinnum); if (flags & DF_EFFECTS) - MSG_WriteByte (msg, to->effects); + MSG_WriteByte (msg, to->es.effects); if (flags & DF_WEAPONFRAME) - MSG_WriteByte (msg, to->weaponframe); + MSG_WriteByte (msg, to->es.weaponframe); } static void write_player (delta_t *delta, plent_state_t *from, plent_state_t *to, sizebuf_t *msg, int mask, int full) { - int flags = to->flags; + int flags = to->es.flags; int qf_bits = 0; int i; int ds = delta->delta_sequence & 0x7f; @@ -472,30 +472,30 @@ write_player (delta_t *delta, plent_state_t *from, plent_state_t *to, ds = -1; } else { for (i = 0; i < 3; i++) - if (from->velocity[i] != to->velocity[i]) + if (from->es.velocity[i] != to->es.velocity[i]) flags |= PF_VELOCITY1 << i; - if (from->modelindex != to->modelindex) + if (from->es.modelindex != to->es.modelindex) flags |= PF_MODEL; - if (from->skinnum != to->skinnum) + if (from->es.skinnum != to->es.skinnum) flags |= PF_SKINNUM; - if ((from->effects & 0xff) != (to->effects &0xff)) + if ((from->es.effects & 0xff) != (to->es.effects &0xff)) flags |= PF_EFFECTS; - if (from->weaponframe != to->weaponframe) + if (from->es.weaponframe != to->es.weaponframe) flags |= PF_WEAPONFRAME; - if (from->alpha != to->alpha) + if (from->es.alpha != to->es.alpha) qf_bits |= PF_ALPHA; - if (from->scale != to->scale) + if (from->es.scale != to->es.scale) qf_bits |= PF_SCALE; - if ((from->effects & 0xff00) != (to->effects & 0xff00)) + if ((from->es.effects & 0xff00) != (to->es.effects & 0xff00)) qf_bits |= PF_EFFECTS2; - if (from->glow_size != to->glow_size) + if (from->es.glow_size != to->es.glow_size) qf_bits |= PF_GLOWSIZE; - if (from->glow_color != to->glow_color) + if (from->es.glow_color != to->es.glow_color) qf_bits |= PF_GLOWCOLOR; - if (from->colormod != to->colormod) + if (from->es.colormod != to->es.colormod) qf_bits |= PF_COLORMOD; - if ((from->frame & 0xff00) != (to->frame & 0xff00)) + if ((from->es.frame & 0xff00) != (to->es.frame & 0xff00)) qf_bits |= PF_FRAME2; if (qf_bits) flags |= PF_QF; @@ -506,12 +506,12 @@ write_player (delta_t *delta, plent_state_t *from, plent_state_t *to, MSG_WriteByte (msg, svc_playerinfo); if (delta->type == dt_tp_qtv) MSG_WriteByte (msg, ds); - MSG_WriteByte (msg, to->number); + MSG_WriteByte (msg, to->es.number); MSG_WriteShort (msg, flags); - MSG_WriteCoordV (msg, to->origin); + MSG_WriteCoordV (msg, to->es.origin); - MSG_WriteByte (msg, to->frame); + MSG_WriteByte (msg, to->es.frame); if (flags & PF_MSEC) MSG_WriteByte (msg, to->msec); @@ -519,32 +519,32 @@ write_player (delta_t *delta, plent_state_t *from, plent_state_t *to, MSG_WriteDeltaUsercmd (msg, &from->cmd, &to->cmd); for (i = 0; i < 3; i++) if (flags & (PF_VELOCITY1 << i)) - MSG_WriteShort (msg, to->velocity[i]); + MSG_WriteShort (msg, to->es.velocity[i]); if (flags & PF_MODEL) - MSG_WriteByte (msg, to->modelindex); + MSG_WriteByte (msg, to->es.modelindex); if (flags & PF_SKINNUM) - MSG_WriteByte (msg, to->skinnum); + MSG_WriteByte (msg, to->es.skinnum); if (flags & PF_EFFECTS) - MSG_WriteByte (msg, to->effects); + MSG_WriteByte (msg, to->es.effects); if (flags & PF_WEAPONFRAME) - MSG_WriteByte (msg, to->weaponframe); + MSG_WriteByte (msg, to->es.weaponframe); if (flags & PF_QF) { MSG_WriteByte (msg, qf_bits); if (qf_bits & PF_ALPHA) - MSG_WriteByte (msg, to->alpha); + MSG_WriteByte (msg, to->es.alpha); if (qf_bits & PF_SCALE) - MSG_WriteByte (msg, to->scale); + MSG_WriteByte (msg, to->es.scale); if (qf_bits & PF_EFFECTS2) - MSG_WriteByte (msg, to->effects >> 8); + MSG_WriteByte (msg, to->es.effects >> 8); if (qf_bits & PF_GLOWSIZE) - MSG_WriteByte (msg, to->glow_size); + MSG_WriteByte (msg, to->es.glow_size); if (qf_bits & PF_GLOWCOLOR) - MSG_WriteByte (msg, to->glow_color); + MSG_WriteByte (msg, to->es.glow_color); if (qf_bits & PF_COLORMOD) - MSG_WriteByte (msg, to->colormod); + MSG_WriteByte (msg, to->es.colormod); if (qf_bits & PF_FRAME2) - MSG_WriteByte (msg, to->frame); + MSG_WriteByte (msg, to->es.frame); } } @@ -566,19 +566,19 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg) void (*write) (delta_t *, plent_state_t *, plent_state_t *, sizebuf_t *, int, int); - if (!null_player_state.alpha) { - null_player_state.alpha = 255; - null_player_state.scale = 16; - null_player_state.glow_size = 0; - null_player_state.glow_color = 254; - null_player_state.colormod = 255; + if (!null_player_state.es.alpha) { + null_player_state.es.alpha = 255; + null_player_state.es.scale = 16; + null_player_state.es.glow_size = 0; + null_player_state.es.glow_color = 254; + null_player_state.es.colormod = 255; } - null_player_state.modelindex = 0; + null_player_state.es.modelindex = 0; if (delta->client) { clent = delta->client->edict; spec_track = delta->client->spec_track; - null_player_state.modelindex = sv_playermodel; + null_player_state.es.modelindex = sv_playermodel; full = 0; // normal qw clients don't get real deltas on players } @@ -625,9 +625,9 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg) state = &pack->players[pack->num_players]; pack->num_players++; - state->number = j; - state->flags = 0; - VectorCopy (SVvector (ent, origin), state->origin); + state->es.number = j; + state->es.flags = 0; + VectorCopy (SVvector (ent, origin), state->es.origin); state->msec = min (255, 1000 * (sv.time - cl->localtime)); @@ -639,44 +639,44 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg) state->cmd.angles[0] = 0; } - VectorCopy (SVvector (ent, velocity), state->velocity); - state->modelindex = SVfloat (ent, modelindex); - state->frame = SVfloat (ent, frame); - state->skinnum = SVfloat (ent, skin); - state->effects = SVfloat (ent, effects); - state->weaponframe = SVfloat (ent, weaponframe); + VectorCopy (SVvector (ent, velocity), state->es.velocity); + state->es.modelindex = SVfloat (ent, modelindex); + state->es.frame = SVfloat (ent, frame); + state->es.skinnum = SVfloat (ent, skin); + state->es.effects = SVfloat (ent, effects); + state->es.weaponframe = SVfloat (ent, weaponframe); if (SVfloat (ent, health) <= 0) - state->flags |= PF_DEAD; + state->es.flags |= PF_DEAD; if (SVvector (ent, mins)[2] != -24) - state->flags |= PF_GIB; - state->flags |= PF_MSEC | PF_COMMAND; + state->es.flags |= PF_GIB; + state->es.flags |= PF_MSEC | PF_COMMAND; - state->alpha = 255; - state->scale = 16; - state->glow_size = 0; - state->glow_color = 254; - state->colormod = 255; + state->es.alpha = 255; + state->es.scale = 16; + state->es.glow_size = 0; + state->es.glow_color = 254; + state->es.colormod = 255; if (sv_fields.alpha != -1 && SVfloat (ent, alpha)) { float alpha = SVfloat (ent, alpha); - state->alpha = bound (0, alpha, 1) * 255.0; + state->es.alpha = bound (0, alpha, 1) * 255.0; } if (sv_fields.scale != -1 && SVfloat (ent, scale)) { float scale = SVfloat (ent, scale); - state->scale = bound (0, scale, 15.9375) * 16; + state->es.scale = bound (0, scale, 15.9375) * 16; } if (sv_fields.glow_size != -1 && SVfloat (ent, glow_size)) { int glow_size = SVfloat (ent, glow_size); - state->glow_size = bound (-1024, glow_size, 1016) >> 3; + state->es.glow_size = bound (-1024, glow_size, 1016) >> 3; } if (sv_fields.glow_color != -1 && SVfloat (ent, glow_color)) - state->glow_color = SVfloat (ent, glow_color); + state->es.glow_color = SVfloat (ent, glow_color); if (sv_fields.colormod != -1 && !VectorIsZero (SVvector (ent, colormod))) { float *colormod= SVvector (ent, colormod); - state->colormod = ((int) (bound (0, colormod[0], 1) * 7) << 5) | - ((int) (bound (0, colormod[1], 1) * 7) << 2) | - (int) (bound (0, colormod[2], 1) * 3); + state->es.colormod = ((int) (bound (0, colormod[0], 1) * 7) << 5) | + ((int) (bound (0, colormod[1], 1) * 7) << 2) | + (int) (bound (0, colormod[2], 1) * 3); } if (cl->spectator) { @@ -693,10 +693,10 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg) if (from_pack && from_pack->players) { while (k < from_pack->num_players - && from_pack->players[k].number < state->number) + && from_pack->players[k].es.number < state->es.number) k++; if (k < from_pack->num_players - && from_pack->players[k].number == state->number) { + && from_pack->players[k].es.number == state->es.number) { write (delta, &from_pack->players[k], state, msg, mask, full); continue; } From 36761192a6d6ff1f037ee0a49e746b93c01dede9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 11 Mar 2021 15:23:35 +0900 Subject: [PATCH 399/435] [qw] Partially clean up muzzle flash handling It needs some more work (see FIXME in the code). --- include/client/effects.h | 4 ++++ libs/client/cl_effects.c | 39 ++++++++++++++++++++++----------------- qw/source/cl_parse.c | 30 ++++++++++++------------------ 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/include/client/effects.h b/include/client/effects.h index 1f1259274..9fea133d2 100644 --- a/include/client/effects.h +++ b/include/client/effects.h @@ -30,6 +30,8 @@ #ifndef __client_effects_h #define __client_effects_h +#include "QF/simd/types.h" + struct entity_s; struct entity_state_s; @@ -39,5 +41,7 @@ void CL_ModelEffects (struct entity_s *ent, int num, int glow_color, double time); void CL_EntityEffects (int num, struct entity_s *ent, struct entity_state_s *state, double time); +void CL_MuzzleFlash (vec4f_t position, vec4f_t fv, float zoffset, int num, + double time); #endif//__client_effects_h diff --git a/libs/client/cl_effects.c b/libs/client/cl_effects.c index 3030431a8..cc702587c 100644 --- a/libs/client/cl_effects.c +++ b/libs/client/cl_effects.c @@ -148,28 +148,33 @@ CL_ModelEffects (entity_t *ent, int num, int glow_color, double time) r_funcs->particles->R_GlowTrail (ent, glow_color); } +void +CL_MuzzleFlash (vec4f_t position, vec4f_t fv, float zoffset, int num, + double time) +{ + dlight_t *dl = r_funcs->R_AllocDlight (num); + if (dl) { + position += 18 * fv; + VectorCopy (position, dl->origin); + dl->origin[2] += zoffset; + dl->radius = 200 + (rand () & 31); + dl->die = time + 0.1; + dl->minlight = 32; + dl->color[0] = 0.2; + dl->color[1] = 0.1; + dl->color[2] = 0.05; + dl->color[3] = 0.7; + } +} + void CL_EntityEffects (int num, entity_t *ent, entity_state_t *state, double time) { - dlight_t *dl; - if (state->effects & EF_BRIGHTFIELD) r_funcs->particles->R_EntityParticles (ent); if (state->effects & EF_MUZZLEFLASH) { - dl = r_funcs->R_AllocDlight (num); - if (dl) { - vec4f_t position = Transform_GetWorldPosition (ent->transform); - vec4f_t fv = Transform_Forward (ent->transform); - position += 18 * fv; - VectorCopy (position, dl->origin); - dl->origin[2] += 16; - dl->radius = 200 + (rand () & 31); - dl->die = time + 0.1; - dl->minlight = 32; - dl->color[0] = 0.2; - dl->color[1] = 0.1; - dl->color[2] = 0.05; - dl->color[3] = 0.7; - } + vec4f_t position = Transform_GetWorldPosition (ent->transform); + vec4f_t fv = Transform_Forward (ent->transform); + CL_MuzzleFlash (position, fv, 16, num, time); } } diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 7366b4da0..095f636bc 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -65,6 +65,7 @@ #include "clview.h" #include "sbar.h" +#include "client/effects.h" #include "client/temp_entities.h" #include "qw/bothdefs.h" @@ -1255,12 +1256,14 @@ CL_SetStat (int stat, int value) } static void -CL_MuzzleFlash (void) +CL_ParseMuzzleFlash (void) { - dlight_t *dl; + //FIXME this should just enable the effect on the relevant entity and + //then automatic entity updates take care of the rest int i; player_state_t *pl; - vec3_t fv, rv, uv; + vec3_t f, r, u; + vec4f_t position = { 0, 0, 0, 1}, fv = {}; i = MSG_ReadShort (net_message); @@ -1269,23 +1272,14 @@ CL_MuzzleFlash (void) pl = &cl.frames[parsecountmod].playerstate[i - 1]; - dl = r_funcs->R_AllocDlight (i); - if (!dl) - return; - if (i - 1 == cl.playernum) - AngleVectors (cl.viewangles, fv, rv, uv); + AngleVectors (cl.viewangles, f, r, u); else - AngleVectors (pl->viewangles, fv, rv, uv); + AngleVectors (pl->viewangles, f, r, u); - VectorMultAdd (pl->pls.origin, 18, fv, dl->origin); - dl->radius = 200 + (rand () & 31); - dl->die = cl.time + 0.1; - dl->minlight = 32; - dl->color[0] = 0.2; - dl->color[1] = 0.1; - dl->color[2] = 0.05; - dl->color[3] = 0.7; + VectorCopy (f, fv); + VectorCopy (pl->pls.es.origin, position); + CL_MuzzleFlash (position, fv, 0, i, cl.time); } #define SHOWNET(x) \ @@ -1621,7 +1615,7 @@ CL_ParseServerMessage (void) break; case svc_muzzleflash: - CL_MuzzleFlash (); + CL_ParseMuzzleFlash (); break; case svc_updateuserinfo: From 8466de2325a874d787b422f84e95d044793cef90 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 11 Mar 2021 16:19:49 +0900 Subject: [PATCH 400/435] [client] Use vec4_t in entity_state_t And clean up the mess (sort of:P) --- include/client/effects.h | 2 +- include/client/entities.h | 5 +++-- include/client/locs.h | 19 ++++++++++--------- include/clview.h | 3 ++- libs/client/cl_effects.c | 2 +- libs/client/locs.c | 31 +++++++++++++++++-------------- nq/include/client.h | 8 ++++---- nq/source/cl_demo.c | 4 ++-- nq/source/cl_ents.c | 16 ++++++++-------- nq/source/cl_parse.c | 13 +++++++------ nq/source/cl_view.c | 12 +++++++----- nq/source/sv_main.c | 3 ++- qtv/source/client.c | 3 ++- qtv/source/sv_parse.c | 5 +++-- qw/include/client.h | 4 ++-- qw/source/cl_cam.c | 8 ++++---- qw/source/cl_demo.c | 2 +- qw/source/cl_entparse.c | 2 +- qw/source/cl_ents.c | 7 ++++--- qw/source/cl_parse.c | 6 ++++-- qw/source/cl_pred.c | 11 +++-------- qw/source/cl_view.c | 20 +++++++++++--------- qw/source/sv_ents.c | 2 +- qw/source/sv_init.c | 4 ++-- qw/source/teamplay.c | 8 ++++---- 25 files changed, 106 insertions(+), 94 deletions(-) diff --git a/include/client/effects.h b/include/client/effects.h index 9fea133d2..dbec75769 100644 --- a/include/client/effects.h +++ b/include/client/effects.h @@ -35,7 +35,7 @@ struct entity_s; struct entity_state_s; -void CL_NewDlight (int key, vec3_t org, int effects, byte glow_size, +void CL_NewDlight (int key, vec4f_t org, int effects, byte glow_size, byte glow_color, double time); void CL_ModelEffects (struct entity_s *ent, int num, int glow_color, double time); diff --git a/include/client/entities.h b/include/client/entities.h index 45420cbb7..fda534295 100644 --- a/include/client/entities.h +++ b/include/client/entities.h @@ -32,6 +32,7 @@ #define __client_entities_h #include "QF/qtypes.h" +#include "QF/simd/types.h" // entity_state_t is the information conveyed from the server // in an update message @@ -39,8 +40,8 @@ typedef struct entity_state_s { int number; // edict index unsigned flags; // nolerp, etc - vec3_t origin; - vec3_t velocity; + vec4f_t origin; + vec4f_t velocity; vec3_t angles; uint16_t modelindex; uint16_t frame; diff --git a/include/client/locs.h b/include/client/locs.h index 8786c6532..06817ef5a 100644 --- a/include/client/locs.h +++ b/include/client/locs.h @@ -29,23 +29,24 @@ #define __QF_locs_h #include "QF/qtypes.h" +#include "QF/simd/types.h" typedef struct { - vec3_t loc; - char *name; + vec4f_t loc; + char *name; } location_t; -location_t *locs_find(const vec3_t target) __attribute__((pure)); -void locs_add (const vec3_t location, const char *name); -void locs_del (const vec3_t loc); -void locs_edit (const vec3_t loc, const char *desc); +location_t *locs_find(vec4f_t target) __attribute__((pure)); +void locs_add (vec4f_t location, const char *name); +void locs_del (vec4f_t loc); +void locs_edit (vec4f_t loc, const char *desc); void locs_load(const char *filename); -void locs_mark (const vec3_t loc, const char *desc); -int locs_nearest (const vec3_t loc) __attribute__((pure)); +void locs_mark (vec4f_t loc, const char *desc); +int locs_nearest (vec4f_t loc) __attribute__((pure)); void locs_reset (void); void locs_save (const char *filename, qboolean gz); void map_to_loc (const char *mapname, char *filename); -void locs_draw (vec3_t simorg); +void locs_draw (vec4f_t simorg); #endif//__QF_locs_h diff --git a/include/clview.h b/include/clview.h index 7568ab23b..2b2cbffb2 100644 --- a/include/clview.h +++ b/include/clview.h @@ -30,6 +30,7 @@ #define __clview_h_ #include "QF/mathlib.h" +#include "QF/simd/types.h" #define INFO_CSHIFT_BONUS (1 << 0) #define INFO_CSHIFT_CONTENTS (1 << 1) @@ -39,7 +40,7 @@ void V_Init (void); void V_Init_Cvars (void); void V_RenderView (void); -float V_CalcRoll (const vec3_t angles, const vec3_t velocity); +float V_CalcRoll (const vec3_t angles, vec4f_t velocity); void V_UpdatePalette (void); void V_StartPitchDrift (void); void V_StopPitchDrift (void); diff --git a/libs/client/cl_effects.c b/libs/client/cl_effects.c index cc702587c..af40dc62c 100644 --- a/libs/client/cl_effects.c +++ b/libs/client/cl_effects.c @@ -47,7 +47,7 @@ #include "client/effects.h" void -CL_NewDlight (int key, vec3_t org, int effects, byte glow_size, +CL_NewDlight (int key, vec4f_t org, int effects, byte glow_size, byte glow_color, double time) { float radius; diff --git a/libs/client/locs.c b/libs/client/locs.c index dd6a17d9f..07deee426 100644 --- a/libs/client/locs.c +++ b/libs/client/locs.c @@ -48,6 +48,8 @@ #include "QF/sys.h" #include "QF/va.h" +#include "QF/simd/vec4f.h" + #include "QF/plugin/vid_render.h" //FIXME #include "compat.h" @@ -63,7 +65,7 @@ int locations_count = 0; int location_blocks = 0; int -locs_nearest (const vec3_t loc) +locs_nearest (vec4f_t loc) { float best_distance = 9999999, distance; int i, j = -1; @@ -71,7 +73,8 @@ locs_nearest (const vec3_t loc) for (i = 0; i < locations_count; i++) { cur = locations[i]; - distance = VectorDistance_fast (loc, cur->loc); + vec4f_t d = loc - cur->loc; + distance = dotf (d, d)[0]; if ((distance < best_distance)) { best_distance = distance; j = i; @@ -81,7 +84,7 @@ locs_nearest (const vec3_t loc) } location_t * -locs_find (const vec3_t target) +locs_find (vec4f_t target) { int i; @@ -110,7 +113,7 @@ locs_more (void) } void -locs_add (const vec3_t location, const char *name) +locs_add (vec4f_t location, const char *name) { int num; @@ -137,7 +140,7 @@ locs_load (const char *filename) const char *tmp; char *t1, *t2; const char *line; - vec3_t loc; + vec4f_t loc; QFile *file; tmp = va (0, "maps/%s", filename); @@ -216,7 +219,7 @@ locs_save (const char *filename, qboolean gz) } void -locs_mark (const vec3_t loc, const char *desc) +locs_mark (vec4f_t loc, const char *desc) { locs_add (loc, desc); Sys_Printf ("Marked current location: %s\n", desc); @@ -229,14 +232,14 @@ locs_mark (const vec3_t loc, const char *desc) call with NULL description to modify location vectors */ void -locs_edit (const vec3_t loc, const char *desc) +locs_edit (vec4f_t loc, const char *desc) { int i; if (locations_count) { i = locs_nearest (loc); if (!desc) { - VectorCopy (loc, locations[i]->loc); + locations[i]->loc = loc; Sys_Printf ("Moving location marker for %s\n", locations[i]->name); } else { @@ -250,7 +253,7 @@ locs_edit (const vec3_t loc, const char *desc) } void -locs_del (const vec3_t loc) +locs_del (vec4f_t loc) { int i; @@ -282,12 +285,12 @@ map_to_loc (const char *mapname, char *filename) } void -locs_draw (vec3_t simorg) +locs_draw (vec4f_t simorg) { //FIXME custom ent rendering code would be nice dlight_t *dl; location_t *nearloc; - vec3_t trueloc; + vec4f_t trueloc; int i; nearloc = locs_find (simorg); @@ -302,14 +305,14 @@ locs_draw (vec3_t simorg) dl->color[2] = 0; dl->color[3] = 0.7; } - VectorCopy (nearloc->loc, trueloc); + trueloc = nearloc->loc; r_funcs->particles->R_Particle_New (pt_smokecloud, part_tex_smoke, - trueloc, 2.0, + &trueloc[0], 2.0,//FIXME vec3_origin, r_data->realtime + 9.0, 254, 0.25 + qfrandom (0.125), 0.0); for (i = 0; i < 15; i++) r_funcs->particles->R_Particle_NewRandom (pt_fallfade, - part_tex_dot, trueloc, 12, + part_tex_dot, &trueloc[0], 12,//FIXME 0.7, 96, r_data->realtime + 5.0, 104 + (rand () & 7), 1.0, 0.0); } diff --git a/nq/include/client.h b/nq/include/client.h index 07c43ae87..4af07cd24 100644 --- a/nq/include/client.h +++ b/nq/include/client.h @@ -162,13 +162,13 @@ typedef struct { // server each frame. The server sets punchangle when the view is temporarily // offset, and an angle reset commands at the start of each level and after // teleporting. - int mindex; - vec3_t mviewangles[2]; // During demo playback viewangles is lerped + int frameIndex; + vec3_t frameViewAngles[2]; // During demo playback viewangles is lerped // between these vec3_t viewangles; - vec3_t mvelocity[2]; // Update by server, used for lean+bob + vec4f_t frameVelocity[2]; // Update by server, used for lean+bob // (0 is newest) - vec3_t velocity; // Lerped between mvelocity[0] and [1] + vec4f_t velocity; // Lerped between frameVelocity[0] and [1] vec3_t punchangle; // Temporary offset // pitch drifting vars diff --git a/nq/source/cl_demo.c b/nq/source/cl_demo.c index 772778b92..39cdf9d24 100644 --- a/nq/source/cl_demo.c +++ b/nq/source/cl_demo.c @@ -182,14 +182,14 @@ read_demopacket (void) if (net_message->message->cursize > MAX_DEMMSG) Host_Error ("Demo message > MAX_DEMMSG: %d/%d", net_message->message->cursize, MAX_DEMMSG); - VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); + VectorCopy (cl.frameViewAngles[0], cl.frameViewAngles[1]); for (i = 0; i < 3; i++) { r = Qread (cls.demofile, &f, 4); if (r != 4) { CL_StopPlayback (); return 0; } - cl.mviewangles[0][i] = LittleFloat (f); + cl.frameViewAngles[0][i] = LittleFloat (f); } r = Qread (cls.demofile, net_message->message->data, net_message->message->cursize); diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index 957cadb6a..e8aecb26c 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -156,19 +156,18 @@ CL_RelinkEntities (void) frac = CL_LerpPoint (); // interpolate player info - for (i = 0; i < 3; i++) - cl.velocity[i] = cl.mvelocity[1][i] + - frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); + cl.velocity = cl.frameVelocity[1] + + frac * (cl.frameVelocity[0] - cl.frameVelocity[1]); if (cls.demoplayback) { // interpolate the angles for (j = 0; j < 3; j++) { - d = cl.mviewangles[0][j] - cl.mviewangles[1][j]; + d = cl.frameViewAngles[0][j] - cl.frameViewAngles[1][j]; if (d > 180) d -= 360; else if (d < -180) d += 360; - cl.viewangles[j] = cl.mviewangles[1][j] + frac * d; + cl.viewangles[j] = cl.frameViewAngles[1][j] + frac * d; } } @@ -176,8 +175,8 @@ CL_RelinkEntities (void) // start on the entity after the world for (i = 1; i < cl.num_entities; i++) { - new = &nq_entstates.frame[0 + cl.mindex][i]; - old = &nq_entstates.frame[1 - cl.mindex][i]; + new = &nq_entstates.frame[0 + cl.frameIndex][i]; + old = &nq_entstates.frame[1 - cl.frameIndex][i]; ent = &cl_entities[i]; renderer = &ent->renderer; animation = &ent->animation; @@ -293,7 +292,8 @@ CL_RelinkEntities (void) CL_TransformEntity (ent, angles); } CL_EntityEffects (i, ent, new, cl.time); - CL_NewDlight (i, ent->origin, new->effects, new->glow_size, + vec4f_t org = { VectorExpand (ent->origin), 1}; //FIXME + CL_NewDlight (i, org, new->effects, new->glow_size, new->glow_color, cl.time); if (VectorDistance_fast (old->origin, ent->origin) > (256 * 256)) VectorCopy (ent->origin, old->origin); diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index 260920d13..ccf535e18 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -491,7 +491,7 @@ CL_ParseUpdate (int bits) num = MSG_ReadByte (net_message); baseline = CL_EntityNum (num); - state = &nq_entstates.frame[0 + cl.mindex][num]; + state = &nq_entstates.frame[0 + cl.frameIndex][num]; for (i = 0; i < 16; i++) if (bits & (1 << i)) @@ -620,7 +620,8 @@ CL_ParseBaseline (entity_state_t *baseline, int version) baseline->colormap = MSG_ReadByte (net_message); baseline->skinnum = MSG_ReadByte (net_message); - MSG_ReadCoordAngleV (net_message, baseline->origin, baseline->angles); + MSG_ReadCoordAngleV (net_message, &baseline->origin[0], baseline->angles); + baseline->origin[3] = 1;//FIXME if (bits & B_ALPHA) baseline->alpha = MSG_ReadByte (net_message); @@ -659,17 +660,17 @@ CL_ParseClientdata (void) else cl.idealpitch = 0; - VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); + cl.frameVelocity[1] = cl.frameVelocity[0]; for (i = 0; i < 3; i++) { if (bits & (SU_PUNCH1 << i)) cl.punchangle[i] = ((signed char) MSG_ReadByte (net_message)); else cl.punchangle[i] = 0; if (bits & (SU_VELOCITY1 << i)) - cl.mvelocity[0][i] = ((signed char) MSG_ReadByte (net_message)) + cl.frameVelocity[0][i] = ((signed char) MSG_ReadByte (net_message)) * 16; else - cl.mvelocity[0][i] = 0; + cl.frameVelocity[0][i] = 0; } //FIXME @@ -918,7 +919,7 @@ CL_ParseServerMessage (void) case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (net_message); - cl.mindex = !cl.mindex; + cl.frameIndex = !cl.frameIndex; break; case svc_print: diff --git a/nq/source/cl_view.c b/nq/source/cl_view.c index e6812a263..fa62de0fd 100644 --- a/nq/source/cl_view.c +++ b/nq/source/cl_view.c @@ -33,6 +33,8 @@ #include "QF/msg.h" #include "QF/screen.h" +#include "QF/simd/vec4f.h" + #include "QF/plugin/vid_render.h" #include "compat.h" @@ -87,7 +89,7 @@ cshift_t cshift_bonus = { {215, 186, 60}, 50}; #define sqr(x) ((x) * (x)) float -V_CalcRoll (const vec3_t angles, const vec3_t velocity) +V_CalcRoll (const vec3_t angles, vec4f_t velocity) { float side, sign, value; vec3_t forward, right, up; @@ -110,7 +112,7 @@ V_CalcRoll (const vec3_t angles, const vec3_t velocity) static float V_CalcBob (void) { - vec_t *velocity = cl.velocity; + vec4f_t velocity = cl.velocity; float cycle; static double bobtime; static float bob; @@ -132,8 +134,8 @@ V_CalcBob (void) // bob is proportional to velocity in the xy plane // (don't count Z, or jumping messes it up) - - bob = sqrt (sqr (velocity[0]) + sqr (velocity[1])) * cl_bob->value; + velocity[2] = 0; + bob = sqrt (dotf (velocity, velocity)[0]) * cl_bob->value; bob = bob * 0.3 + bob * 0.7 * sin (cycle * M_PI); if (bob > 4) bob = 4; @@ -582,7 +584,7 @@ V_CalcViewRoll (void) { float side; vec_t *angles = cl_entities[cl.viewentity].angles; - vec_t *velocity = cl.velocity; + vec4f_t velocity = cl.velocity; side = V_CalcRoll (angles, velocity); r_data->refdef->viewangles[ROLL] += side; diff --git a/nq/source/sv_main.c b/nq/source/sv_main.c index 38604e66c..d8a98b5b4 100644 --- a/nq/source/sv_main.c +++ b/nq/source/sv_main.c @@ -1037,7 +1037,8 @@ SV_CreateBaseline (void) MSG_WriteByte (&sv.signon, baseline->colormap); MSG_WriteByte (&sv.signon, baseline->skinnum); - MSG_WriteCoordAngleV (&sv.signon, baseline->origin, baseline->angles); + MSG_WriteCoordAngleV (&sv.signon, &baseline->origin[0],//FIXME + baseline->angles); if (bits & B_ALPHA) MSG_WriteByte (&sv.signon, baseline->alpha); diff --git a/qtv/source/client.c b/qtv/source/client.c index 6da363953..43e3f424f 100644 --- a/qtv/source/client.c +++ b/qtv/source/client.c @@ -682,7 +682,8 @@ write_player (int num, plent_state_t *pl, server_t *sv, sizebuf_t *msg) MSG_WriteByte (msg, num); MSG_WriteShort (msg, pflags); - MSG_WriteCoordV (msg, pl->es.origin); + MSG_WriteCoordV (msg, &pl->es.origin[0]);//FIXME + pl->es.origin[3] = 1; MSG_WriteByte (msg, pl->es.frame); diff --git a/qtv/source/sv_parse.c b/qtv/source/sv_parse.c index 268e9999d..fcf5c3616 100644 --- a/qtv/source/sv_parse.c +++ b/qtv/source/sv_parse.c @@ -515,7 +515,7 @@ parse_player_delta (qmsg_t *msg, plent_state_t *from, plent_state_t *to) int flags; flags = to->es.flags = MSG_ReadShort (msg); - MSG_ReadCoordV (msg, to->es.origin); + MSG_ReadCoordV (msg, &to->es.origin[0]); to->es.frame = (to->es.frame & 0xff00) | MSG_ReadByte (msg); if (flags & PF_MSEC) to->msec = MSG_ReadByte (msg); @@ -752,7 +752,8 @@ parse_baseline (qmsg_t *msg, entity_state_t *ent) ent->frame = MSG_ReadByte (msg); ent->colormap = MSG_ReadByte (msg); ent->skinnum = MSG_ReadByte (msg); - MSG_ReadCoordAngleV (msg, ent->origin, ent->angles); + MSG_ReadCoordAngleV (msg, &ent->origin[0], ent->angles); //FIXME + ent->origin[3] = 1; ent->colormod = 255; ent->alpha = 255; ent->scale = 16; diff --git a/qw/include/client.h b/qw/include/client.h index 3c64c128b..5389579c4 100644 --- a/qw/include/client.h +++ b/qw/include/client.h @@ -222,8 +222,8 @@ typedef struct { // the client simulates or interpolates movement to get these values double time; // this is the time value that the client // is rendering at. always <= realtime - vec3_t simorg; - vec3_t simvel; + vec4f_t simorg; + vec4f_t simvel; vec3_t simangles; vec3_t punchangle; // temporary view kick from weapon firing diff --git a/qw/source/cl_cam.c b/qw/source/cl_cam.c index 91e7a44eb..1b1959f13 100644 --- a/qw/source/cl_cam.c +++ b/qw/source/cl_cam.c @@ -221,7 +221,7 @@ Cam_TryFlyby (player_state_t * self, player_state_t * player, vec3_t vec, VectorMultAdd (player->pls.es.origin, 800, vec, v); // v is endpos // fake a player move - trace = Cam_DoTrace (player->pls.es.origin, v); + trace = Cam_DoTrace (&player->pls.es.origin[0], v);//FIXME if ( /* trace.inopen || */ trace.inwater) return 9999; VectorCopy (trace.endpos, vec); @@ -230,7 +230,7 @@ Cam_TryFlyby (player_state_t * self, player_state_t * player, vec3_t vec, if (len < 32 || len > 800) return 9999; if (checkvis) { - trace = Cam_DoTrace (self->pls.es.origin, vec); + trace = Cam_DoTrace (&self->pls.es.origin[0], vec);//FIXME if (trace.fraction != 1 || trace.inwater) return 9999; @@ -242,13 +242,13 @@ Cam_TryFlyby (player_state_t * self, player_state_t * player, vec3_t vec, // Is player visible? static qboolean -Cam_IsVisible (player_state_t * player, vec3_t vec) +Cam_IsVisible (player_state_t *player, vec3_t vec) { float d; trace_t trace; vec3_t v; - trace = Cam_DoTrace (player->pls.es.origin, vec); + trace = Cam_DoTrace (&player->pls.es.origin[0], vec);//FIXME if (trace.fraction != 1 || /* trace.inopen || */ trace.inwater) return false; // check distance, don't let the player get too far away or too close diff --git a/qw/source/cl_demo.c b/qw/source/cl_demo.c index 31594d51f..0694b5f25 100644 --- a/qw/source/cl_demo.c +++ b/qw/source/cl_demo.c @@ -797,7 +797,7 @@ demo_start_recording (int track) MSG_WriteByte (&buf, es->frame); MSG_WriteByte (&buf, es->colormap); MSG_WriteByte (&buf, es->skinnum); - MSG_WriteCoordAngleV (&buf, es->origin, es->angles); + MSG_WriteCoordAngleV (&buf, &es->origin[0], es->angles);//FIXME if (buf.cursize > MAX_MSGLEN / 2) { CL_WriteRecordDemoMessage (&buf, seq++); diff --git a/qw/source/cl_entparse.c b/qw/source/cl_entparse.c index b1b5d3386..a7716b729 100644 --- a/qw/source/cl_entparse.c +++ b/qw/source/cl_entparse.c @@ -427,7 +427,7 @@ CL_ParsePlayerinfo (void) flags = state->pls.es.flags = MSG_ReadShort (net_message); state->messagenum = cl.parsecount; - MSG_ReadCoordV (net_message, state->pls.es.origin); + MSG_ReadCoordV (net_message, &state->pls.es.origin[0]);//FIXME state->pls.es.frame = MSG_ReadByte (net_message); diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 1e8ab80d9..606fc1ce8 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -356,7 +356,8 @@ CL_LinkPlayers (void) player_state_t exact; player_state_t *state; qboolean clientplayer; - vec3_t org, ang = {0, 0, 0}; + vec3_t ang = {0, 0, 0}; + vec4f_t org; playertime = realtime - cls.latency + 0.02; if (playertime > realtime) @@ -377,11 +378,11 @@ CL_LinkPlayers (void) // spawn light flashes, even ones coming from invisible objects if (j == cl.playernum) { - VectorCopy (cl.simorg, org); + org = cl.simorg; r_data->player_entity = &cl_player_ents[j]; clientplayer = true; } else { - VectorCopy (state->pls.es.origin, org); + org = state->pls.es.origin; clientplayer = false; } if (info->chat && info->chat->value[0] != '0') { diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 095f636bc..bfd1fa5a2 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -945,7 +945,8 @@ CL_ParseBaseline (entity_state_t *es) es->colormap = MSG_ReadByte (net_message); es->skinnum = MSG_ReadByte (net_message); - MSG_ReadCoordAngleV (net_message, es->origin, es->angles); + MSG_ReadCoordAngleV (net_message, &es->origin[0], es->angles);//FIXME + es->origin[3] = 1; // LordHavoc: set up baseline to for new effects (alpha, colormod, etc) es->colormod = 255; @@ -1541,7 +1542,8 @@ CL_ParseServerMessage (void) cl.completed_time = realtime; r_data->vid->recalc_refdef = true; // go to full screen Sys_MaskPrintf (SYS_DEV, "intermission simorg: "); - MSG_ReadCoordV (net_message, cl.simorg); + MSG_ReadCoordV (net_message, &cl.simorg[0]);//FIXME + cl.simorg[3] = 1; for (i = 0; i < 3; i++) Sys_MaskPrintf (SYS_DEV, "%f ", cl.simorg[i]); Sys_MaskPrintf (SYS_DEV, "\nintermission simangles: "); diff --git a/qw/source/cl_pred.c b/qw/source/cl_pred.c index 1fe115949..f48533673 100644 --- a/qw/source/cl_pred.c +++ b/qw/source/cl_pred.c @@ -184,14 +184,9 @@ CL_PredictMove (void) return; } - for (i = 0; i < 3; i++) { - cl.simorg[i] = from->playerstate[cl.playernum].pls.es.origin[i] + - f * (to->playerstate[cl.playernum].pls.es.origin[i] - - from->playerstate[cl.playernum].pls.es.origin[i]); - cl.simvel[i] = from->playerstate[cl.playernum].pls.es.velocity[i] + - f * (to->playerstate[cl.playernum].pls.es.velocity[i] - - from->playerstate[cl.playernum].pls.es.velocity[i]); - } + cl.simorg = from->playerstate[cl.playernum].pls.es.origin + + f * (to->playerstate[cl.playernum].pls.es.origin - + from->playerstate[cl.playernum].pls.es.origin); } void diff --git a/qw/source/cl_view.c b/qw/source/cl_view.c index 3b1ca0688..9497e3ef9 100644 --- a/qw/source/cl_view.c +++ b/qw/source/cl_view.c @@ -33,6 +33,8 @@ #include "QF/msg.h" #include "QF/screen.h" +#include "QF/simd/vec4f.h" + #include "compat.h" #include "clview.h" @@ -93,7 +95,7 @@ cshift_t cshift_bonus = { {215, 186, 60}, 50}; #define sqr(x) ((x) * (x)) float -V_CalcRoll (const vec3_t angles, const vec3_t velocity) +V_CalcRoll (const vec3_t angles, const vec4f_t velocity) { float side, sign, value; vec3_t forward, right, up; @@ -116,7 +118,7 @@ V_CalcRoll (const vec3_t angles, const vec3_t velocity) static float V_CalcBob (void) { - vec_t *velocity = cl.simvel; + vec4f_t velocity = cl.simvel; float cycle; static double bobtime; static float bob; @@ -138,8 +140,8 @@ V_CalcBob (void) // bob is proportional to velocity in the xy plane // (don't count Z, or jumping messes it up) - - bob = sqrt (sqr (velocity[0]) + sqr (velocity[1])) * cl_bob->value; + velocity[2] = 0; + bob = sqrt (dotf (velocity, velocity)[0]) * cl_bob->value; bob = bob * 0.3 + bob * 0.7 * sin (cycle * M_PI); if (bob > 4) bob = 4; @@ -240,7 +242,7 @@ V_ParseDamage (void) { float count, side; int armor, blood; - vec_t *origin = cl.simorg; + vec4f_t origin = cl.simorg; vec_t *angles = cl.simangles; vec3_t from, forward, right, up; @@ -535,7 +537,7 @@ CalcGunAngle (void) static void V_BoundOffsets (void) { - vec_t *origin = cl.simorg; + vec4f_t origin = cl.simorg; // absolutely bound refresh reletive to entity clipping hull // so the view can never be inside a solid wall @@ -587,7 +589,7 @@ V_CalcViewRoll (void) { float side; vec_t *angles = cl.simangles; - vec_t *velocity = cl.simvel; + vec4f_t velocity = cl.simvel; side = V_CalcRoll (angles, velocity); r_data->refdef->viewangles[ROLL] += side; @@ -609,7 +611,7 @@ V_CalcIntermissionRefdef (void) { entity_t *view; float old; - vec_t *origin = cl.simorg; + vec4f_t origin = cl.simorg; vec_t *angles = cl.simangles; // view is the weapon model (visible only from inside body) @@ -635,7 +637,7 @@ V_CalcRefdef (void) static float oldz = 0; int i; vec3_t forward, right, up; - vec_t *origin = cl.simorg; + vec4f_t origin = cl.simorg; vec_t *viewangles = cl.simangles; V_DriftPitch (); diff --git a/qw/source/sv_ents.c b/qw/source/sv_ents.c index 50c7a3d97..ccbf9278b 100644 --- a/qw/source/sv_ents.c +++ b/qw/source/sv_ents.c @@ -509,7 +509,7 @@ write_player (delta_t *delta, plent_state_t *from, plent_state_t *to, MSG_WriteByte (msg, to->es.number); MSG_WriteShort (msg, flags); - MSG_WriteCoordV (msg, to->es.origin); + MSG_WriteCoordV (msg, &to->es.origin[0]);//FIXME MSG_WriteByte (msg, to->es.frame); diff --git a/qw/source/sv_init.c b/qw/source/sv_init.c index e0a370f92..6fbd6cbc7 100644 --- a/qw/source/sv_init.c +++ b/qw/source/sv_init.c @@ -167,8 +167,8 @@ SV_CreateBaseline (void) MSG_WriteByte (&sv.signon, SVdata (svent)->state.colormap); MSG_WriteByte (&sv.signon, SVdata (svent)->state.skinnum); - MSG_WriteCoordAngleV (&sv.signon, SVdata (svent)->state.origin, - SVdata (svent)->state.angles); + MSG_WriteCoordAngleV (&sv.signon, &SVdata (svent)->state.origin[0], + SVdata (svent)->state.angles);//FIXME } } diff --git a/qw/source/teamplay.c b/qw/source/teamplay.c index 75e6aefe3..159da95f0 100644 --- a/qw/source/teamplay.c +++ b/qw/source/teamplay.c @@ -58,7 +58,7 @@ #include "qw/include/client.h" static qboolean died = false, recorded_location = false; -static vec3_t death_location, last_recorded_location; +static vec4f_t death_location, last_recorded_location; cvar_t *cl_deadbodyfilter; cvar_t *cl_gibfilter; @@ -165,7 +165,7 @@ Team_ParseSay (dstring_t *buf, const char *s) location = locs_find (death_location); if (location) { recorded_location = true; - VectorCopy (death_location, last_recorded_location); + last_recorded_location = death_location; t1 = location->name; break; } @@ -187,7 +187,7 @@ Team_ParseSay (dstring_t *buf, const char *s) location = locs_find (cl.simorg); if (location) { recorded_location = true; - VectorCopy (cl.simorg, last_recorded_location); + last_recorded_location = cl.simorg; t1 = location->name; } else snprintf (t2, sizeof (t2), "Unknown!"); @@ -279,7 +279,7 @@ void Team_Dead (void) { died = true; - VectorCopy (cl.simorg, death_location); + death_location = cl.simorg; } void From 2015474468ac316b51e2276cc37a055c62cb4fcc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 12 Mar 2021 11:48:53 +0900 Subject: [PATCH 401/435] Move and clean up clview.h Redundant or dead prototypes deleted, and the client/view.h seems a good place for the file. --- include/Makemodule.am | 2 +- include/{clview.h => client/view.h} | 13 ++++--------- libs/video/renderer/sw32/draw.c | 3 ++- nq/source/cl_main.c | 2 +- nq/source/cl_view.c | 5 +++-- qw/source/cl_entparse.c | 2 +- qw/source/cl_ents.c | 2 +- qw/source/cl_input.c | 3 ++- qw/source/cl_main.c | 2 +- qw/source/cl_parse.c | 2 +- qw/source/cl_screen.c | 3 ++- qw/source/cl_view.c | 7 ++++--- 12 files changed, 23 insertions(+), 23 deletions(-) rename include/{clview.h => client/view.h} (85%) diff --git a/include/Makemodule.am b/include/Makemodule.am index 645a820bf..0755ed1b5 100644 --- a/include/Makemodule.am +++ b/include/Makemodule.am @@ -11,7 +11,6 @@ EXTRA_DIST += \ include/block16.h \ include/block8.h \ include/buildnum.h \ - include/clview.h \ include/compat.h \ include/context_sdl.h \ include/context_x11.h \ @@ -80,6 +79,7 @@ EXTRA_DIST += \ include/client/entities.h \ include/client/temp_entities.h \ include/client/locs.h \ + include/client/view.h \ include/qw/bothdefs.h \ include/qw/msg_backbuf.h \ include/qw/msg_ucmd.h \ diff --git a/include/clview.h b/include/client/view.h similarity index 85% rename from include/clview.h rename to include/client/view.h index 2b2cbffb2..756eb1d21 100644 --- a/include/clview.h +++ b/include/client/view.h @@ -1,5 +1,5 @@ /* - clview.h + view.h (description) @@ -26,8 +26,8 @@ */ // view.h -#ifndef __clview_h_ -#define __clview_h_ +#ifndef __client_view_h_ +#define __client_view_h_ #include "QF/mathlib.h" #include "QF/simd/types.h" @@ -41,14 +41,9 @@ void V_Init (void); void V_Init_Cvars (void); void V_RenderView (void); float V_CalcRoll (const vec3_t angles, vec4f_t velocity); -void V_UpdatePalette (void); void V_StartPitchDrift (void); void V_StopPitchDrift (void); -void V_RenderView (void); -void V_UpdatePalette (void); -void V_Register (void); void V_SetContentsColor (int contents); -void V_CalcBlend (void); -#endif // __clview_h_ +#endif // __client_view_h_ diff --git a/libs/video/renderer/sw32/draw.c b/libs/video/renderer/sw32/draw.c index 13454c437..fdb24e2c5 100644 --- a/libs/video/renderer/sw32/draw.c +++ b/libs/video/renderer/sw32/draw.c @@ -1362,6 +1362,7 @@ sw32_Draw_BlendScreen (quat_t color) } break; default: - Sys_Error("V_UpdatePalette: unsupported r_pixbytes %i", sw32_r_pixbytes); + Sys_Error("sw32_Draw_BlendScreen: unsupported r_pixbytes %i", + sw32_r_pixbytes); } } diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index 25ff7bd39..e2c222713 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -49,10 +49,10 @@ #include "QF/plugin/vid_render.h" #include "compat.h" -#include "clview.h" #include "sbar.h" #include "client/temp_entities.h" +#include "client/view.h" #include "nq/include/chase.h" #include "nq/include/cl_skin.h" diff --git a/nq/source/cl_view.c b/nq/source/cl_view.c index fa62de0fd..1ccf06d98 100644 --- a/nq/source/cl_view.c +++ b/nq/source/cl_view.c @@ -38,7 +38,8 @@ #include "QF/plugin/vid_render.h" #include "compat.h" -#include "clview.h" + +#include "client/view.h" #include "nq/include/chase.h" #include "nq/include/client.h" @@ -393,7 +394,7 @@ V_CalcPowerupCshift (void) LordHavoc made this a real, true alpha blend. Cleaned it up a bit, but otherwise this is his code. --KB */ -void +static void V_CalcBlend (void) { float a2, a3; diff --git a/qw/source/cl_entparse.c b/qw/source/cl_entparse.c index a7716b729..60c8cf2c4 100644 --- a/qw/source/cl_entparse.c +++ b/qw/source/cl_entparse.c @@ -42,9 +42,9 @@ #include "QF/sys.h" #include "compat.h" -#include "clview.h" #include "client/temp_entities.h" +#include "client/view.h" #include "qw/msg_ucmd.h" #include "qw/pmove.h" diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 606fc1ce8..b70b143cc 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -43,12 +43,12 @@ #include "QF/sys.h" #include "compat.h" -#include "clview.h" #include "d_iface.h" #include "client/effects.h" #include "client/locs.h" #include "client/temp_entities.h" +#include "client/view.h" #include "qw/bothdefs.h" #include "qw/msg_ucmd.h" diff --git a/qw/source/cl_input.c b/qw/source/cl_input.c index 55ef38f5d..5a2fe2b6e 100644 --- a/qw/source/cl_input.c +++ b/qw/source/cl_input.c @@ -46,7 +46,8 @@ #include "QF/va.h" #include "compat.h" -#include "clview.h" + +#include "client/view.h" #include "qw/msg_ucmd.h" diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index ea143c9ae..be73db0e7 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -92,11 +92,11 @@ #include "QF/plugin/console.h" #include "buildnum.h" -#include "clview.h" #include "compat.h" #include "sbar.h" #include "client/temp_entities.h" +#include "client/view.h" #include "qw/bothdefs.h" #include "qw/pmove.h" diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index bfd1fa5a2..b75355fa1 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -62,11 +62,11 @@ #include "QF/va.h" #include "compat.h" -#include "clview.h" #include "sbar.h" #include "client/effects.h" #include "client/temp_entities.h" +#include "client/view.h" #include "qw/bothdefs.h" #include "qw/pmove.h" diff --git a/qw/source/cl_screen.c b/qw/source/cl_screen.c index 7827c30db..22c8b5b96 100644 --- a/qw/source/cl_screen.c +++ b/qw/source/cl_screen.c @@ -44,9 +44,10 @@ #include "QF/pcx.h" #include "QF/screen.h" -#include "clview.h" #include "sbar.h" +#include "client/view.h" + #include "qw/include/client.h" static qpic_t *scr_net; diff --git a/qw/source/cl_view.c b/qw/source/cl_view.c index 9497e3ef9..f20d5747a 100644 --- a/qw/source/cl_view.c +++ b/qw/source/cl_view.c @@ -36,7 +36,8 @@ #include "QF/simd/vec4f.h" #include "compat.h" -#include "clview.h" + +#include "client/view.h" #include "qw/bothdefs.h" @@ -95,7 +96,7 @@ cshift_t cshift_bonus = { {215, 186, 60}, 50}; #define sqr(x) ((x) * (x)) float -V_CalcRoll (const vec3_t angles, const vec4f_t velocity) +V_CalcRoll (const vec3_t angles, vec4f_t velocity) { float side, sign, value; vec3_t forward, right, up; @@ -399,7 +400,7 @@ V_CalcPowerupCshift (void) LordHavoc made this a real, true alpha blend. Cleaned it up a bit, but otherwise this is his code. --KB */ -void +static void V_CalcBlend (void) { float a2, a3; From 5158cc5527556219fcff0fcf0b63bbc3a9037294 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 19 Mar 2021 11:04:47 +0900 Subject: [PATCH 402/435] [util] Add normal and magnitude float vector functions --- include/QF/simd/vec4f.h | 37 ++++++++++++++++++++++++++ libs/video/renderer/glsl/glsl_sprite.c | 4 +-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/include/QF/simd/vec4f.h b/include/QF/simd/vec4f.h index 85eb252eb..8fe207b74 100644 --- a/include/QF/simd/vec4f.h +++ b/include/QF/simd/vec4f.h @@ -93,6 +93,9 @@ GNU89INLINE inline vec4f_t qrotf (vec4f_t a, vec4f_t b) __attribute__((const)); GNU89INLINE inline vec4f_t qconjf (vec4f_t q) __attribute__((const)); GNU89INLINE inline vec4f_t loadvec3f (const float v3[3]) __attribute__((pure, access(read_only, 1))); GNU89INLINE inline void storevec3f (float v3[3], vec4f_t v4) __attribute__((access (write_only, 1))); +GNU89INLINE inline vec4f_t normalf (vec4f_t v) __attribute__((pure)); +GNU89INLINE inline vec4f_t magnitudef (vec4f_t v) __attribute__((pure)); +GNU89INLINE inline vec4f_t magnitude3f (vec4f_t v) __attribute__((pure)); #ifndef IMPLEMENT_VEC4F_Funcs GNU89INLINE inline @@ -288,4 +291,38 @@ storevec3f (float v3[3], vec4f_t v4) v3[2] = v4[2]; } +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +normalf (vec4f_t v) +{ + return v / vsqrtf (dotf (v, v)); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +magnitudef (vec4f_t v) +{ + return vsqrtf (dotf (v, v)); +} + +#ifndef IMPLEMENT_VEC4F_Funcs +GNU89INLINE inline +#else +VISIBLE +#endif +vec4f_t +magnitude3f (vec4f_t v) +{ + v[3] = 0; + return vsqrtf (dotf (v, v)); +} + #endif//__QF_simd_vec4f_h diff --git a/libs/video/renderer/glsl/glsl_sprite.c b/libs/video/renderer/glsl/glsl_sprite.c index 63704ebfa..4d35bc8d6 100644 --- a/libs/video/renderer/glsl/glsl_sprite.c +++ b/libs/video/renderer/glsl/glsl_sprite.c @@ -243,7 +243,7 @@ R_DrawSprite (void) VectorSet (0, 0, 1, svup); // CrossProduct (svup, -r_origin, svright) VectorSet (tvec[1], -tvec[0], 0, svright); - svright /= vsqrtf (dotf (svright, svright)); + svright = normalf (svright); // CrossProduct (svright, svup, svpn); VectorSet (-svright[1], svright[0], 0, svpn); break; @@ -268,7 +268,7 @@ R_DrawSprite (void) VectorSet (0, 0, 1, svup); // CrossProduct (svup, -r_origin, svright) VectorSet (vpn[1], -vpn[0], 0, svright); - svright /= vsqrtf (dotf (svright, svright)); + svright = normalf (svright); // CrossProduct (svright, svup, svpn); VectorSet (-svright[1], svright[0], 0, svpn); break; From 5bf21931c7b40d2becb32377d7183f10753fea47 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 19 Mar 2021 20:18:45 +0900 Subject: [PATCH 403/435] [renderer] Remove more old fields from entity_t The only transform related field remaining is old_origin. This also brings the renderer closer to using simd (lots of stuff to fix still, though). --- include/QF/render.h | 11 +- include/client/entities.h | 3 +- include/client/view.h | 15 + libs/client/cl_effects.c | 3 +- libs/client/cl_entities.c | 21 +- libs/client/cl_temp_entities.c | 84 ++--- libs/client/locs.c | 2 +- libs/video/renderer/gl/gl_dyn_part.c | 79 +++-- libs/video/renderer/gl/gl_lightmap.c | 16 +- libs/video/renderer/gl/gl_mod_alias.c | 34 +- libs/video/renderer/gl/gl_mod_iqm.c | 1 - libs/video/renderer/gl/gl_mod_sprite.c | 8 - libs/video/renderer/gl/gl_rmain.c | 59 ++-- libs/video/renderer/gl/gl_rmisc.c | 5 +- libs/video/renderer/gl/gl_rsurf.c | 13 +- libs/video/renderer/gl/gl_sky.c | 20 +- libs/video/renderer/gl/gl_sky_clip.c | 14 +- libs/video/renderer/glsl/glsl_alias.c | 7 +- libs/video/renderer/glsl/glsl_bsp.c | 16 +- libs/video/renderer/glsl/glsl_iqm.c | 12 +- libs/video/renderer/glsl/glsl_lightmap.c | 10 +- libs/video/renderer/glsl/glsl_main.c | 17 +- libs/video/renderer/glsl/glsl_particles.c | 81 +++-- libs/video/renderer/glsl/glsl_sprite.c | 24 +- libs/video/renderer/r_efrag.c | 6 +- libs/video/renderer/sw/d_edge.c | 7 +- libs/video/renderer/sw/sw_rmain.c | 41 +-- libs/video/renderer/sw/sw_rmisc.c | 10 +- libs/video/renderer/sw/sw_rpart.c | 42 ++- libs/video/renderer/sw/sw_rsprite.c | 9 +- libs/video/renderer/sw/sw_rsurf.c | 10 +- libs/video/renderer/sw32/d_edge.c | 7 +- libs/video/renderer/sw32/sw32_rmain.c | 30 +- libs/video/renderer/sw32/sw32_rmisc.c | 10 +- libs/video/renderer/sw32/sw32_rpart.c | 42 ++- libs/video/renderer/sw32/sw32_rsprite.c | 9 +- libs/video/renderer/sw32/sw32_rsurf.c | 10 +- .../renderer/vulkan/shader/lighting.frag | 2 +- libs/video/renderer/vulkan/vulkan_bsp.c | 17 +- libs/video/renderer/vulkan/vulkan_lightmap.c | 9 +- libs/video/renderer/vulkan/vulkan_main.c | 38 ++- nq/include/client.h | 5 +- nq/source/cl_chase.c | 123 ++++---- nq/source/cl_demo.c | 2 +- nq/source/cl_ents.c | 61 ++-- nq/source/cl_input.c | 45 +-- nq/source/cl_main.c | 14 +- nq/source/cl_parse.c | 20 +- nq/source/cl_screen.c | 4 +- nq/source/cl_view.c | 265 +++++++--------- qw/include/client.h | 12 +- qw/source/cl_chase.c | 123 ++++---- qw/source/cl_demo.c | 22 +- qw/source/cl_entparse.c | 5 +- qw/source/cl_ents.c | 47 ++- qw/source/cl_input.c | 2 + qw/source/cl_main.c | 2 + qw/source/cl_parse.c | 37 ++- qw/source/cl_pred.c | 26 +- qw/source/cl_screen.c | 4 +- qw/source/cl_view.c | 293 ++++++++---------- qw/source/teamplay.c | 16 +- 62 files changed, 1070 insertions(+), 912 deletions(-) diff --git a/include/QF/render.h b/include/QF/render.h index 99fb105a9..adc5e141e 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -32,6 +32,7 @@ #include "QF/model.h" #include "QF/qdefs.h" // FIXME #include "QF/vid.h" +#include "QF/simd/types.h" typedef enum { pt_static, @@ -131,10 +132,7 @@ typedef struct entity_s { renderer_t renderer; int active; //XXX FIXME XXX should not be here - float scale; - vec3_t origin; - vec3_t old_origin; - vec3_t angles; + vec4f_t old_origin; } entity_t; // !!! if this is changed, it must be changed in asm_draw.h too !!! @@ -159,8 +157,9 @@ typedef struct { float xOrigin; // should probably always be 0.5 float yOrigin; // between be around 0.3 to 0.5 - vec3_t vieworg; - vec3_t viewangles; + //FIXME was vec3_t, need to deal with asm (maybe? is it worth it?) + vec4f_t viewposition; + vec4f_t viewrotation; float fov_x, fov_y; diff --git a/include/client/entities.h b/include/client/entities.h index fda534295..5981d1c9d 100644 --- a/include/client/entities.h +++ b/include/client/entities.h @@ -71,6 +71,7 @@ extern entstates_t qw_entstates; extern vec3_t ent_colormod[256]; struct entity_s; -void CL_TransformEntity (struct entity_s *ent, const vec3_t angles); +void CL_TransformEntity (struct entity_s *ent, float scale, + const vec3_t angles, vec4f_t position); #endif//__client_entities_h diff --git a/include/client/view.h b/include/client/view.h index 756eb1d21..40ad78df3 100644 --- a/include/client/view.h +++ b/include/client/view.h @@ -37,6 +37,21 @@ #define INFO_CSHIFT_DAMAGE (1 << 2) #define INFO_CSHIFT_POWERUP (1 << 3) +typedef struct viewstate_s { + vec4f_t movecmd; + vec4f_t velocity; + vec4f_t origin; + vec3_t angles; + int weaponframe; + int onground; + uint32_t flags; + float frametime; + vec4f_t punchangle; +} viewstate_t; + +#define VF_DEAD 1 +#define VF_GIB 2 + void V_Init (void); void V_Init_Cvars (void); void V_RenderView (void); diff --git a/libs/client/cl_effects.c b/libs/client/cl_effects.c index af40dc62c..707699141 100644 --- a/libs/client/cl_effects.c +++ b/libs/client/cl_effects.c @@ -123,7 +123,8 @@ CL_ModelEffects (entity_t *ent, int num, int glow_color, double time) if (model->flags & EF_ROCKET) { dl = r_funcs->R_AllocDlight (num); if (dl) { - VectorCopy (ent->origin, dl->origin); + VectorCopy (Transform_GetWorldPosition (ent->transform), + dl->origin); dl->radius = 200.0; dl->die = time + 0.1; //FIXME VectorCopy (r_firecolor->vec, dl->color); diff --git a/libs/client/cl_entities.c b/libs/client/cl_entities.c index 837cfbe60..599576863 100644 --- a/libs/client/cl_entities.c +++ b/libs/client/cl_entities.c @@ -346,21 +346,14 @@ vec3_t ent_colormod[256] = { }; void -CL_TransformEntity (entity_t *ent, const vec3_t angles) +CL_TransformEntity (entity_t *ent, float scale, const vec3_t angles, + vec4f_t position) { - union { - quat_t q; - vec4f_t v; - } rotation; - vec4f_t position; - vec4f_t scale; + vec4f_t rotation; + vec4f_t scalevec = { scale, scale, scale, 1}; - VectorCopy (ent->origin, position); - position[3] = 1; - VectorSet (ent->scale, ent->scale, ent->scale, scale); - scale[3] = 1; if (VectorIsZero (angles)) { - QuatSet (0, 0, 0, 1, rotation.q); + rotation = (vec4f_t) { 0, 0, 0, 1 }; } else { vec3_t ang; VectorCopy (angles, ang); @@ -370,7 +363,7 @@ CL_TransformEntity (entity_t *ent, const vec3_t angles) // to everything else? ang[PITCH] = -ang[PITCH]; } - AngleQuat (ang, rotation.q); + AngleQuat (ang, &rotation[0]);//FIXME } - Transform_SetLocalTransform (ent->transform, scale, rotation.v, position); + Transform_SetLocalTransform (ent->transform, scalevec, rotation, position); } diff --git a/libs/client/cl_temp_entities.c b/libs/client/cl_temp_entities.c index 0b6672f0f..03fab9b73 100644 --- a/libs/client/cl_temp_entities.c +++ b/libs/client/cl_temp_entities.c @@ -61,7 +61,8 @@ typedef struct { int entity; struct model_s *model; float endtime; - vec3_t start, end; + vec4f_t start, end; + vec4f_t rotation; tent_t *tents; int seed; } beam_t; @@ -100,6 +101,8 @@ static model_t *cl_mod_bolt3; static model_t *cl_spr_explod; static model_t *cl_spike; +static vec4f_t beam_rolls[360]; + static void CL_TEnts_Precache (int phase) { @@ -132,6 +135,10 @@ CL_TEnts_Init (void) { QFS_GamedirCallback (CL_TEnts_Precache); CL_TEnts_Precache (1); + for (int i = 0; i < 360; i++) { + float ang = i * M_PI / 360; + beam_rolls[i] = (vec4f_t) { sin (ang), 0, 0, cos (ang) }; + } } void @@ -145,7 +152,6 @@ CL_Init_Entity (entity_t *ent) ent->transform = Transform_New (0); ent->renderer.skin = 0; QuatSet (1.0, 1.0, 1.0, 1.0, ent->renderer.colormod); - ent->scale = 1.0; ent->animation.pose1 = ent->animation.pose2 = -1; } @@ -255,57 +261,52 @@ static inline void beam_setup (beam_t *b, qboolean transform, double time, TEntContext_t *ctx) { tent_t *tent; - float forward, pitch, yaw, d; + float d; int ent_count; - vec3_t dist, org, ang; + vec4f_t dist, org; + vec4f_t rotation; + vec4f_t scale = { 1, 1, 1, 1 }; unsigned seed; // calculate pitch and yaw - VectorSubtract (b->end, b->start, dist); + dist = b->end - b->start; - if (dist[1] == 0 && dist[0] == 0) { - yaw = 0; - if (dist[2] > 0) - pitch = 90; - else - pitch = 270; + // FIXME interpolation may be off when passing through the -x axis + if (dist[0] < 0 && dist[1] == 0 && dist[2] == 0) { + // anti-parallel with the +x axis, so assome 180 degree rotation around + // the z-axis + rotation = (vec4f_t) { 0, 0, 1, 0 }; } else { - yaw = (int) (atan2 (dist[1], dist[0]) * 180 / M_PI); - if (yaw < 0) - yaw += 360; - - forward = sqrt (dist[0] * dist[0] + dist[1] * dist[1]); - pitch = (int) (atan2 (dist[2], forward) * 180 / M_PI); - if (pitch < 0) - pitch += 360; + rotation = qrotf ((vec4f_t) { 1, 0, 0, 0 }, dist); } + b->rotation = rotation; // add new entities for the lightning - VectorCopy (b->start, org); - d = VectorNormalize (dist); - VectorScale (dist, 30, dist); + org = b->start; + d = magnitudef (dist)[0]; + dist = normalf (dist) * 30; ent_count = ceil (d / 30); d = 0; seed = b->seed + ((int) (time * BEAM_SEED_INTERVAL) % BEAM_SEED_INTERVAL); - ang[ROLL] = 0; while (ent_count--) { tent = new_temp_entity (); tent->next = b->tents; b->tents = tent; - VectorMultAdd (org, d, dist, tent->ent.origin); + vec4f_t position = org + d * dist; d += 1.0; tent->ent.renderer.model = b->model; - ang[PITCH] = pitch; - ang[YAW] = yaw; if (transform) { seed = seed * BEAM_SEED_PRIME; - ang[ROLL] = seed % 360; - CL_TransformEntity (&tent->ent, ang); + Transform_SetLocalTransform (tent->ent.transform, scale, + qmulf (rotation, + beam_rolls[seed % 360]), + position); + } else { + Transform_SetLocalPosition (tent->ent.transform, position); } - VectorCopy (ang, tent->ent.angles); r_funcs->R_AddEfrags (&ctx->worldModel->brush, &tent->ent); } } @@ -404,14 +405,14 @@ parse_tent (qmsg_t *net_message, double time, TEntContext_t *ctx, ex = &to->to.ex; ex->tent = new_temp_entity (); - VectorCopy (position, ex->tent->ent.origin); ex->start = time; //FIXME need better model management if (!cl_spr_explod->cache.data) { cl_spr_explod = Mod_ForName ("progs/s_explod.spr", true); } ex->tent->ent.renderer.model = cl_spr_explod; - CL_TransformEntity (&ex->tent->ent, ex->tent->ent.angles); + Transform_SetLocalPosition (ex->tent->ent.transform,//FIXME + (vec4f_t) {VectorExpand (position), 1}); break; case TE_Explosion2: MSG_ReadCoordV (net_message, position); @@ -635,8 +636,9 @@ CL_UpdateBeams (double time, TEntContext_t *ctx) // add new entities for the lightning for (t = b->tents; t; t = t->next) { seed = seed * BEAM_SEED_PRIME; - t->ent.angles[ROLL] = seed % 360; - CL_TransformEntity (&t->ent, t->ent.angles); + Transform_SetLocalRotation (t->ent.transform, + qmulf (b->rotation, + beam_rolls[seed % 360])); } } } @@ -727,6 +729,8 @@ CL_ParseProjectiles (qmsg_t *net_message, qboolean nail2, TEntContext_t *ctx) byte bits[6]; int i, c, j, num; entity_t *pr; + vec4f_t position = { 0, 0, 0, 1 }; + vec3_t angles; c = MSG_ReadByte (net_message); @@ -747,13 +751,13 @@ CL_ParseProjectiles (qmsg_t *net_message, qboolean nail2, TEntContext_t *ctx) pr = &tent->ent; pr->renderer.model = cl_spike; pr->renderer.skin = 0; - pr->origin[0] = ((bits[0] + ((bits[1] & 15) << 8)) << 1) - 4096; - pr->origin[1] = (((bits[1] >> 4) + (bits[2] << 4)) << 1) - 4096; - pr->origin[2] = ((bits[3] + ((bits[4] & 15) << 8)) << 1) - 4096; - pr->angles[0] = (bits[4] >> 4) * (360.0 / 16.0); - pr->angles[1] = bits[5] * (360.0 / 256.0); - pr->angles[2] = 0; - CL_TransformEntity (&tent->ent, tent->ent.angles); + position[0] = ((bits[0] + ((bits[1] & 15) << 8)) << 1) - 4096; + position[1] = (((bits[1] >> 4) + (bits[2] << 4)) << 1) - 4096; + position[2] = ((bits[3] + ((bits[4] & 15) << 8)) << 1) - 4096; + angles[0] = (bits[4] >> 4) * (360.0 / 16.0); + angles[1] = bits[5] * (360.0 / 256.0); + angles[2] = 0; + CL_TransformEntity (&tent->ent, 1, angles, position); r_funcs->R_AddEfrags (&ctx->worldModel->brush, &tent->ent); } diff --git a/libs/client/locs.c b/libs/client/locs.c index 07deee426..2ab477921 100644 --- a/libs/client/locs.c +++ b/libs/client/locs.c @@ -140,7 +140,7 @@ locs_load (const char *filename) const char *tmp; char *t1, *t2; const char *line; - vec4f_t loc; + vec4f_t loc = { 0, 0, 0, 1 }; QFile *file; tmp = va (0, "maps/%s", filename); diff --git a/libs/video/renderer/gl/gl_dyn_part.c b/libs/video/renderer/gl/gl_dyn_part.c index 5aa093813..13afc1fe9 100644 --- a/libs/video/renderer/gl/gl_dyn_part.c +++ b/libs/video/renderer/gl/gl_dyn_part.c @@ -42,6 +42,7 @@ #include "QF/cmd.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/mersenne.h" #include "QF/qargs.h" #include "QF/quakefs.h" @@ -521,12 +522,14 @@ R_RocketTrail_QF (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (1.5); @@ -555,12 +558,14 @@ R_GrenadeTrail_QF (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 6.0 + qfrandom (7.0); @@ -590,12 +595,14 @@ R_BloodTrail_QF (const entity_t *ent) float len = 0.0; int j; vec3_t old_origin, porg, pvel, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 5.0 + qfrandom (10.0); @@ -630,12 +637,14 @@ R_SlightBloodTrail_QF (const entity_t *ent) float len = 0.0; int j; vec3_t old_origin, porg, pvel, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (7.5); @@ -670,12 +679,14 @@ R_WizTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -711,12 +722,14 @@ R_FlameTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -752,12 +765,14 @@ R_VoorTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; int j; vec3_t subtract, old_origin, porg, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -790,7 +805,8 @@ R_GlowTrail_QF (const entity_t *ent, int glow_color) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, (maxlen - dist), subtract); @@ -869,12 +885,14 @@ R_RocketTrail_EE (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (1.5); @@ -904,12 +922,14 @@ R_GrenadeTrail_EE (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 6.0 + qfrandom (7.0); @@ -1143,7 +1163,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) // l = r_maxparticles - numparticles; // } - VectorCopy (ent->origin, org); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); for (i = -16; i < 16; i += 8) { dir [1] = i * 8; @@ -1177,6 +1197,7 @@ R_EntityParticles_ID (const entity_t *ent) float angle, sp, sy, cp, cy; // cr, sr float beamlength = 16.0, dist = 64.0; vec3_t forward, porg; + vec3_t org; if (numparticles + j >= r_maxparticles) { return; @@ -1184,6 +1205,8 @@ R_EntityParticles_ID (const entity_t *ent) j = r_maxparticles - numparticles; } + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + if (!avelocities[0][0]) { for (i = 0; i < NUMVERTEXNORMALS; i++) { int k; @@ -1209,11 +1232,11 @@ R_EntityParticles_ID (const entity_t *ent) forward[1] = cp * sy; forward[2] = -sp; - porg[0] = ent->origin[0] + r_avertexnormals[i][0] * dist + + porg[0] = org[0] + r_avertexnormals[i][0] * dist + forward[0] * beamlength; - porg[1] = ent->origin[1] + r_avertexnormals[i][1] * dist + + porg[1] = org[1] + r_avertexnormals[i][1] * dist + forward[1] * beamlength; - porg[2] = ent->origin[2] + r_avertexnormals[i][2] * dist + + porg[2] = org[2] + r_avertexnormals[i][2] * dist + forward[2] * beamlength; particle_new (pt_explode, part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 0.01, 0x6f, 1.0, 0); @@ -1232,7 +1255,8 @@ R_RocketTrail_ID (const entity_t *ent) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, (maxlen - dist), subtract); @@ -1264,7 +1288,8 @@ R_GrenadeTrail_ID (const entity_t *ent) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1291,12 +1316,14 @@ R_BloodTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; unsigned int rnd; vec3_t old_origin, subtract, vec, porg; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1322,12 +1349,14 @@ R_SlightBloodTrail_ID (const entity_t *ent) float dist = 6.0, len = 0.0; unsigned int rnd; vec3_t old_origin, porg, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1353,12 +1382,14 @@ R_WizTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1390,12 +1421,14 @@ R_FlameTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1427,12 +1460,14 @@ R_VoorTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; unsigned int rnd; vec3_t old_origin, porg, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1471,7 +1506,7 @@ gl_R_DrawParticles (void) qfglDepthMask (GL_FALSE); qfglInterleavedArrays (GL_T2F_C4UB_V3F, 0, particleVertexArray); - minparticledist = DotProduct (r_refdef.vieworg, vpn) + + minparticledist = DotProduct (r_refdef.viewposition, vpn) + r_particles_nearclip->value; activeparticles = 0; diff --git a/libs/video/renderer/gl/gl_lightmap.c b/libs/video/renderer/gl/gl_lightmap.c index d46c35014..2ea33a8c0 100644 --- a/libs/video/renderer/gl/gl_lightmap.c +++ b/libs/video/renderer/gl/gl_lightmap.c @@ -43,6 +43,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" #include "QF/GL/defines.h" @@ -117,16 +118,22 @@ R_AddDynamicLights_1 (msurface_t *surf) unsigned int sdtable[18]; unsigned int *bl; vec3_t impact, local; + vec4f_t entorigin = { 0, 0, 0, 1 }; smax = (surf->extents[0] >> 4) + 1; smax_bytes = smax * gl_internalformat; tmax = (surf->extents[1] >> 4) + 1; + if (currententity->transform) { + //FIXME give world entity a transform + entorigin = Transform_GetWorldPosition (currententity->transform); + } + for (lnum = 0; lnum < r_maxdlights; lnum++) { if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) continue; // not lit by this light - VectorSubtract (r_dlights[lnum].origin, currententity->origin, local); + VectorSubtract (r_dlights[lnum].origin, entorigin, local); dist = DotProduct (local, surf->plane->normal) - surf->plane->dist; VectorMultSub (r_dlights[lnum].origin, dist, surf->plane->normal, impact); @@ -182,16 +189,21 @@ R_AddDynamicLights_3 (msurface_t *surf) unsigned int sdtable[18]; unsigned int *bl; vec3_t impact, local; + vec4f_t entorigin = { 0, 0, 0, 1 }; smax = (surf->extents[0] >> 4) + 1; smax_bytes = smax * gl_internalformat; tmax = (surf->extents[1] >> 4) + 1; + if (currententity->transform) { + entorigin = Transform_GetWorldPosition (currententity->transform); + } + for (lnum = 0; lnum < r_maxdlights; lnum++) { if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) continue; // not lit by this light - VectorSubtract (r_dlights[lnum].origin, currententity->origin, local); + VectorSubtract (r_dlights[lnum].origin, entorigin, local); dist = DotProduct (local, surf->plane->normal) - surf->plane->dist; VectorMultSub (r_dlights[lnum].origin, dist, surf->plane->normal, impact); diff --git a/libs/video/renderer/gl/gl_mod_alias.c b/libs/video/renderer/gl/gl_mod_alias.c index 92c67038d..3f96b4364 100644 --- a/libs/video/renderer/gl/gl_mod_alias.c +++ b/libs/video/renderer/gl/gl_mod_alias.c @@ -196,8 +196,10 @@ GL_DrawAliasShadowTri (const aliashdr_t *paliashdr, const vert_order_t *vo) vec3_t point; const vec_t *scale = paliashdr->mdl.scale; const vec_t *scale_origin = paliashdr->mdl.scale_origin; + vec4f_t entorigin; - lheight = currententity->origin[2] - lightspot[2]; + entorigin = Transform_GetWorldPosition (currententity->transform); + lheight = entorigin[2] - lightspot[2]; height = -lheight + 1.0; qfglBegin (GL_TRIANGLES); @@ -232,8 +234,10 @@ GL_DrawAliasShadow (const aliashdr_t *paliashdr, const vert_order_t *vo) const int *order = vo->order; vec3_t point; const blended_vert_t *verts = vo->verts; + vec4f_t entorigin; - lheight = currententity->origin[2] - lightspot[2]; + entorigin = Transform_GetWorldPosition (currententity->transform); + lheight = entorigin[2] - lightspot[2]; height = -lheight + 1.0; while ((count = *order++)) { @@ -413,17 +417,23 @@ gl_R_DrawAliasModel (entity_t *e) dlight_t *l; model_t *model; vec3_t dist, scale; + vec4f_t origin; vert_order_t *vo; model = e->renderer.model; radius = model->radius; - if (e->scale != 1.0) - radius *= e->scale; - if (R_CullSphere (e->origin, radius)) + origin = Transform_GetWorldPosition (e->transform); + VectorCopy (Transform_GetWorldScale (e->transform), scale); + //FIXME assumes uniform scale + if (scale[0] != 1.0) { + radius *= scale[0]; + } + if (R_CullSphere (&origin[0], radius)) {//FIXME return; + } - VectorSubtract (r_origin, e->origin, modelorg); + VectorSubtract (r_origin, origin, modelorg); gl_modelalpha = e->renderer.colormod[3]; @@ -436,7 +446,7 @@ gl_R_DrawAliasModel (entity_t *e) float lightadj; // get lighting information - R_LightPoint (&r_worldentity.renderer.model->brush, e->origin); + R_LightPoint (&r_worldentity.renderer.model->brush, &origin[0]);//FIXME lightadj = (ambientcolor[0] + ambientcolor[1] + ambientcolor[2]) / 765.0; @@ -457,7 +467,7 @@ gl_R_DrawAliasModel (entity_t *e) if (gl_vector_light->int_val) { for (l = r_dlights, lnum = 0; lnum < r_maxdlights; lnum++, l++) { if (l->die >= vr_data.realtime) { - VectorSubtract (l->origin, e->origin, dist); + VectorSubtract (l->origin, origin, dist); if ((d = DotProduct (dist, dist)) > // Out of range ((l->radius + radius) * (l->radius + radius))) { continue; @@ -508,7 +518,7 @@ gl_R_DrawAliasModel (entity_t *e) for (l = r_dlights, lnum = 0; lnum < r_maxdlights; lnum++, l++) { if (l->die >= vr_data.realtime) { - VectorSubtract (l->origin, e->origin, dist); + VectorSubtract (l->origin, origin, dist); if ((d = DotProduct (dist, dist)) > (l->radius + radius) * (l->radius + radius)) { @@ -567,10 +577,12 @@ gl_R_DrawAliasModel (entity_t *e) if (paliashdr->mdl.ident == HEADER_MDL16) { // because we multipled by 256 when we loaded the verts, we have to // scale by 1/256 when drawing. - VectorScale (paliashdr->mdl.scale, e->scale / 256.0, scale); + //FIXME see scaling above + VectorScale (paliashdr->mdl.scale, 1 / 256.0, scale); vo = GL_GetAliasFrameVerts16 (paliashdr, e); } else { - VectorScale (paliashdr->mdl.scale, e->scale, scale); + //FIXME see scaling above + VectorScale (paliashdr->mdl.scale, 1, scale); vo = GL_GetAliasFrameVerts (paliashdr, e); } diff --git a/libs/video/renderer/gl/gl_mod_iqm.c b/libs/video/renderer/gl/gl_mod_iqm.c index 601a76fbf..f66c2c7ca 100644 --- a/libs/video/renderer/gl/gl_mod_iqm.c +++ b/libs/video/renderer/gl/gl_mod_iqm.c @@ -103,7 +103,6 @@ gl_R_DrawIQMModel (entity_t *ent) qfglPushMatrix (); gl_R_RotateForEntity (ent); - qfglScalef (ent->scale, ent->scale, ent->scale); for (i = 0; i < iqm->num_meshes; i++) { qfglBindTexture (GL_TEXTURE_2D, gl->textures[i]); diff --git a/libs/video/renderer/gl/gl_mod_sprite.c b/libs/video/renderer/gl/gl_mod_sprite.c index d0dd91444..d4b1c1f86 100644 --- a/libs/video/renderer/gl/gl_mod_sprite.c +++ b/libs/video/renderer/gl/gl_mod_sprite.c @@ -123,10 +123,6 @@ R_DrawSpriteModel_f (entity_t *e) VectorCopy (vup, up); VectorCopy (vright, right); } - if (e->scale != 1.0) { - up *= e->scale; - right *= e->scale; - } VectorCopy (e->renderer.colormod, color); modelalpha = color[3] = e->renderer.colormod[3]; @@ -194,10 +190,6 @@ R_DrawSpriteModel_VA_f (entity_t *e) VectorCopy (vup, up); VectorCopy (vright, right); } - if (e->scale != 1.0) { - up *= e->scale; - right *= e->scale; - } for (i = 0; i < 4; i++) { color[i] = e->renderer.colormod[i] * 255; diff --git a/libs/video/renderer/gl/gl_rmain.c b/libs/video/renderer/gl/gl_rmain.c index 8079b790b..8bf8ec46a 100644 --- a/libs/video/renderer/gl/gl_rmain.c +++ b/libs/video/renderer/gl/gl_rmain.c @@ -74,7 +74,7 @@ qboolean gl_mirror; plane_t *gl_mirror_plane; float gl_r_world_matrix[16]; -static float r_base_world_matrix[16]; +//FIXME static float r_base_world_matrix[16]; //vec3_t gl_shadecolor; // Ender (Extend) Colormod float gl_modelalpha; // Ender (Extend) Alpha @@ -344,9 +344,12 @@ gl_R_SetupFrame (void) gl_Fog_SetupFrame (); // build the transformation matrix for the given view angles - VectorCopy (r_refdef.vieworg, r_origin); + VectorCopy (r_refdef.viewposition, r_origin); + + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 1, 0, 0, 0 }), vpn); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, -1, 0, 0 }), vright); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, 0, 1, 0 }), vup); - AngleVectors (r_refdef.viewangles, vpn, vright, vup); R_SetFrustum (); @@ -419,13 +422,19 @@ R_SetupGL (void) qfglMatrixMode (GL_MODELVIEW); qfglLoadIdentity (); - qfglRotatef (-90, 1, 0, 0); // put Z going up - qfglRotatef (90, 0, 0, 1); // put Z going up - qfglRotatef (-r_refdef.viewangles[ROLL], 1, 0, 0); - qfglRotatef (-r_refdef.viewangles[PITCH], 0, 1, 0); - qfglRotatef (-r_refdef.viewangles[YAW], 0, 0, 1); - qfglTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], - -r_refdef.vieworg[2]); + static mat4f_t z_up = { + { 0, 0, -1, 0}, + {-1, 0, 0, 0}, + { 0, 1, 0, 0}, + { 0, 0, 0, 1}, + }; + mat4f_t view; + mat4fquat (view, qconjf (r_refdef.viewrotation)); + mmulf (view, z_up, view); + vec4f_t offset = -r_refdef.viewposition; + offset[3] = 1; + view[3] = mvmulf (view, offset); + qfglLoadMatrixf (&view[0][0]); qfglGetFloatv (GL_MODELVIEW_MATRIX, gl_r_world_matrix); @@ -480,12 +489,12 @@ R_RenderScene (void) static void R_Mirror (void) { - float d; + //float d; // msurface_t *s; // if (!gl_mirror) // FIXME: Broken return; - +/* memcpy (r_base_world_matrix, gl_r_world_matrix, sizeof (r_base_world_matrix)); @@ -551,6 +560,7 @@ R_Mirror (void) r_worldentity.model->textures[gl_mirrortexturenum]->texturechain = NULL; #endif qfglColor3ubv (color_white); +*/ } /* @@ -584,6 +594,18 @@ R_RenderView_ (void) R_ZGraph (); } +//FIXME static void R_RenderViewFishEye (void); + +void +gl_R_RenderView (void) +{ + R_RenderView_ (); + /*if(!scr_fisheye->int_val) + R_RenderView_ (); + else + R_RenderViewFishEye ();*/ +} +/*FIXME // Algorithm: // Draw up to six views, one in each direction. // Save the picture to cube map texture, use GL_ARB_texture_cube_map. @@ -593,17 +615,6 @@ R_RenderView_ (void) // grid vertices coordinates. // Render view. Fisheye is done. -static void R_RenderViewFishEye (void); - -void -gl_R_RenderView (void) -{ - if(!scr_fisheye->int_val) - R_RenderView_ (); - else - R_RenderViewFishEye (); -} - #define BOX_FRONT 0 #define BOX_RIGHT 1 #define BOX_BEHIND 2 @@ -891,7 +902,7 @@ R_RenderViewFishEye (void) R_SetupGL_Viewport_and_Perspective (); qfglMatrixMode (GL_MODELVIEW); qfglCallList (fisheye_grid); -} +}*/ void gl_R_ClearState (void) diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index d9a1c6797..de34bb203 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -74,6 +74,7 @@ static void R_Envmap_f (void) { + /*FIXME update for simd byte buffer[256 * 256 * 4]; qfglDrawBuffer (GL_FRONT); @@ -122,7 +123,7 @@ R_Envmap_f (void) gl_envmap = false; qfglDrawBuffer (GL_BACK); qfglReadBuffer (GL_BACK); - gl_ctx->end_rendering (); + gl_ctx->end_rendering ();*/ } void @@ -250,6 +251,7 @@ gl_R_ViewChanged (float aspect) void gl_R_TimeRefresh_f (void) { +/*FIXME update for simd double start, stop, time; int i; @@ -265,4 +267,5 @@ gl_R_TimeRefresh_f (void) stop = Sys_DoubleTime (); time = stop - start; Sys_Printf ("%g seconds (%g fps)\n", time, 128 / time); +*/ } diff --git a/libs/video/renderer/gl/gl_rsurf.c b/libs/video/renderer/gl/gl_rsurf.c index b954fc066..96d1ec93f 100644 --- a/libs/video/renderer/gl/gl_rsurf.c +++ b/libs/video/renderer/gl/gl_rsurf.c @@ -545,12 +545,13 @@ gl_R_DrawBrushModel (entity_t *e) if (e->scale != 1.0) radius *= e->scale; #endif - if (R_CullSphere (e->origin, radius)) + if (R_CullSphere (&worldMatrix[3][0], radius)) {//FIXME return; + } } else { rotated = false; - VectorAdd (e->origin, model->mins, mins); - VectorAdd (e->origin, model->maxs, maxs); + VectorAdd (worldMatrix[3], model->mins, mins); + VectorAdd (worldMatrix[3], model->maxs, maxs); #if 0 // QSG FIXME if (e->scale != 1.0) { VectorScale (mins, e->scale, mins); @@ -561,7 +562,7 @@ gl_R_DrawBrushModel (entity_t *e) return; } - VectorSubtract (r_refdef.vieworg, e->origin, modelorg); + VectorSubtract (r_refdef.viewposition, worldMatrix[3], modelorg); if (rotated) { vec4f_t temp = { modelorg[0], modelorg[1], modelorg[2], 0 }; @@ -579,7 +580,7 @@ gl_R_DrawBrushModel (entity_t *e) || (!r_dlights[k].radius)) continue; - VectorSubtract (r_dlights[k].origin, e->origin, lightorigin); + VectorSubtract (r_dlights[k].origin, worldMatrix[3], lightorigin); R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, brush->nodes + brush->hulls[0].firstclipnode); } @@ -723,7 +724,7 @@ gl_R_DrawWorld (void) memset (&worldent, 0, sizeof (worldent)); worldent.renderer.model = r_worldentity.renderer.model; - VectorCopy (r_refdef.vieworg, modelorg); + VectorCopy (r_refdef.viewposition, modelorg); currententity = &worldent; diff --git a/libs/video/renderer/gl/gl_sky.c b/libs/video/renderer/gl/gl_sky.c index cb3258246..db289326b 100644 --- a/libs/video/renderer/gl/gl_sky.c +++ b/libs/video/renderer/gl/gl_sky.c @@ -189,9 +189,9 @@ R_DrawSkyBox (void) float *v = (float *) gl_skyvec[i][j]; qfglTexCoord2fv (v); - qfglVertex3f (r_refdef.vieworg[0] + v[2], - r_refdef.vieworg[1] + v[3], - r_refdef.vieworg[2] + v[4]); + qfglVertex3f (r_refdef.viewposition[0] + v[2], + r_refdef.viewposition[1] + v[3], + r_refdef.viewposition[2] + v[4]); } qfglEnd (); } @@ -219,7 +219,7 @@ skydome_vertex (const vec3_t v, float speedscale) s = speedscale + dir[0]; t = speedscale + dir[1]; - VectorAdd (r_refdef.vieworg, v, point); + VectorAdd (r_refdef.viewposition, v, point); qfglTexCoord2f (s, t); qfglVertex3fv (point); @@ -242,7 +242,7 @@ skydome_debug (void) h = 1; t = 0; - VectorAdd (zenith, r_refdef.vieworg, v[0]); + VectorAdd (zenith, r_refdef.viewposition, v[0]); for (b = 1; b <= 8; b++) { x = gl_bubble_costable[b + 8]; y = -gl_bubble_sintable[b + 8]; @@ -250,7 +250,7 @@ skydome_debug (void) v[h][0] = a1x * x; v[h][1] = a1y * x; v[h][2] = y * domescale[2]; - VectorAdd (v[h], r_refdef.vieworg, v[h]); + VectorAdd (v[h], r_refdef.viewposition, v[h]); for (i = t; i != h; i = (i + 1) % 3) { qfglVertex3fv (v[i]); qfglVertex3fv (v[h]); @@ -262,7 +262,7 @@ skydome_debug (void) v[h][0] = a2x * x; v[h][1] = a2y * x; v[h][2] = y * domescale[2]; - VectorAdd (v[h], r_refdef.vieworg, v[h]); + VectorAdd (v[h], r_refdef.viewposition, v[h]); for (i = t; i != h; i = (i + 1) % 3) { qfglVertex3fv (v[i]); qfglVertex3fv (v[h]); @@ -274,7 +274,7 @@ skydome_debug (void) h = 1; t = 0; - VectorAdd (nadir, r_refdef.vieworg, v[0]); + VectorAdd (nadir, r_refdef.viewposition, v[0]); for (b = 15; b >= 8; b--) { x = gl_bubble_costable[b + 8]; y = -gl_bubble_sintable[b + 8]; @@ -282,7 +282,7 @@ skydome_debug (void) v[h][0] = a2x * x; v[h][1] = a2y * x; v[h][2] = y * domescale[2]; - VectorAdd (v[h], r_refdef.vieworg, v[h]); + VectorAdd (v[h], r_refdef.viewposition, v[h]); for (i = t; i != h; i = (i + 1) % 3) { qfglVertex3fv (v[i]); qfglVertex3fv (v[h]); @@ -294,7 +294,7 @@ skydome_debug (void) v[h][0] = a1x * x; v[h][1] = a1y * x; v[h][2] = y * domescale[2]; - VectorAdd (v[h], r_refdef.vieworg, v[h]); + VectorAdd (v[h], r_refdef.viewposition, v[h]); for (i = t; i != h; i = (i + 1) % 3) { qfglVertex3fv (v[i]); qfglVertex3fv (v[h]); diff --git a/libs/video/renderer/gl/gl_sky_clip.c b/libs/video/renderer/gl/gl_sky_clip.c index 44a560005..697403eb9 100644 --- a/libs/video/renderer/gl/gl_sky_clip.c +++ b/libs/video/renderer/gl/gl_sky_clip.c @@ -220,14 +220,14 @@ find_cube_vertex (int face1, int face2, int face3, vec3_t v) set_vertex add the vertex to the polygon describing the face of the cube. Offsets - the vertex relative to r_refdef.vieworg so the cube is always centered + the vertex relative to r_refdef.viewposition so the cube is always centered on the player and also calculates the texture coordinates of the vertex (wish I could find a cleaner way of calculating s and t). */ static void set_vertex (struct box_def *box, int face, int ind, const vec3_t v) { - VectorAdd (v, r_refdef.vieworg, box->face[face].poly.verts[ind]); + VectorAdd (v, r_refdef.viewposition, box->face[face].poly.verts[ind]); switch (face) { case 0: box->face[face].poly.verts[ind][3] = (1024 - v[1] + 4) / BOX_WIDTH; @@ -601,14 +601,14 @@ R_DrawSkyBoxPoly (const glpoly_t *poly) Sys_Error ("too many verts!"); } - VectorSubtract (poly->verts[poly->numverts - 1], r_refdef.vieworg, last_v); + VectorSubtract (poly->verts[poly->numverts - 1], r_refdef.viewposition, last_v); prev_face = determine_face (last_v); box.visited_faces[0].face = prev_face; box.face_count = 1; for (i = 0; i < poly->numverts; i++) { - VectorSubtract (poly->verts[i], r_refdef.vieworg, v); + VectorSubtract (poly->verts[i], r_refdef.viewposition, v); face = determine_face (v); if (face != prev_face) { if ((face_axis[face]) == (face_axis[prev_face])) { @@ -864,11 +864,11 @@ gl_R_DrawSkyChain (const instsurf_t *sky_chain) vec3_t x, c = { 0, 0, 0 }; for (i = 0; i < p->numverts; i++) { - VectorSubtract (p->verts[i], r_refdef.vieworg, x); + VectorSubtract (p->verts[i], r_refdef.viewposition, x); VectorAdd (x, c, c); } VectorScale (c, 1.0 / p->numverts, c); - VectorAdd (c, r_refdef.vieworg, c); + VectorAdd (c, r_refdef.viewposition, c); qfglVertex3fv (c); p = p->next; } @@ -889,7 +889,7 @@ gl_R_DrawSkyChain (const instsurf_t *sky_chain) qfglBegin (GL_LINE_LOOP); for (j = 0; j < 4; j++) { VectorScale (&gl_skyvec[i][j][2], 1.0 / 128.0, v); - VectorAdd (v, r_refdef.vieworg, v); + VectorAdd (v, r_refdef.viewposition, v); qfglVertex3fv (v); } qfglEnd (); diff --git a/libs/video/renderer/glsl/glsl_alias.c b/libs/video/renderer/glsl/glsl_alias.c index e0c29cfe4..22983ceef 100644 --- a/libs/video/renderer/glsl/glsl_alias.c +++ b/libs/video/renderer/glsl/glsl_alias.c @@ -157,17 +157,20 @@ calc_lighting (entity_t *ent, float *ambient, float *shadelight, unsigned i; float add; vec3_t dist; + vec4f_t entorigin; int light; + entorigin = Transform_GetWorldPosition (ent->transform); + VectorSet ( -1, 0, 0, lightvec); //FIXME - light = R_LightPoint (&r_worldentity.renderer.model->brush, ent->origin); + light = R_LightPoint (&r_worldentity.renderer.model->brush, &entorigin[0]); *ambient = max (light, max (ent->renderer.model->min_light, ent->renderer.min_light) * 128); *shadelight = *ambient; for (i = 0; i < r_maxdlights; i++) { if (r_dlights[i].die >= vr_data.realtime) { - VectorSubtract (ent->origin, r_dlights[i].origin, dist); + VectorSubtract (entorigin, r_dlights[i].origin, dist); add = r_dlights[i].radius - VectorLength (dist); if (add > 0) *ambient += add; diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index 3fc716cf8..50a4e98af 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -660,7 +660,8 @@ R_DrawBrushModel (entity_t *e) plane_t *plane; msurface_t *surf; qboolean rotated; - vec3_t mins, maxs, org; + vec3_t mins, maxs; + vec4f_t org; mod_brush_t *brush; model = e->renderer.model; @@ -671,19 +672,20 @@ R_DrawBrushModel (entity_t *e) if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { rotated = true; radius = model->radius; - if (R_CullSphere (e->origin, radius)) + if (R_CullSphere (&mat[3][0], radius)) { // FIXME return; + } } else { rotated = false; - VectorAdd (e->origin, model->mins, mins); - VectorAdd (e->origin, model->maxs, maxs); + VectorAdd (mat[3], model->mins, mins); + VectorAdd (mat[3], model->maxs, maxs); if (R_CullBox (mins, maxs)) return; } - VectorSubtract (r_refdef.vieworg, e->origin, org); + org = r_refdef.viewposition - mat[3]; if (rotated) { - vec4f_t temp = { org[0], org[1], org[2], 0 }; + vec4f_t temp = org; org[0] = dotf (temp, mat[0])[0]; org[1] = dotf (temp, mat[1])[0]; @@ -699,7 +701,7 @@ R_DrawBrushModel (entity_t *e) || (!r_dlights[k].radius)) continue; - VectorSubtract (r_dlights[k].origin, e->origin, lightorigin); + VectorSubtract (r_dlights[k].origin, mat[3], lightorigin); R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, brush->nodes + brush->hulls[0].firstclipnode); } diff --git a/libs/video/renderer/glsl/glsl_iqm.c b/libs/video/renderer/glsl/glsl_iqm.c index 76a9ae85e..93a25e982 100644 --- a/libs/video/renderer/glsl/glsl_iqm.c +++ b/libs/video/renderer/glsl/glsl_iqm.c @@ -214,22 +214,24 @@ glsl_R_DrawIQM (void) dlight_t *lights[MAX_IQM_LIGHTS]; int i; vec_t norm_mat[9]; + vec4f_t entorigin; mat4f_t mvp_mat; float blend; iqmframe_t *frame; - R_LightPoint (&r_worldentity.renderer.model->brush, ent->origin);//FIXME min_light? - VectorScale (ambientcolor, 1/255.0, ambientcolor); - R_FindNearLights (ent->origin, MAX_IQM_LIGHTS, lights); - // we need only the rotation for normals. mat4f_t mat; Transform_GetWorldMatrix (ent->transform, mat); VectorCopy (mat[0], norm_mat + 0); VectorCopy (mat[1], norm_mat + 3); VectorCopy (mat[2], norm_mat + 6); + entorigin = mat[3]; mmulf (mvp_mat, iqm_vp, mat); + R_LightPoint (&r_worldentity.renderer.model->brush, &entorigin[0]);//FIXME min_light? + VectorScale (ambientcolor, 1/255.0, ambientcolor); + R_FindNearLights (&entorigin[0], MAX_IQM_LIGHTS, lights);//FIXME + blend = R_IQMGetLerpedFrames (ent, iqm); frame = R_IQMBlendFrames (iqm, ent->animation.pose1, ent->animation.pose2, blend, 0); @@ -240,7 +242,7 @@ glsl_R_DrawIQM (void) lightpar_t *l = &iqm_shader.lights[i]; if (!lights[i]) break; - VectorSubtract (lights[i]->origin, ent->origin, val); + VectorSubtract (lights[i]->origin, entorigin, val); val[3] = lights[i]->radius; qfeglUniform4fv (l->position.location, 1, val); qfeglUniform4fv (l->color.location, 1, lights[i]->color); diff --git a/libs/video/renderer/glsl/glsl_lightmap.c b/libs/video/renderer/glsl/glsl_lightmap.c index 65af9d238..f34de4692 100644 --- a/libs/video/renderer/glsl/glsl_lightmap.c +++ b/libs/video/renderer/glsl/glsl_lightmap.c @@ -44,6 +44,7 @@ #endif #include +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -70,6 +71,7 @@ R_AddDynamicLights_1 (msurface_t *surf) int sd, td; float dist, rad, minlight; vec3_t impact, local, lightorigin; + vec4f_t entorigin = { 0, 0, 0, 1}; int s, t; int smax, tmax; mtexinfo_t *tex; @@ -78,12 +80,16 @@ R_AddDynamicLights_1 (msurface_t *surf) tmax = (surf->extents[1] >> 4) + 1; tex = surf->texinfo; + if (currententity->transform) { + //FIXME give world entity a transform + entorigin = Transform_GetWorldPosition (currententity->transform); + } + for (lnum = 0; lnum < r_maxdlights; lnum++) { if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) continue; // not lit by this light - VectorSubtract (r_dlights[lnum].origin, currententity->origin, - lightorigin); + VectorSubtract (r_dlights[lnum].origin, entorigin, lightorigin); rad = r_dlights[lnum].radius; dist = DotProduct (lightorigin, surf->plane->normal) - surf->plane->dist; diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index ba8c2dce7..fed46ed3a 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -113,8 +113,11 @@ glsl_R_SetupFrame (void) R_ClearEnts (); r_framecount++; - VectorCopy (r_refdef.vieworg, r_origin); - AngleVectors (r_refdef.viewangles, vpn, vright, vup); + VectorCopy (r_refdef.viewposition, r_origin); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 1, 0, 0, 0 }), vpn); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, -1, 0, 0 }), vright); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, 0, 1, 0 }), vup); + R_SetFrustum (); @@ -131,7 +134,6 @@ R_SetupView (void) { 0, 1, 0, 0}, { 0, 0, 0, 1}, }; - vec4f_t rotation; vec4f_t offset = { 0, 0, 0, 1 }; x = r_refdef.vrect.x; @@ -140,11 +142,10 @@ R_SetupView (void) h = r_refdef.vrect.height; qfeglViewport (x, y, w, h); - AngleQuat (r_refdef.viewangles, &rotation[0]); - rotation = qconjf (rotation); - mat4fquat (glsl_view, rotation); + mat4fquat (glsl_view, qconjf (r_refdef.viewrotation)); mmulf (glsl_view, z_up, glsl_view); - VectorNegate (r_refdef.vieworg, offset); + offset = -r_refdef.viewposition; + offset[3] = 1; glsl_view[3] = mvmulf (glsl_view, offset); qfeglEnable (GL_CULL_FACE); @@ -304,6 +305,7 @@ glsl_R_ClearState (void) void glsl_R_TimeRefresh_f (void) { +/* FIXME update for simd double start, stop, time; int i; @@ -319,4 +321,5 @@ glsl_R_TimeRefresh_f (void) stop = Sys_DoubleTime (); time = stop - start; Sys_Printf ("%g seconds (%g fps)\n", time, 128 / time); +*/ } diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index eb7eccb6d..de8c64602 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -42,6 +42,7 @@ #include "QF/cmd.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/image.h" #include "QF/mersenne.h" #include "QF/qargs.h" @@ -629,12 +630,14 @@ R_RocketTrail_QF (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (1.5); @@ -663,12 +666,14 @@ R_GrenadeTrail_QF (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 6.0 + qfrandom (7.0); @@ -698,12 +703,14 @@ R_BloodTrail_QF (const entity_t *ent) float len = 0.0; int j; vec3_t old_origin, porg, pvel, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 5.0 + qfrandom (10.0); @@ -738,12 +745,14 @@ R_SlightBloodTrail_QF (const entity_t *ent) float len = 0.0; int j; vec3_t old_origin, porg, pvel, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (7.5); @@ -778,12 +787,14 @@ R_WizTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -819,12 +830,14 @@ R_FlameTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -860,12 +873,14 @@ R_VoorTrail_QF (const entity_t *ent) float dist = 3.0, len = 0.0; int j; vec3_t subtract, old_origin, porg, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, maxlen - dist, subtract); @@ -898,7 +913,8 @@ R_GlowTrail_QF (const entity_t *ent, int glow_color) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; VectorScale (vec, (maxlen - dist), subtract); @@ -977,12 +993,14 @@ R_RocketTrail_EE (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 1.5 + qfrandom (1.5); @@ -1012,12 +1030,14 @@ R_GrenadeTrail_EE (const entity_t *ent) float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; vec3_t old_origin, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); origlen = vr_data.frametime / maxlen; pscale = 6.0 + qfrandom (7.0); @@ -1251,7 +1271,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) // l = r_maxparticles - numparticles; // } - VectorCopy (ent->origin, org); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); for (i = -16; i < 16; i += 8) { dir [1] = i * 8; @@ -1285,6 +1305,7 @@ R_EntityParticles_ID (const entity_t *ent) float angle, sp, sy, cp, cy; // cr, sr float beamlength = 16.0, dist = 64.0; vec3_t forward, porg; + vec3_t org; if (numparticles + j >= r_maxparticles) { return; @@ -1292,6 +1313,8 @@ R_EntityParticles_ID (const entity_t *ent) j = r_maxparticles - numparticles; } + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + for (i = 0; i < NUMVERTEXNORMALS; i++) { int k; for (k = 0; k < 3; k++) { @@ -1315,11 +1338,11 @@ R_EntityParticles_ID (const entity_t *ent) forward[1] = cp * sy; forward[2] = -sp; - porg[0] = ent->origin[0] + vertex_normals[i][0] * dist + + porg[0] = org[0] + vertex_normals[i][0] * dist + forward[0] * beamlength; - porg[1] = ent->origin[1] + vertex_normals[i][1] * dist + + porg[1] = org[1] + vertex_normals[i][1] * dist + forward[1] * beamlength; - porg[2] = ent->origin[2] + vertex_normals[i][2] * dist + + porg[2] = org[2] + vertex_normals[i][2] * dist + forward[2] * beamlength; particle_new (pt_explode, part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 0.01, 0x6f, 1.0, 0); @@ -1338,7 +1361,8 @@ R_RocketTrail_ID (const entity_t *ent) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, (maxlen - dist), subtract); @@ -1370,7 +1394,8 @@ R_GrenadeTrail_ID (const entity_t *ent) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1397,12 +1422,14 @@ R_BloodTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; unsigned int rnd; vec3_t old_origin, subtract, vec, porg; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1428,12 +1455,14 @@ R_SlightBloodTrail_ID (const entity_t *ent) float dist = 6.0, len = 0.0; unsigned int rnd; vec3_t old_origin, porg, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1459,12 +1488,14 @@ R_WizTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1496,12 +1527,14 @@ R_FlameTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; static int tracercount; vec3_t old_origin, pvel, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1533,12 +1566,14 @@ R_VoorTrail_ID (const entity_t *ent) float dist = 3.0, len = 0.0; unsigned int rnd; vec3_t old_origin, porg, subtract, vec; + vec3_t org; if (numparticles >= r_maxparticles) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); maxlen = VectorNormalize (vec); VectorScale (vec, maxlen - dist, subtract); @@ -1594,7 +1629,7 @@ draw_qf_particles (void) // LordHavoc: particles should not affect zbuffer qfeglDepthMask (GL_FALSE); - minparticledist = DotProduct (r_refdef.vieworg, vpn) + + minparticledist = DotProduct (r_refdef.viewposition, vpn) + r_particles_nearclip->value; activeparticles = 0; @@ -1736,7 +1771,7 @@ draw_id_particles (void) qfeglEnable (GL_TEXTURE_2D); qfeglBindTexture (GL_TEXTURE_2D, glsl_palette); - minparticledist = DotProduct (r_refdef.vieworg, vpn) + + minparticledist = DotProduct (r_refdef.viewposition, vpn) + r_particles_nearclip->value; activeparticles = 0; diff --git a/libs/video/renderer/glsl/glsl_sprite.c b/libs/video/renderer/glsl/glsl_sprite.c index 4d35bc8d6..7eecea5dd 100644 --- a/libs/video/renderer/glsl/glsl_sprite.c +++ b/libs/video/renderer/glsl/glsl_sprite.c @@ -185,6 +185,7 @@ make_quad (mspriteframe_t *frame, vec4f_t vpn, vec4f_t vright, { vec4f_t left, up, right, down; vec4f_t ul, ur, ll, lr; + vec4f_t origin = Transform_GetWorldPosition (currententity->transform); // build the sprite poster in worldspace // first, rotate the sprite axes into world space @@ -198,12 +199,12 @@ make_quad (mspriteframe_t *frame, vec4f_t vpn, vec4f_t vright, ll = down + left; lr = down + right; // finally, translate the sprite corners, creating two triangles - VectorAdd (currententity->origin, ul, verts[0]); // first triangle - VectorAdd (currententity->origin, ur, verts[1]); - VectorAdd (currententity->origin, lr, verts[2]); - VectorAdd (currententity->origin, ul, verts[3]); // second triangle - VectorAdd (currententity->origin, lr, verts[4]); - VectorAdd (currententity->origin, ll, verts[5]); + VectorAdd (origin, ul, verts[0]); // first triangle + VectorAdd (origin, ur, verts[1]); + VectorAdd (origin, lr, verts[2]); + VectorAdd (origin, ul, verts[3]); // second triangle + VectorAdd (origin, lr, verts[4]); + VectorAdd (origin, ll, verts[5]); } void @@ -212,9 +213,9 @@ R_DrawSprite (void) entity_t *ent = currententity; msprite_t *sprite = (msprite_t *) ent->renderer.model->cache.data; mspriteframe_t *frame1, *frame2; - float blend, sr, cr, dot, angle; + float blend, sr, cr, dot; vec3_t tvec; - vec4f_t svpn = {}, svright = {}, svup = {}; + vec4f_t svpn = {}, svright = {}, svup = {}, rot; static quat_t color = { 1, 1, 1, 1}; float vertsa[6][3], vertsb[6][3]; static float uvab[6][4] = { @@ -284,9 +285,10 @@ R_DrawSprite (void) // rotated in that plane round the center according to the sprite // entity's roll angle. Thus svpn stays the same, but svright and // svup rotate - angle = currententity->angles[ROLL] * (M_PI / 180); - sr = sin (angle); - cr = cos (angle); + rot = Transform_GetLocalRotation (currententity->transform); + //FIXME assumes the entity is only rolled + sr = 2 * rot[0] * rot[3]; + cr = rot[3] * rot[3] - rot[0] * rot[0]; VectorCopy (vpn, svpn); VectorScale (vright, cr, svright); VectorMultAdd (svright, sr, vup, svright); diff --git a/libs/video/renderer/r_efrag.c b/libs/video/renderer/r_efrag.c index 86d494b6d..eb559e9cd 100644 --- a/libs/video/renderer/r_efrag.c +++ b/libs/video/renderer/r_efrag.c @@ -30,6 +30,7 @@ #include +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -210,8 +211,9 @@ R_AddEfrags (mod_brush_t *brush, entity_t *ent) entmodel = ent->renderer.model; - VectorAdd (ent->origin, entmodel->mins, emins); - VectorAdd (ent->origin, entmodel->maxs, emaxs); + vec4f_t org = Transform_GetWorldPosition (ent->transform); + VectorAdd (org, entmodel->mins, emins); + VectorAdd (org, entmodel->maxs, emaxs); ent->visibility.topnode = 0; R_SplitEntityOnNode (brush, ent, emins, emaxs); diff --git a/libs/video/renderer/sw/d_edge.c b/libs/video/renderer/sw/d_edge.c index f510e2063..d1e8a4e29 100644 --- a/libs/video/renderer/sw/d_edge.c +++ b/libs/video/renderer/sw/d_edge.c @@ -29,6 +29,7 @@ #endif #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "d_local.h" @@ -207,7 +208,8 @@ D_DrawSurfaces (void) // TODO: store once at start of frame currententity = s->entity; // FIXME: make this passed in // to R_RotateBmodel () - VectorSubtract (r_origin, currententity->origin, + VectorSubtract (r_origin, + Transform_GetWorldPosition (currententity->transform), local_modelorg); TransformVector (local_modelorg, transformed_modelorg); @@ -240,7 +242,8 @@ D_DrawSurfaces (void) // TODO: store once at start of frame currententity = s->entity; // FIXME: make this passed in // to R_RotateBmodel () - VectorSubtract (r_origin, currententity->origin, + VectorSubtract (r_origin, + Transform_GetWorldPosition (currententity->transform), local_modelorg); TransformVector (local_modelorg, transformed_modelorg); diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 8ab480bcc..63eecbb60 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -362,16 +362,16 @@ R_DrawEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; + VectorCopy (Transform_GetWorldPosition (currententity->transform), + r_entorigin); switch (currententity->renderer.model->type) { case mod_sprite: - VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); R_DrawSprite (); break; case mod_alias: case mod_iqm: - VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); minlight = max (currententity->renderer.model->min_light, @@ -384,7 +384,7 @@ R_DrawEntitiesOnList (void) || R_AliasCheckBBox ()) { // 128 instead of 255 due to clamping below j = max (R_LightPoint (&r_worldentity.renderer.model->brush, - currententity->origin), minlight * 128); + r_entorigin), minlight * 128); lighting.ambientlight = j; lighting.shadelight = j; @@ -393,7 +393,7 @@ R_DrawEntitiesOnList (void) for (lnum = 0; lnum < r_maxdlights; lnum++) { if (r_dlights[lnum].die >= vr_data.realtime) { - VectorSubtract (currententity->origin, + VectorSubtract (r_entorigin, r_dlights[lnum].origin, dist); add = r_dlights[lnum].radius - VectorLength (dist); @@ -443,7 +443,8 @@ R_DrawViewModel (void) if (!currententity->renderer.model) return; - VectorCopy (currententity->origin, r_entorigin); + VectorCopy (Transform_GetWorldPosition (currententity->transform), + r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); VectorCopy (vup, viewlightvec); @@ -453,7 +454,7 @@ R_DrawViewModel (void) currententity->renderer.model->min_light); j = max (R_LightPoint (&r_worldentity.renderer.model->brush, - currententity->origin), minlight * 128); + r_entorigin), minlight * 128); r_viewlighting.ambientlight = j; r_viewlighting.shadelight = j; @@ -468,7 +469,7 @@ R_DrawViewModel (void) if (dl->die < vr_data.realtime) continue; - VectorSubtract (currententity->origin, dl->origin, dist); + VectorSubtract (r_entorigin, dl->origin, dist); add = dl->radius - VectorLength (dist); if (add > 0) r_viewlighting.ambientlight += add; @@ -498,7 +499,7 @@ R_BmodelCheckBBox (model_t *clmodel, float *minmaxs) Transform_GetWorldMatrix (currententity->transform, mat); if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { for (i = 0; i < 4; i++) { - d = DotProduct (currententity->origin, view_clipplanes[i].normal); + d = DotProduct (mat[3], view_clipplanes[i].normal); d -= view_clipplanes[i].dist; if (d <= -clmodel->radius) @@ -546,6 +547,7 @@ R_DrawBEntitiesOnList (void) int j, clipflags; unsigned int k; vec3_t oldorigin; + vec3_t origin; model_t *clmodel; float minmaxs[6]; entity_t *ent; @@ -559,6 +561,8 @@ R_DrawBEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; + VectorCopy (Transform_GetWorldPosition (currententity->transform), + origin); switch (currententity->renderer.model->type) { case mod_brush: clmodel = currententity->renderer.model; @@ -566,16 +570,15 @@ R_DrawBEntitiesOnList (void) // see if the bounding box lets us trivially reject, also // sets trivial accept status for (j = 0; j < 3; j++) { - minmaxs[j] = currententity->origin[j] + clmodel->mins[j]; - minmaxs[3 + j] = currententity->origin[j] + - clmodel->maxs[j]; + minmaxs[j] = origin[j] + clmodel->mins[j]; + minmaxs[3 + j] = origin[j] + clmodel->maxs[j]; } clipflags = R_BmodelCheckBBox (clmodel, minmaxs); if (clipflags != BMODEL_FULLY_CLIPPED) { mod_brush_t *brush = &clmodel->brush; - VectorCopy (currententity->origin, r_entorigin); + VectorCopy (origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // FIXME: is this needed? @@ -594,8 +597,7 @@ R_DrawBEntitiesOnList (void) if ((r_dlights[k].die < vr_data.realtime) || (!r_dlights[k].radius)) continue; - VectorSubtract (r_dlights[k].origin, - currententity->origin, + VectorSubtract (r_dlights[k].origin, origin, lightorigin); R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, @@ -829,7 +831,7 @@ R_RenderView_ (void) R_HighFPPrecision (); } -static void R_RenderViewFishEye (void); +//XXX FIXME static void R_RenderViewFishEye (void); void R_RenderView (void) @@ -849,11 +851,12 @@ R_RenderView (void) if ((intptr_t) (&r_warpbuffer) & 3) Sys_Error ("Globals are missaligned"); - + R_RenderView_ (); +/*XXX FIXME if (!scr_fisheye->int_val) R_RenderView_ (); else - R_RenderViewFishEye (); + R_RenderViewFishEye ();*/ } void @@ -867,7 +870,7 @@ R_InitTurb (void) // AMP2 not 20 } } - +/*XXX FIXME #define BOX_FRONT 0 #define BOX_BEHIND 2 #define BOX_LEFT 3 @@ -1152,7 +1155,7 @@ R_RenderViewFishEye (void) r_refdef.viewangles[PITCH] = pitch; r_refdef.viewangles[ROLL] = roll; renderlookup (offs, scrbufs); -} +}*/ void R_ClearState (void) diff --git a/libs/video/renderer/sw/sw_rmisc.c b/libs/video/renderer/sw/sw_rmisc.c index dee5c780e..2ea74ad4e 100644 --- a/libs/video/renderer/sw/sw_rmisc.c +++ b/libs/video/renderer/sw/sw_rmisc.c @@ -53,6 +53,7 @@ R_CheckVariables (void) void R_TimeRefresh_f (void) { +/* FIXME update for simd int i; float start, stop, time; int startangle; @@ -82,6 +83,7 @@ R_TimeRefresh_f (void) Sys_Printf ("%g seconds (%g fps)\n", time, 128 / time); r_refdef.viewangles[1] = startangle; +*/ } void @@ -237,10 +239,12 @@ R_SetupFrame (void) #endif // build the transformation matrix for the given view angles - VectorCopy (r_refdef.vieworg, modelorg); - VectorCopy (r_refdef.vieworg, r_origin); + VectorCopy (r_refdef.viewposition, modelorg); + VectorCopy (r_refdef.viewposition, r_origin); - AngleVectors (r_refdef.viewangles, vpn, vright, vup); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 1, 0, 0, 0 }), vpn); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, -1, 0, 0 }), vright); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, 0, 1, 0 }), vup); R_SetFrustum (); // current viewleaf diff --git a/libs/video/renderer/sw/sw_rpart.c b/libs/video/renderer/sw/sw_rpart.c index d154ad739..c429279b2 100644 --- a/libs/video/renderer/sw/sw_rpart.c +++ b/libs/video/renderer/sw/sw_rpart.c @@ -37,6 +37,7 @@ #endif #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/mersenne.h" #include "QF/qargs.h" #include "QF/quakefs.h" @@ -386,9 +387,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) if (!r_particles->int_val) return; - org[0] = ent->origin[0]; - org[1] = ent->origin[1]; - org[2] = ent->origin[2]; + VectorCopy (Transform_GetWorldPosition (ent->transform), org); for (i = -16; i < 16; i += 8) { for (j = -16; j < 16; j += 8) { for (k = 0; k < 32; k += 8) { @@ -431,10 +430,13 @@ R_EntityParticles_ID (const entity_t *ent) float beamlength = 16.0, dist = 64.0; particle_t *p; vec3_t forward; + vec3_t org; if (!r_particles->int_val) return; + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + for (i = 0; i < NUMVERTEXNORMALS; i++) { int k; for (k = 0; k < 3; k++) { @@ -470,11 +472,11 @@ R_EntityParticles_ID (const entity_t *ent) p->type = pt_explode; p->phys = R_ParticlePhysics (p->type); - p->org[0] = ent->origin[0] + r_avertexnormals[i][0] * dist + + p->org[0] = org[0] + r_avertexnormals[i][0] * dist + forward[0] * beamlength; - p->org[1] = ent->origin[1] + r_avertexnormals[i][1] * dist + + p->org[1] = org[1] + r_avertexnormals[i][1] * dist + forward[1] * beamlength; - p->org[2] = ent->origin[2] + r_avertexnormals[i][2] * dist + + p->org[2] = org[2] + r_avertexnormals[i][2] * dist + forward[2] * beamlength; } } @@ -486,12 +488,14 @@ R_RocketTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; + VectorCopy (Transform_GetWorldPosition (ent->transform), org); VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -525,12 +529,14 @@ R_GrenadeTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -564,12 +570,14 @@ R_BloodTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -602,12 +610,14 @@ R_SlightBloodTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -639,12 +649,14 @@ R_WizTrail_QF (const entity_t *ent) float len; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -686,12 +698,14 @@ R_FlameTrail_QF (const entity_t *ent) float len; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -734,12 +748,14 @@ R_VoorTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { diff --git a/libs/video/renderer/sw/sw_rsprite.c b/libs/video/renderer/sw/sw_rsprite.c index 8eb4151e7..6a70d2f4f 100644 --- a/libs/video/renderer/sw/sw_rsprite.c +++ b/libs/video/renderer/sw/sw_rsprite.c @@ -286,7 +286,7 @@ R_DrawSprite (void) int i; msprite_t *psprite; vec3_t tvec; - float dot, angle, sr, cr; + float dot, sr, cr; psprite = currententity->renderer.model->cache.data; @@ -371,9 +371,10 @@ R_DrawSprite (void) // generate the sprite's axes, parallel to the viewplane, but rotated // in that plane around the center according to the sprite entity's // roll angle. So vpn stays the same, but vright and vup rotate - angle = currententity->angles[ROLL] * (M_PI * 2 / 360); - sr = sin (angle); - cr = cos (angle); + vec4f_t rot = Transform_GetLocalRotation (currententity->transform); + //FIXME assumes the entity is only rolled + sr = 2 * rot[0] * rot[3]; + cr = rot[3] * rot[3] - rot[0] * rot[0]; for (i = 0; i < 3; i++) { r_spritedesc.vpn[i] = vpn[i]; diff --git a/libs/video/renderer/sw/sw_rsurf.c b/libs/video/renderer/sw/sw_rsurf.c index 1dded8c00..36ea5fe79 100644 --- a/libs/video/renderer/sw/sw_rsurf.c +++ b/libs/video/renderer/sw/sw_rsurf.c @@ -28,6 +28,7 @@ # include "config.h" #endif +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -78,6 +79,7 @@ R_AddDynamicLights (void) int sd, td; float dist, rad, minlight; vec3_t impact, local, lightorigin; + vec4f_t entorigin = { 0, 0, 0, 1 }; int s, t; int i; int smax, tmax; @@ -88,12 +90,16 @@ R_AddDynamicLights (void) tmax = (surf->extents[1] >> 4) + 1; tex = surf->texinfo; + if (currententity->transform) { + //FIXME give world entity a transform + entorigin = Transform_GetWorldPosition (currententity->transform); + } + for (lnum = 0; lnum < r_maxdlights; lnum++) { if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) continue; // not lit by this light - VectorSubtract (r_dlights[lnum].origin, currententity->origin, - lightorigin); + VectorSubtract (r_dlights[lnum].origin, entorigin, lightorigin); rad = r_dlights[lnum].radius; dist = DotProduct (lightorigin, surf->plane->normal) - surf->plane->dist; diff --git a/libs/video/renderer/sw32/d_edge.c b/libs/video/renderer/sw32/d_edge.c index 6fa0b131a..6015eaf23 100644 --- a/libs/video/renderer/sw32/d_edge.c +++ b/libs/video/renderer/sw32/d_edge.c @@ -32,6 +32,7 @@ #include "namehack.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -243,7 +244,8 @@ sw32_D_DrawSurfaces (void) // TODO: store once at start of frame currententity = s->entity; // FIXME: make this passed in // to sw32_R_RotateBmodel () - VectorSubtract (r_origin, currententity->origin, + VectorSubtract (r_origin, + Transform_GetWorldPosition (currententity->transform), local_modelorg); sw32_TransformVector (local_modelorg, transformed_modelorg); @@ -276,7 +278,8 @@ sw32_D_DrawSurfaces (void) // TODO: store once at start of frame currententity = s->entity; // FIXME: make this passed in // to sw32_R_RotateBmodel () - VectorSubtract (r_origin, currententity->origin, + VectorSubtract (r_origin, + Transform_GetWorldPosition (currententity->transform), local_modelorg); sw32_TransformVector (local_modelorg, transformed_modelorg); diff --git a/libs/video/renderer/sw32/sw32_rmain.c b/libs/video/renderer/sw32/sw32_rmain.c index 36d94fd2a..d6dfd7670 100644 --- a/libs/video/renderer/sw32/sw32_rmain.c +++ b/libs/video/renderer/sw32/sw32_rmain.c @@ -369,16 +369,16 @@ R_DrawEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; + VectorCopy (Transform_GetWorldPosition (currententity->transform), + r_entorigin); switch (currententity->renderer.model->type) { case mod_sprite: - VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); sw32_R_DrawSprite (); break; case mod_alias: case mod_iqm: - VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); minlight = max (currententity->renderer.min_light, @@ -391,7 +391,7 @@ R_DrawEntitiesOnList (void) || sw32_R_AliasCheckBBox ()) { // 128 instead of 255 due to clamping below j = max (R_LightPoint (&r_worldentity.renderer.model->brush, - currententity->origin), + r_entorigin), minlight * 128); lighting.ambientlight = j; @@ -401,7 +401,7 @@ R_DrawEntitiesOnList (void) for (lnum = 0; lnum < r_maxdlights; lnum++) { if (r_dlights[lnum].die >= vr_data.realtime) { - VectorSubtract (currententity->origin, + VectorSubtract (r_entorigin, r_dlights[lnum].origin, dist); add = r_dlights[lnum].radius - VectorLength (dist); @@ -450,7 +450,8 @@ R_DrawViewModel (void) if (!currententity->renderer.model) return; - VectorCopy (currententity->origin, r_entorigin); + VectorCopy (Transform_GetWorldPosition (currententity->transform), + r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); VectorCopy (vup, viewlightvec); @@ -460,7 +461,7 @@ R_DrawViewModel (void) currententity->renderer.model->min_light); j = max (R_LightPoint (&r_worldentity.renderer.model->brush, - currententity->origin), minlight * 128); + r_entorigin), minlight * 128); r_viewlighting.ambientlight = j; r_viewlighting.shadelight = j; @@ -475,7 +476,7 @@ R_DrawViewModel (void) if (dl->die < vr_data.realtime) continue; - VectorSubtract (currententity->origin, dl->origin, dist); + VectorSubtract (r_entorigin, dl->origin, dist); add = dl->radius - VectorLength (dist); if (add > 0) r_viewlighting.ambientlight += add; @@ -505,7 +506,7 @@ R_BmodelCheckBBox (model_t *clmodel, float *minmaxs) Transform_GetWorldMatrix (currententity->transform, mat); if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { for (i = 0; i < 4; i++) { - d = DotProduct (currententity->origin, sw32_view_clipplanes[i].normal); + d = DotProduct (mat[3], sw32_view_clipplanes[i].normal); d -= sw32_view_clipplanes[i].dist; if (d <= -clmodel->radius) @@ -553,6 +554,7 @@ R_DrawBEntitiesOnList (void) int j, clipflags; unsigned int k; vec3_t oldorigin; + vec3_t origin; model_t *clmodel; float minmaxs[6]; entity_t *ent; @@ -566,6 +568,8 @@ R_DrawBEntitiesOnList (void) for (ent = r_ent_queue; ent; ent = ent->next) { currententity = ent; + VectorCopy (Transform_GetWorldPosition (currententity->transform), + origin); switch (currententity->renderer.model->type) { case mod_brush: clmodel = currententity->renderer.model; @@ -573,16 +577,15 @@ R_DrawBEntitiesOnList (void) // see if the bounding box lets us trivially reject, also // sets trivial accept status for (j = 0; j < 3; j++) { - minmaxs[j] = currententity->origin[j] + clmodel->mins[j]; - minmaxs[3 + j] = currententity->origin[j] + - clmodel->maxs[j]; + minmaxs[j] = origin[j] + clmodel->mins[j]; + minmaxs[3 + j] = origin[j] + clmodel->maxs[j]; } clipflags = R_BmodelCheckBBox (clmodel, minmaxs); if (clipflags != BMODEL_FULLY_CLIPPED) { mod_brush_t *brush = &clmodel->brush; - VectorCopy (currententity->origin, r_entorigin); + VectorCopy (origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // FIXME: is this needed? @@ -601,8 +604,7 @@ R_DrawBEntitiesOnList (void) if ((r_dlights[k].die < vr_data.realtime) || (!r_dlights[k].radius)) continue; - VectorSubtract (r_dlights[k].origin, - currententity->origin, + VectorSubtract (r_dlights[k].origin, origin, lightorigin); R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, diff --git a/libs/video/renderer/sw32/sw32_rmisc.c b/libs/video/renderer/sw32/sw32_rmisc.c index 753268993..390b13b86 100644 --- a/libs/video/renderer/sw32/sw32_rmisc.c +++ b/libs/video/renderer/sw32/sw32_rmisc.c @@ -55,6 +55,7 @@ R_CheckVariables (void) void sw32_R_TimeRefresh_f (void) { +/* FIXME update for simd int i; float start, stop, time; int startangle; @@ -84,6 +85,7 @@ sw32_R_TimeRefresh_f (void) Sys_Printf ("%g seconds (%g fps)\n", time, 128 / time); r_refdef.viewangles[1] = startangle; +*/ } void @@ -233,10 +235,12 @@ sw32_R_SetupFrame (void) #endif // build the transformation matrix for the given view angles - VectorCopy (r_refdef.vieworg, modelorg); - VectorCopy (r_refdef.vieworg, r_origin); + VectorCopy (r_refdef.viewposition, modelorg); + VectorCopy (r_refdef.viewposition, r_origin); - AngleVectors (r_refdef.viewangles, vpn, vright, vup); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 1, 0, 0, 0 }), vpn); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, -1, 0, 0 }), vright); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, 0, 1, 0 }), vup); R_SetFrustum (); // current viewleaf diff --git a/libs/video/renderer/sw32/sw32_rpart.c b/libs/video/renderer/sw32/sw32_rpart.c index fc640bc8e..851618819 100644 --- a/libs/video/renderer/sw32/sw32_rpart.c +++ b/libs/video/renderer/sw32/sw32_rpart.c @@ -40,6 +40,7 @@ #endif #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/mersenne.h" #include "QF/qargs.h" #include "QF/quakefs.h" @@ -330,9 +331,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) particle_t *p; vec3_t dir, org; - org[0] = ent->origin[0]; - org[1] = ent->origin[1]; - org[2] = ent->origin[2]; + VectorCopy (Transform_GetWorldPosition (ent->transform), org); for (i = -16; i < 16; i += 8) { for (j = -16; j < 16; j += 8) { for (k = 0; k < 32; k += 8) { @@ -376,6 +375,9 @@ R_EntityParticles_ID (const entity_t *ent) float beamlength = 16.0, dist = 64.0; particle_t *p; vec3_t forward; + vec3_t org; + + VectorCopy (Transform_GetWorldPosition (ent->transform), org); for (i = 0; i < NUMVERTEXNORMALS; i++) { int k; @@ -412,11 +414,11 @@ R_EntityParticles_ID (const entity_t *ent) p->type = pt_explode; p->phys = R_ParticlePhysics (p->type); - p->org[0] = ent->origin[0] + r_avertexnormals[i][0] * dist + + p->org[0] = org[0] + r_avertexnormals[i][0] * dist + forward[0] * beamlength; - p->org[1] = ent->origin[1] + r_avertexnormals[i][1] * dist + + p->org[1] = org[1] + r_avertexnormals[i][1] * dist + forward[1] * beamlength; - p->org[2] = ent->origin[2] + r_avertexnormals[i][2] * dist + + p->org[2] = org[2] + r_avertexnormals[i][2] * dist + forward[2] * beamlength; } } @@ -499,12 +501,14 @@ R_RocketTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, ent->old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, ent->old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -538,12 +542,14 @@ R_GrenadeTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -577,12 +583,14 @@ R_BloodTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -615,12 +623,14 @@ R_SlightBloodTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -652,12 +662,14 @@ R_WizTrail_QF (const entity_t *ent) float len; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -699,12 +711,14 @@ R_FlameTrail_QF (const entity_t *ent) float len; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { @@ -747,12 +761,14 @@ R_VoorTrail_QF (const entity_t *ent) int j; particle_t *p; vec3_t old_origin, vec; + vec3_t org; if (!r_particles->int_val) return; VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); + VectorCopy (Transform_GetWorldPosition (ent->transform), org); + VectorSubtract (org, old_origin, vec); len = VectorNormalize (vec); while (len > 0) { diff --git a/libs/video/renderer/sw32/sw32_rsprite.c b/libs/video/renderer/sw32/sw32_rsprite.c index 9c6cb7221..bbdc1996f 100644 --- a/libs/video/renderer/sw32/sw32_rsprite.c +++ b/libs/video/renderer/sw32/sw32_rsprite.c @@ -282,7 +282,7 @@ sw32_R_DrawSprite (void) int i; msprite_t *psprite; vec3_t tvec; - float dot, angle, sr, cr; + float dot, sr, cr; psprite = currententity->renderer.model->cache.data; @@ -367,9 +367,10 @@ sw32_R_DrawSprite (void) // generate the sprite's axes, parallel to the viewplane, but rotated // in that plane around the center according to the sprite entity's // roll angle. So vpn stays the same, but vright and vup rotate - angle = currententity->angles[ROLL] * (M_PI * 2 / 360); - sr = sin (angle); - cr = cos (angle); + vec4f_t rot = Transform_GetLocalRotation (currententity->transform); + //FIXME assumes the entity is only rolled + sr = 2 * rot[0] * rot[3]; + cr = rot[3] * rot[3] - rot[0] * rot[0]; for (i = 0; i < 3; i++) { sw32_r_spritedesc.vpn[i] = vpn[i]; diff --git a/libs/video/renderer/sw32/sw32_rsurf.c b/libs/video/renderer/sw32/sw32_rsurf.c index dfc9c31cc..9eba575a9 100644 --- a/libs/video/renderer/sw32/sw32_rsurf.c +++ b/libs/video/renderer/sw32/sw32_rsurf.c @@ -31,6 +31,7 @@ #define NH_DEFINE #include "namehack.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" @@ -96,6 +97,7 @@ R_AddDynamicLights (void) int sd, td; float dist, rad, minlight; vec3_t impact, local, lightorigin; + vec4f_t entorigin = { 0, 0, 0, 1 }; int s, t; int i; int smax, tmax; @@ -106,12 +108,16 @@ R_AddDynamicLights (void) tmax = (surf->extents[1] >> 4) + 1; tex = surf->texinfo; + if (currententity->transform) { + //FIXME give world entity a transform + entorigin = Transform_GetWorldPosition (currententity->transform); + } + for (lnum = 0; lnum < r_maxdlights; lnum++) { if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) continue; // not lit by this light - VectorSubtract (r_dlights[lnum].origin, currententity->origin, - lightorigin); + VectorSubtract (r_dlights[lnum].origin, entorigin, lightorigin); rad = r_dlights[lnum].radius; dist = DotProduct (lightorigin, surf->plane->normal) - surf->plane->dist; diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index e2db7cc78..7468e4dec 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -44,7 +44,7 @@ main (void) vec3 c = subpassLoad (color).rgb; vec3 n = subpassLoad (normal).rgb; vec3 p = subpassLoad (position).rgb; - vec3 light = vec3 (0); + vec3 light = vec3 (0.8); if (MaxLights > 0) { for (int i = 0; i < lightCount; i++) { diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 38aa57ee9..f1ba6e472 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -610,7 +610,8 @@ R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) plane_t *plane; msurface_t *surf; qboolean rotated; - vec3_t mins, maxs, org; + vec3_t mins, maxs; + vec4f_t org; mod_brush_t *brush; model = e->renderer.model; @@ -621,21 +622,21 @@ R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) { rotated = true; radius = model->radius; - if (R_CullSphere (e->origin, radius)) + if (R_CullSphere (&mat[3][0], radius)) { //FIXME return; + } } else { rotated = false; - VectorAdd (e->origin, model->mins, mins); - VectorAdd (e->origin, model->maxs, maxs); + VectorAdd (mat[3], model->mins, mins); + VectorAdd (mat[3], model->maxs, maxs); if (R_CullBox (mins, maxs)) return; } - VectorSubtract (r_refdef.vieworg, e->origin, org); + org = r_refdef.viewposition - mat[3]; if (rotated) { - vec3_t temp; + vec4f_t temp = org; - VectorCopy (org, temp); org[0] = DotProduct (temp, mat[0]); org[1] = DotProduct (temp, mat[1]); org[2] = DotProduct (temp, mat[2]); @@ -650,7 +651,7 @@ R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) || (!r_dlights[k].radius)) continue; - VectorSubtract (r_dlights[k].origin, e->origin, lightorigin); + VectorSubtract (r_dlights[k].origin, mat[3], lightorigin); R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, brush->nodes + brush->hulls[0].firstclipnode); } diff --git a/libs/video/renderer/vulkan/vulkan_lightmap.c b/libs/video/renderer/vulkan/vulkan_lightmap.c index 97c30c667..3cfbcb7ba 100644 --- a/libs/video/renderer/vulkan/vulkan_lightmap.c +++ b/libs/video/renderer/vulkan/vulkan_lightmap.c @@ -41,6 +41,7 @@ #include #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/render.h" #include "QF/sys.h" #include "QF/Vulkan/qf_bsp.h" @@ -61,6 +62,7 @@ add_dynamic_lights (msurface_t *surf, float *block) int sd, td; float dist, rad, minlight; vec3_t impact, local, lightorigin; + vec4f_t entorigin = { 0, 0, 0, 1 }; int smax, tmax; int s, t; mtexinfo_t *tex; @@ -71,13 +73,18 @@ add_dynamic_lights (msurface_t *surf, float *block) tex = surf->texinfo; plane = surf->plane; + if (currententity->transform) { + //FIXME give world entity a transform + entorigin = Transform_GetWorldPosition (currententity->transform); + } + for (lnum = 0; lnum < r_maxdlights; lnum++) { if (!(surf->dlightbits[lnum / 32] & (1 << (lnum % 32)))) continue; // not lit by this light dlight_t *light = &r_dlights[lnum]; - VectorSubtract (light->origin, currententity->origin, lightorigin); + VectorSubtract (light->origin, entorigin, lightorigin); rad = light->radius; dist = DotProduct (lightorigin, plane->normal) - plane->dist; rad -= fabs (dist); diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index e63ff0b03..a7ed49669 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -66,8 +66,11 @@ setup_frame (vulkan_ctx_t *ctx) R_ClearEnts (); r_framecount++; - VectorCopy (r_refdef.vieworg, r_origin); - AngleVectors (r_refdef.viewangles, vpn, vright, vup); + VectorCopy (r_refdef.viewposition, r_origin); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 1, 0, 0, 0 }), vpn); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, -1, 0, 0 }), vright); + VectorCopy (qvmulf (r_refdef.viewrotation, (vec4f_t) { 0, 0, 1, 0 }), vup); + R_SetFrustum (); r_viewleaf = Mod_PointInLeaf (r_origin, r_worldentity.renderer.model); @@ -76,14 +79,14 @@ setup_frame (vulkan_ctx_t *ctx) static void setup_view (vulkan_ctx_t *ctx) { - mat4_t mat; - float *view = ctx->matrices.view_3d; - static mat4_t z_up = { - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1, + mat4f_t view; + static mat4f_t z_up = { + { 0, 0, -1, 0}, + {-1, 0, 0, 0}, + { 0, 1, 0, 0}, + { 0, 0, 0, 1}, }; + vec4f_t offset = { 0, 0, 0, 1 }; /*x = r_refdef.vrect.x; y = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)); @@ -91,17 +94,12 @@ setup_view (vulkan_ctx_t *ctx) h = r_refdef.vrect.height; qfeglViewport (x, y, w, h);*/ - Mat4Zero (mat); - VectorCopy (vpn, mat + 0); - VectorNegate (vright, mat + 4); // we want vleft - VectorCopy (vup, mat + 8); - mat[15] = 1; - Mat4Transpose (mat, mat);//AngleVectors gives the transpose of what we want - Mat4Mult (z_up, mat, view); - - Mat4Identity (mat); - VectorNegate (r_refdef.vieworg, mat + 12); - Mat4Mult (view, mat, view); + mat4fquat (view, qconjf (r_refdef.viewrotation)); + mmulf (view, z_up, view); + offset = -r_refdef.viewposition; + offset[3] = 1; + view[3] = mvmulf (view, offset); + memcpy (ctx->matrices.view_3d, view, sizeof (view)); } static void diff --git a/nq/include/client.h b/nq/include/client.h index 4af07cd24..5d98e437b 100644 --- a/nq/include/client.h +++ b/nq/include/client.h @@ -38,6 +38,7 @@ #include "QF/render.h" #include "client/entities.h" +#include "client/view.h" #include "game.h" #include "netmain.h" @@ -165,11 +166,9 @@ typedef struct { int frameIndex; vec3_t frameViewAngles[2]; // During demo playback viewangles is lerped // between these - vec3_t viewangles; vec4f_t frameVelocity[2]; // Update by server, used for lean+bob // (0 is newest) - vec4f_t velocity; // Lerped between frameVelocity[0] and [1] - vec3_t punchangle; // Temporary offset + viewstate_t viewstate; // pitch drifting vars float idealpitch; diff --git a/nq/source/cl_chase.c b/nq/source/cl_chase.c index 5d23817cd..6f0c430c6 100644 --- a/nq/source/cl_chase.c +++ b/nq/source/cl_chase.c @@ -41,16 +41,19 @@ #include "QF/mathlib.h" #include "QF/plugin/vid_render.h" +#include "QF/simd/vec4f.h" #include "world.h" #include "nq/include/chase.h" #include "nq/include/client.h" -vec3_t camera_origin = {0,0,0}; -vec3_t camera_angles = {0,0,0}; -vec3_t player_origin = {0,0,0}; -vec3_t player_angles = {0,0,0}; + +vec4f_t camera_origin = {0,0,0,1}; +vec4f_t player_origin = {0,0,0,1}; +vec4f_t player_angles = {0,0,0,1}; + +vec3_t camera_angles = {0,0,0}; vec3_t chase_angles; vec3_t chase_dest; @@ -94,19 +97,17 @@ TraceLine (vec3_t start, vec3_t end, vec3_t impact) void Chase_Update (void) { - float pitch, yaw, fwd; - int i; - usercmd_t cmd; // movement direction - vec3_t forward, up, right, stop, dir; + float pitch, yaw, fwd; + usercmd_t cmd; // movement direction + vec4f_t forward = {}, up = {}, right = {}, stop = {}, dir = {}; // lazy camera, look toward player entity if (chase_active->int_val == 2 || chase_active->int_val == 3) { // control camera angles with key/mouse/joy-look - - camera_angles[PITCH] += cl.viewangles[PITCH] - player_angles[PITCH]; - camera_angles[YAW] += cl.viewangles[YAW] - player_angles[YAW]; - camera_angles[ROLL] += cl.viewangles[ROLL] - player_angles[ROLL]; + vec3_t d; + VectorSubtract (cl.viewstate.angles, player_angles, d); + VectorAdd (camera_angles, d, camera_angles); if (chase_active->int_val == 2) { if (camera_angles[PITCH] < -60) @@ -118,48 +119,48 @@ Chase_Update (void) // move camera, it's not enough to just change the angles because // the angles are automatically changed to look toward the player - if (chase_active->int_val == 3) - VectorCopy (r_data->refdef->vieworg, player_origin); + if (chase_active->int_val == 3) { + player_origin = r_data->refdef->viewposition; + } - AngleVectors (camera_angles, forward, right, up); - VectorScale (forward, chase_back->value, forward); - VectorSubtract (player_origin, forward, camera_origin); + AngleVectors (camera_angles, &forward[0], &right[0], &up[0]); + camera_origin = player_origin - chase_back->value * forward; if (chase_active->int_val == 2) { - VectorCopy (r_data->refdef->vieworg, player_origin); + player_origin = r_data->refdef->viewposition; // don't let camera get too low - if (camera_origin[2] < player_origin[2] + chase_up->value) + if (camera_origin[2] < player_origin[2] + chase_up->value) { camera_origin[2] = player_origin[2] + chase_up->value; + } } // don't let camera get too far from player - VectorSubtract (camera_origin, player_origin, dir); - VectorCopy (dir, forward); - VectorNormalize (forward); + dir = camera_origin - player_origin; + forward = normalf (dir); - if (VectorLength (dir) > chase_back->value) { - VectorScale (forward, chase_back->value, dir); - VectorAdd (player_origin, dir, camera_origin); + if (magnitudef (dir)[0] > chase_back->value) { + camera_origin = player_origin + forward * chase_back->value; } // check for walls between player and camera - VectorScale (forward, 8, forward); - VectorAdd (camera_origin, forward, camera_origin); - TraceLine (player_origin, camera_origin, stop); - if (VectorLength (stop) != 0) - VectorSubtract (stop, forward, camera_origin); + camera_origin += 8 * forward; + //FIXME + TraceLine (&player_origin[0], &camera_origin[0], &stop[0]); + stop[3] = 1; + if (magnitude3f (stop)[0] != 0) { + camera_origin = stop - forward; + } - VectorSubtract (camera_origin, r_data->refdef->vieworg, dir); - VectorCopy (dir, forward); - VectorNormalize (forward); + dir = camera_origin - r_data->refdef->viewposition; + forward = normalf (dir); if (chase_active->int_val == 2) { if (dir[1] == 0 && dir[0] == 0) { // look straight up or down -// camera_angles[YAW] = r_data->refdef->viewangles[YAW]; +// camera_angles[YAW] = r_data->refdef->viewstate.angles[YAW]; if (dir[2] > 0) camera_angles[PITCH] = 90; else @@ -182,13 +183,13 @@ Chase_Update (void) } } - VectorCopy (camera_angles, r_data->refdef->viewangles);// rotate camera - VectorCopy (camera_origin, r_data->refdef->vieworg); // move camera + AngleQuat (camera_angles, &r_data->refdef->viewrotation[0]);//FIXME rotate camera + r_data->refdef->viewposition = camera_origin; // move camera // get basic movement from keyboard memset (&cmd, 0, sizeof (cmd)); -// VectorCopy (cl.viewangles, cmd.angles); +// VectorCopy (cl.viewstate.angles, cmd.angles); if (in_strafe.state & 1) { cmd.sidemove += cl_sidespeed->value * CL_KeyState (&in_right); @@ -208,54 +209,54 @@ Chase_Update (void) } // mouse and joystick controllers add to movement - VectorSet (0, cl.viewangles[1] - camera_angles[1], 0, dir); - AngleVectors (dir, forward, right, up); - VectorScale (forward, viewdelta.position[2] * m_forward->value, - forward); - VectorScale (right, viewdelta.position[0] * m_side->value, right); - VectorAdd (forward, right, dir); + VectorSet (0, cl.viewstate.angles[1] - camera_angles[1], 0, dir); + AngleVectors (&dir[0], &forward[0], &right[0], &up[0]); //FIXME + forward *= viewdelta.position[2] * m_forward->value; + right *= viewdelta.position[0] * m_side->value; + dir = forward + right; cmd.forwardmove += dir[0]; cmd.sidemove -= dir[1]; VectorSet (0, camera_angles[1], 0, dir); - AngleVectors (dir, forward, right, up); + AngleVectors (&dir[0], &forward[0], &right[0], &up[0]); //FIXME VectorScale (forward, cmd.forwardmove, forward); VectorScale (right, cmd.sidemove, right); VectorAdd (forward, right, dir); if (dir[1] || dir[0]) { - cl.viewangles[YAW] = (atan2 (dir[1], dir[0]) * 180 / M_PI); - if (cl.viewangles[YAW] < 0) cl.viewangles[YAW] += 360; -// if (cl.viewangles[YAW] < 180) -// cl.viewangles[YAW] += 180; -// else -// cl.viewangles[YAW] -= 180; + cl.viewstate.angles[YAW] = (atan2 (dir[1], dir[0]) * 180 / M_PI); + if (cl.viewstate.angles[YAW] < 0) { + cl.viewstate.angles[YAW] += 360; + } } - cl.viewangles[PITCH] = 0; + cl.viewstate.angles[PITCH] = 0; // remember the new angle to calculate the difference next frame - VectorCopy (cl.viewangles, player_angles); + VectorCopy (cl.viewstate.angles, player_angles); return; } // regular camera, faces same direction as player - AngleVectors (cl.viewangles, forward, right, up); + //FIXME + AngleVectors (cl.viewstate.angles, &forward[0], &right[0], &up[0]); // calc exact destination - for (i = 0; i < 3; i++) - camera_origin[i] = r_data->refdef->vieworg[i] - - forward[i] * chase_back->value - right[i] * chase_right->value; + camera_origin = r_data->refdef->viewposition + - forward * chase_back->value - right * chase_right->value; + // chase_up is world up camera_origin[2] += chase_up->value; // check for walls between player and camera - TraceLine (r_data->refdef->vieworg, camera_origin, stop); - if (VectorLength (stop) != 0) - for (i = 0; i < 3; i++) - camera_origin[i] = stop[i] + forward[i] * 8; + //FIXME + TraceLine (&r_data->refdef->viewposition[0], &camera_origin[0], &stop[0]); + stop[3] = 1; + if (magnitude3f (stop)[0] != 0) { + camera_origin = stop + forward * 8; + } - VectorCopy (camera_origin, r_data->refdef->vieworg); + r_data->refdef->viewposition = camera_origin; } diff --git a/nq/source/cl_demo.c b/nq/source/cl_demo.c index 39cdf9d24..03950998a 100644 --- a/nq/source/cl_demo.c +++ b/nq/source/cl_demo.c @@ -105,7 +105,7 @@ CL_WriteDemoMessage (sizebuf_t *msg) len = LittleLong (msg->cursize); Qwrite (cls.demofile, &len, 4); for (i = 0; i < 3; i++) { - f = LittleFloat (cl.viewangles[i]); + f = LittleFloat (cl.viewstate.angles[i]); Qwrite (cls.demofile, &f, 4); } Qwrite (cls.demofile, msg->data, msg->cursize); diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index e8aecb26c..2e04ff885 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -144,10 +144,9 @@ CL_RelinkEntities (void) entity_state_t *new, *old; renderer_t *renderer; animation_t *animation; - float bobjrotate, frac, f, d; + float bobjrotate, frac, f; int i, j; int entvalid; - vec3_t delta; int model_flags; r_data->player_entity = &cl_entities[cl.viewentity]; @@ -156,19 +155,21 @@ CL_RelinkEntities (void) frac = CL_LerpPoint (); // interpolate player info - cl.velocity = cl.frameVelocity[1] + cl.viewstate.velocity = cl.frameVelocity[1] + frac * (cl.frameVelocity[0] - cl.frameVelocity[1]); if (cls.demoplayback) { // interpolate the angles + vec3_t d; + VectorSubtract (cl.frameViewAngles[0], cl.frameViewAngles[1], d); for (j = 0; j < 3; j++) { - d = cl.frameViewAngles[0][j] - cl.frameViewAngles[1][j]; - if (d > 180) - d -= 360; - else if (d < -180) - d += 360; - cl.viewangles[j] = cl.frameViewAngles[1][j] + frac * d; + if (d[j] > 180) { + d[j] -= 360; + } else if (d[j] < -180) { + d[j] += 360; + } } + VectorMultAdd (cl.frameViewAngles[1], frac, d, cl.viewstate.angles); } bobjrotate = anglemod (100 * cl.time); @@ -184,8 +185,8 @@ CL_RelinkEntities (void) // if the object wasn't included in the last packet, remove it entvalid = cl_msgtime[i] == cl.mtime[0]; if (entvalid && !new->modelindex) { - VectorCopy (new->origin, ent->origin); - VectorCopy (new->angles, ent->angles); + CL_TransformEntity (ent, new->scale / 16.0, new->angles, + new->origin); entvalid = 0; } if (!entvalid) { @@ -220,7 +221,6 @@ CL_RelinkEntities (void) cl.scores[i - 1].bottomcolor); } } - ent->scale = new->scale / 16.0; VectorCopy (ent_colormod[new->colormod], renderer->colormod); renderer->colormod[3] = ENTALPHA_DECODE (new->alpha); @@ -234,32 +234,30 @@ CL_RelinkEntities (void) // The entity was not updated in the last message so move to the // final spot animation->pose1 = animation->pose2 = -1; - VectorCopy (new->origin, ent->origin); - if (!(model_flags & EF_ROTATE)) - CL_TransformEntity (ent, new->angles); + CL_TransformEntity (ent, new->scale / 16.0, new->angles, + new->origin); if (i != cl.viewentity || chase_active->int_val) { if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); } r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } - VectorCopy (ent->origin, ent->old_origin); + ent->old_origin = new->origin; } else { + vec4f_t delta = new->origin - old->origin; f = frac; - VectorCopy (ent->origin, ent->old_origin); - VectorSubtract (new->origin, old->origin, delta); + ent->old_origin = Transform_GetWorldPosition (ent->transform); // If the delta is large, assume a teleport and don't lerp if (fabs (delta[0]) > 100 || fabs (delta[1] > 100) || fabs (delta[2]) > 100) { // assume a teleportation, not a motion - VectorCopy (new->origin, ent->origin); - if (!(model_flags & EF_ROTATE)) - CL_TransformEntity (ent, new->angles); + CL_TransformEntity (ent, new->scale / 16.0, new->angles, + new->origin); animation->pose1 = animation->pose2 = -1; } else { - vec3_t angles, d; // interpolate the origin and angles - VectorMultAdd (old->origin, f, delta, ent->origin); + vec3_t angles, d; + vec4f_t origin = old->origin + f * delta; if (!(model_flags & EF_ROTATE)) { VectorSubtract (new->angles, old->angles, d); for (j = 0; j < 3; j++) { @@ -269,12 +267,14 @@ CL_RelinkEntities (void) d[j] += 360; } VectorMultAdd (old->angles, f, d, angles); - CL_TransformEntity (ent, angles); } + CL_TransformEntity (ent, new->scale / 16.0, angles, origin); } if (i != cl.viewentity || chase_active->int_val) { if (ent->visibility.efrag) { - if (!VectorCompare (ent->origin, ent->old_origin)) { + vec4f_t org + = Transform_GetWorldPosition (ent->transform); + if (!VectorCompare (org, ent->old_origin)) {//FIXME r_funcs->R_RemoveEfrags (ent); r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } @@ -289,17 +289,20 @@ CL_RelinkEntities (void) vec3_t angles; VectorCopy (new->angles, angles); angles[YAW] = bobjrotate; - CL_TransformEntity (ent, angles); + CL_TransformEntity (ent, new->scale / 16.0, angles, new->origin); } CL_EntityEffects (i, ent, new, cl.time); - vec4f_t org = { VectorExpand (ent->origin), 1}; //FIXME + vec4f_t org = Transform_GetWorldPosition (ent->transform); CL_NewDlight (i, org, new->effects, new->glow_size, new->glow_color, cl.time); - if (VectorDistance_fast (old->origin, ent->origin) > (256 * 256)) - VectorCopy (ent->origin, old->origin); + if (VectorDistance_fast (old->origin, org) > (256 * 256)) { + old->origin = org; + } if (model_flags & ~EF_ROTATE) CL_ModelEffects (ent, i, new->glow_color, cl.time); cl_forcelink[i] = false; } + cl.viewstate.origin + = Transform_GetWorldPosition (cl_entities[cl.viewentity].transform); } diff --git a/nq/source/cl_input.c b/nq/source/cl_input.c index dd980e814..291f0ecac 100644 --- a/nq/source/cl_input.c +++ b/nq/source/cl_input.c @@ -438,35 +438,35 @@ CL_AdjustAngles (void) yawspeed *= host_frametime; if (!(in_strafe.state & 1)) { - cl.viewangles[YAW] -= yawspeed * CL_KeyState (&in_right); - cl.viewangles[YAW] += yawspeed * CL_KeyState (&in_left); - cl.viewangles[YAW] = anglemod (cl.viewangles[YAW]); + cl.viewstate.angles[YAW] -= yawspeed * CL_KeyState (&in_right); + cl.viewstate.angles[YAW] += yawspeed * CL_KeyState (&in_left); + cl.viewstate.angles[YAW] = anglemod (cl.viewstate.angles[YAW]); } if (in_klook.state & 1) { V_StopPitchDrift (); - cl.viewangles[PITCH] -= pitchspeed * CL_KeyState (&in_forward); - cl.viewangles[PITCH] += pitchspeed * CL_KeyState (&in_back); + cl.viewstate.angles[PITCH] -= pitchspeed * CL_KeyState (&in_forward); + cl.viewstate.angles[PITCH] += pitchspeed * CL_KeyState (&in_back); } up = CL_KeyState (&in_lookup); down = CL_KeyState (&in_lookdown); - cl.viewangles[PITCH] -= pitchspeed * up; - cl.viewangles[PITCH] += pitchspeed * down; + cl.viewstate.angles[PITCH] -= pitchspeed * up; + cl.viewstate.angles[PITCH] += pitchspeed * down; if (up || down) V_StopPitchDrift (); // FIXME: Need to clean up view angle limits - if (cl.viewangles[PITCH] > 80) - cl.viewangles[PITCH] = 80; - if (cl.viewangles[PITCH] < -70) - cl.viewangles[PITCH] = -70; + if (cl.viewstate.angles[PITCH] > 80) + cl.viewstate.angles[PITCH] = 80; + if (cl.viewstate.angles[PITCH] < -70) + cl.viewstate.angles[PITCH] = -70; - if (cl.viewangles[ROLL] > 50) - cl.viewangles[ROLL] = 50; - if (cl.viewangles[ROLL] < -50) - cl.viewangles[ROLL] = -50; + if (cl.viewstate.angles[ROLL] > 50) + cl.viewstate.angles[ROLL] = 50; + if (cl.viewstate.angles[ROLL] < -50) + cl.viewstate.angles[ROLL] = -50; } /* @@ -516,12 +516,13 @@ CL_BaseMove (usercmd_t *cmd) IN_Move (); // adjust for chase camera angles + /*FIXME:chase figure out just what this does and get it working if (cl.chase && (chase_active->int_val == 2 || chase_active->int_val == 3)) { vec3_t forward, right, up, f, r; vec3_t dir = {0, 0, 0}; - dir[1] = r_data->refdef->viewangles[1] - cl.viewangles[1]; + dir[1] = r_data->refdef->viewangles[1] - cl.viewstate.angles[1]; AngleVectors (dir, forward, right, up); VectorScale (forward, cmd->forwardmove, f); VectorScale (right, cmd->sidemove, r); @@ -532,16 +533,18 @@ CL_BaseMove (usercmd_t *cmd) viewdelta.position[2] = f[0] + r[0]; viewdelta.position[0] = (f[1] + r[1]) * -1; } + */ cmd->forwardmove += viewdelta.position[2] * m_forward->value; cmd->sidemove += viewdelta.position[0] * m_side->value; cmd->upmove += viewdelta.position[1]; - cl.viewangles[PITCH] += viewdelta.angles[PITCH] * m_pitch->value; - cl.viewangles[YAW] += viewdelta.angles[YAW] * m_yaw->value; - cl.viewangles[ROLL] += viewdelta.angles[ROLL]; + cl.viewstate.angles[PITCH] += viewdelta.angles[PITCH] * m_pitch->value; + cl.viewstate.angles[YAW] += viewdelta.angles[YAW] * m_yaw->value; + cl.viewstate.angles[ROLL] += viewdelta.angles[ROLL]; if (freelook && !(in_strafe.state & 1)) { - cl.viewangles[PITCH] = bound (-70, cl.viewangles[PITCH], 80); + cl.viewstate.angles[PITCH] + = bound (-70, cl.viewstate.angles[PITCH], 80); } } @@ -564,7 +567,7 @@ CL_SendMove (usercmd_t *cmd) MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times - write_angles (&buf, cl.viewangles); + write_angles (&buf, cl.viewstate.angles); MSG_WriteShort (&buf, cmd->forwardmove); MSG_WriteShort (&buf, cmd->sidemove); diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index e2c222713..e52eb5fea 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -34,6 +34,7 @@ #include "QF/console.h" #include "QF/cvar.h" #include "QF/draw.h" +#include "QF/entity.h" #include "QF/input.h" #include "QF/joystick.h" #include "QF/keys.h" @@ -52,7 +53,6 @@ #include "sbar.h" #include "client/temp_entities.h" -#include "client/view.h" #include "nq/include/chase.h" #include "nq/include/cl_skin.h" @@ -409,10 +409,11 @@ CL_PrintEntities_f (void) Sys_Printf ("EMPTY\n"); continue; } - Sys_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n", + vec4f_t org = Transform_GetWorldPosition (ent->transform); + vec4f_t rot = Transform_GetWorldRotation (ent->transform); + Sys_Printf ("%s:%2i "VEC4F_FMT" "VEC4F_FMT"\n", ent->renderer.model->path, ent->animation.frame, - VectorExpand (ent->origin), - VectorExpand (ent->angles)); + VEC4_EXP (org), VEC4_EXP (rot)); } } @@ -426,12 +427,13 @@ CL_ReadFromServer (void) { int ret; TEntContext_t tentCtx = { - {VectorExpand (cl_entities[cl.viewentity].origin), 1}, + Transform_GetWorldPosition (cl_entities[cl.viewentity].transform), cl.worldmodel, cl.viewentity }; cl.oldtime = cl.time; cl.time += host_frametime; + cl.viewstate.frametime = host_frametime; do { ret = CL_GetMessage (); @@ -535,7 +537,7 @@ CL_SetState (cactive_t state) static void Force_CenterView_f (void) { - cl.viewangles[PITCH] = 0; + cl.viewstate.angles[PITCH] = 0; } void diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index ccf535e18..e74a65976 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -41,6 +41,7 @@ #include "QF/console.h" #include "QF/cvar.h" #include "QF/dstring.h" +#include "QF/entity.h" #include "QF/idparse.h" #include "QF/input.h" #include "QF/msg.h" @@ -661,17 +662,18 @@ CL_ParseClientdata (void) cl.idealpitch = 0; cl.frameVelocity[1] = cl.frameVelocity[0]; + vec3_t punchangle = { }; for (i = 0; i < 3; i++) { - if (bits & (SU_PUNCH1 << i)) - cl.punchangle[i] = ((signed char) MSG_ReadByte (net_message)); - else - cl.punchangle[i] = 0; + if (bits & (SU_PUNCH1 << i)) { + punchangle[i] = ((signed char) MSG_ReadByte (net_message)); + } if (bits & (SU_VELOCITY1 << i)) cl.frameVelocity[0][i] = ((signed char) MSG_ReadByte (net_message)) * 16; else cl.frameVelocity[0][i] = 0; } + AngleQuat (punchangle, &cl.viewstate.punchangle[0]);//FIXME //FIXME //if (!VectorCompare (v_punchangles[0], cl.punchangle[0])) { @@ -794,9 +796,9 @@ CL_ParseStatic (int version) ent->renderer.skinnum = baseline.skinnum; VectorCopy (ent_colormod[baseline.colormod], ent->renderer.colormod); ent->renderer.colormod[3] = ENTALPHA_DECODE (baseline.alpha); - ent->scale = baseline.scale / 16.0; - VectorCopy (baseline.origin, ent->origin); - CL_TransformEntity (ent, baseline.angles); + + CL_TransformEntity (ent, baseline.scale / 16.0, baseline.angles, + baseline.origin); r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } @@ -839,7 +841,7 @@ CL_ParseServerMessage (void) signon_t so; TEntContext_t tentCtx = { - {VectorExpand (cl_entities[cl.viewentity].origin), 1}, + Transform_GetWorldPosition (cl_entities[cl.viewentity].transform), cl.worldmodel, cl.viewentity }; @@ -948,7 +950,7 @@ CL_ParseServerMessage (void) case svc_setangle: { - vec_t *dest = cl.viewangles; + vec_t *dest = cl.viewstate.angles; MSG_ReadAngleV (net_message, dest); break; diff --git a/nq/source/cl_screen.c b/nq/source/cl_screen.c index 509352a1c..78d231953 100644 --- a/nq/source/cl_screen.c +++ b/nq/source/cl_screen.c @@ -86,7 +86,9 @@ SCR_CShift (void) int contents = CONTENTS_EMPTY; if (cls.state == ca_active && cl.worldmodel) { - leaf = Mod_PointInLeaf (r_data->refdef->vieworg, cl.worldmodel); + //FIXME + leaf = Mod_PointInLeaf (&r_data->refdef->viewposition[0], + cl.worldmodel); contents = leaf->contents; } V_SetContentsColor (contents); diff --git a/nq/source/cl_view.c b/nq/source/cl_view.c index 1ccf06d98..f5ba3de8f 100644 --- a/nq/source/cl_view.c +++ b/nq/source/cl_view.c @@ -30,6 +30,7 @@ #include "QF/cmd.h" #include "QF/cvar.h" +#include "QF/entity.h" #include "QF/msg.h" #include "QF/screen.h" @@ -39,8 +40,6 @@ #include "compat.h" -#include "client/view.h" - #include "nq/include/chase.h" #include "nq/include/client.h" #include "nq/include/host.h" @@ -81,6 +80,10 @@ cvar_t *v_idlescale; float v_dmg_time, v_dmg_roll, v_dmg_pitch; +vec4f_t v_idle_yaw; +vec4f_t v_idle_roll; +vec4f_t v_idle_pitch; + cshift_t cshift_empty = { {130, 80, 50}, 0}; cshift_t cshift_water = { {130, 80, 50}, 128}; cshift_t cshift_slime = { {0, 25, 5}, 150}; @@ -113,7 +116,7 @@ V_CalcRoll (const vec3_t angles, vec4f_t velocity) static float V_CalcBob (void) { - vec4f_t velocity = cl.velocity; + vec4f_t velocity = cl.viewstate.velocity; float cycle; static double bobtime; static float bob; @@ -124,7 +127,7 @@ V_CalcBob (void) if (cl.onground == -1) return bob; // just use old value - bobtime += host_frametime; + bobtime += cl.viewstate.frametime; cycle = bobtime - (int) (bobtime / cl_bobcycle->value) * cl_bobcycle->value; cycle /= cl_bobcycle->value; @@ -183,9 +186,9 @@ static void V_DriftPitch (void) { float delta, move; - usercmd_t *cmd = &cl.cmd; + float forwardmove = cl.viewstate.movecmd[0]; - if (noclip_anglehack || cl.onground == -1 || cls.demoplayback) { + if (noclip_anglehack || cl.viewstate.onground == -1 || cls.demoplayback) { cl.driftmove = 0; cl.pitchvel = 0; return; @@ -193,10 +196,10 @@ V_DriftPitch (void) // don't count small mouse motion if (cl.nodrift) { - if (fabs (cmd->forwardmove) < cl_forwardspeed->value) + if (fabs (forwardmove) < cl_forwardspeed->value) cl.driftmove = 0; else - cl.driftmove += host_frametime; + cl.driftmove += cl.viewstate.frametime; if (cl.driftmove > v_centermove->value) { V_StartPitchDrift (); @@ -204,28 +207,28 @@ V_DriftPitch (void) return; } - delta = cl.idealpitch - cl.viewangles[PITCH]; + delta = cl.idealpitch - cl.viewstate.angles[PITCH]; if (!delta) { cl.pitchvel = 0; return; } - move = host_frametime * cl.pitchvel; - cl.pitchvel += host_frametime * v_centerspeed->value; + move = cl.viewstate.frametime * cl.pitchvel; + cl.pitchvel += cl.viewstate.frametime * v_centerspeed->value; if (delta > 0) { if (move > delta) { cl.pitchvel = 0; move = delta; } - cl.viewangles[PITCH] += move; + cl.viewstate.angles[PITCH] += move; } else if (delta < 0) { if (move > -delta) { cl.pitchvel = 0; move = -delta; } - cl.viewangles[PITCH] -= move; + cl.viewstate.angles[PITCH] -= move; } } @@ -234,11 +237,10 @@ V_DriftPitch (void) void V_ParseDamage (void) { - entity_t *ent = &cl_entities[cl.viewentity]; float count, side; int armor, blood; - vec_t *origin = ent->origin; - vec_t *angles = ent->angles; + vec4f_t origin = cl.viewstate.origin; + vec_t *angles = cl.viewstate.angles; vec3_t from, forward, right, up; armor = MSG_ReadByte (net_message); @@ -482,74 +484,41 @@ V_PrepBlend (void) /* VIEW RENDERING */ -static float -angledelta (float a) -{ - a = anglemod (a); - if (a > 180) - a -= 360; - return a; -} - static void CalcGunAngle (void) { - float yaw, pitch, move; - static float oldpitch = 0, oldyaw = 0; - - yaw = r_data->refdef->viewangles[YAW]; - pitch = -r_data->refdef->viewangles[PITCH]; - - yaw = angledelta (yaw - r_data->refdef->viewangles[YAW]) * 0.4; - yaw = bound (-10, yaw, 10); - pitch = angledelta (-pitch - r_data->refdef->viewangles[PITCH]) * 0.4; - pitch = bound (-10, pitch, 10); - - move = host_frametime * 20; - if (yaw > oldyaw) { - if (oldyaw + move < yaw) - yaw = oldyaw + move; - } else { - if (oldyaw - move > yaw) - yaw = oldyaw - move; - } - - if (pitch > oldpitch) { - if (oldpitch + move < pitch) - pitch = oldpitch + move; - } else { - if (oldpitch - move > pitch) - pitch = oldpitch - move; - } - - oldyaw = yaw; - oldpitch = pitch; - - cl.viewent.angles[YAW] = r_data->refdef->viewangles[YAW] + yaw; - cl.viewent.angles[PITCH] = -(r_data->refdef->viewangles[PITCH] + pitch); + vec4f_t rotation = r_data->refdef->viewrotation; + //FIXME make child of camera + Transform_SetWorldRotation (cl.viewent.transform, rotation); } static void V_BoundOffsets (void) { - entity_t *ent = &cl_entities[cl.viewentity]; - vec_t *origin = ent->origin; + vec4f_t offset = r_data->refdef->viewposition + - cl.viewstate.origin; // absolutely bound refresh reletive to entity clipping hull // so the view can never be inside a solid wall - if (r_data->refdef->vieworg[0] < origin[0] - 14) - r_data->refdef->vieworg[0] = origin[0] - 14; - else if (r_data->refdef->vieworg[0] > origin[0] + 14) - r_data->refdef->vieworg[0] = origin[0] + 14; - if (r_data->refdef->vieworg[1] < origin[1] - 14) - r_data->refdef->vieworg[1] = origin[1] - 14; - else if (r_data->refdef->vieworg[1] > origin[1] + 14) - r_data->refdef->vieworg[1] = origin[1] + 14; - if (r_data->refdef->vieworg[2] < origin[2] - 22) - r_data->refdef->vieworg[2] = origin[2] - 22; - else if (r_data->refdef->vieworg[2] > origin[2] + 30) - r_data->refdef->vieworg[2] = origin[2] + 30; + offset[0] = bound (-14, offset[0], 14); + offset[1] = bound (-14, offset[1], 14); + offset[2] = bound (-22, offset[2], 30); + r_data->refdef->viewposition = cl.viewstate.origin + offset; +} + +static vec4f_t +idle_quat (vec4f_t axis, cvar_t *cycle, cvar_t *level) +{ + vec4f_t identity = { 0, 0, 0, 1 }; + if (!level || !cycle) { + return identity; + } + float scale = sin (cl.time * cycle->value); + float ang = scale * level->value * v_idlescale->value; + float c = cos (ang); + float s = sin (ang); + return axis * s + identity * c; } /* @@ -560,19 +529,21 @@ V_BoundOffsets (void) static void V_AddIdle (void) { - r_data->refdef->viewangles[ROLL] += v_idlescale->value * - sin (cl.time * v_iroll_cycle->value) * v_iroll_level->value; - r_data->refdef->viewangles[PITCH] += v_idlescale->value * - sin (cl.time * v_ipitch_cycle->value) * v_ipitch_level->value; - r_data->refdef->viewangles[YAW] += v_idlescale->value * - sin (cl.time * v_iyaw_cycle->value) * v_iyaw_level->value; + vec4f_t roll = idle_quat ((vec4f_t) { 1, 0, 0, 0}, + v_iroll_cycle, v_iroll_level); + vec4f_t pitch = idle_quat ((vec4f_t) { 0, 1, 0, 0}, + v_ipitch_cycle, v_ipitch_level); + vec4f_t yaw = idle_quat ((vec4f_t) { 0, 0, 1, 0}, + v_iyaw_cycle, v_iyaw_level); + vec4f_t rot = normalf (qmulf (yaw, qmulf (pitch, roll))); - cl.viewent.angles[ROLL] -= v_idlescale->value * - sin (cl.time * v_iroll_cycle->value) * v_iroll_level->value; - cl.viewent.angles[PITCH] -= v_idlescale->value * - sin (cl.time * v_ipitch_cycle->value) * v_ipitch_level->value; - cl.viewent.angles[YAW] -= v_idlescale->value * - sin (cl.time * v_iyaw_cycle->value) * v_iyaw_level->value; + // rotate the view + r_data->refdef->viewrotation = qmulf (rot, r_data->refdef->viewrotation); + + // counter-rotate the weapon + rot = qmulf (qconjf (rot), + Transform_GetWorldRotation (cl.viewent.transform)); + Transform_SetWorldRotation (cl.viewent.transform, rot); } /* @@ -583,40 +554,38 @@ V_AddIdle (void) static void V_CalcViewRoll (void) { - float side; - vec_t *angles = cl_entities[cl.viewentity].angles; - vec4f_t velocity = cl.velocity; + vec_t *angles = cl.viewstate.angles; + vec4f_t velocity = cl.viewstate.velocity; + vec3_t ang = { }; - side = V_CalcRoll (angles, velocity); - r_data->refdef->viewangles[ROLL] += side; + ang[ROLL] = V_CalcRoll (angles, velocity); if (v_dmg_time > 0) { - r_data->refdef->viewangles[ROLL] += - v_dmg_time / v_kicktime->value * v_dmg_roll; - r_data->refdef->viewangles[PITCH] += - v_dmg_time / v_kicktime->value * v_dmg_pitch; - v_dmg_time -= host_frametime; + ang[ROLL] += v_dmg_time / v_kicktime->value * v_dmg_roll; + ang[PITCH] += v_dmg_time / v_kicktime->value * v_dmg_pitch; + v_dmg_time -= cl.viewstate.frametime; } - if (cl.stats[STAT_HEALTH] <= 0) - r_data->refdef->viewangles[ROLL] = 80; // dead view angle + if (cl.viewstate.flags & VF_DEAD) { // VF_GIB will also set VF_DEAD + ang[ROLL] = 80; // dead view angle + } + + vec4f_t rot; + AngleQuat (ang, &rot[0]);//FIXME + r_data->refdef->viewrotation = qmulf (r_data->refdef->viewrotation, rot); } static void V_CalcIntermissionRefdef (void) { - // ent is the player model (visible when out of body) - entity_t *ent = &cl_entities[cl.viewentity]; entity_t *view; float old; - vec_t *origin = ent->origin; - vec_t *angles = ent->angles; // view is the weapon model (visible only from inside body) view = &cl.viewent; - VectorCopy (origin, r_data->refdef->vieworg); - VectorCopy (angles, r_data->refdef->viewangles); + r_data->refdef->viewposition = cl.viewstate.origin; + AngleQuat (cl.viewstate.angles, &r_data->refdef->viewrotation[0]);//FIXME view->renderer.model = NULL; // always idle in intermission @@ -629,109 +598,98 @@ V_CalcIntermissionRefdef (void) static void V_CalcRefdef (void) { - // ent is the player model (visible when out of body) - entity_t *ent = &cl_entities[cl.viewentity]; // view is the weapon model (visible only from inside body) entity_t *view = &cl.viewent; float bob; static float oldz = 0; - int i; - vec3_t forward, right, up; - vec_t *origin = ent->origin; - vec_t *viewangles = cl.viewangles; + vec4f_t forward = {}, right = {}, up = {}; + vec4f_t origin = cl.viewstate.origin; + vec_t *viewangles = cl.viewstate.angles; V_DriftPitch (); bob = V_CalcBob (); // refresh position - VectorCopy (origin, r_data->refdef->vieworg); - r_data->refdef->vieworg[2] += cl.viewheight + bob; + r_data->refdef->viewposition = origin; + r_data->refdef->viewposition[2] += cl.viewheight + bob; // never let it sit exactly on a node line, because a water plane can // disappear when viewed with the eye exactly on it. // server protocol specifies to only 1/8 pixel, so add 1/16 in each axis - r_data->refdef->vieworg[0] += 1.0 / 16; - r_data->refdef->vieworg[1] += 1.0 / 16; - r_data->refdef->vieworg[2] += 1.0 / 16; + r_data->refdef->viewposition += (vec4f_t) { 1.0/16, 1.0/16, 1.0/16, 0}; - VectorCopy (viewangles, r_data->refdef->viewangles); + AngleQuat (cl.viewstate.angles, &r_data->refdef->viewrotation[0]);//FIXME V_CalcViewRoll (); V_AddIdle (); // offsets - AngleVectors (viewangles, forward, right, up); + //FIXME semi-duplicates AngleQuat (also, vec3_t vs vec4f_t) + AngleVectors (viewangles, &forward[0], &right[0], &up[0]); // don't allow cheats in multiplayer // FIXME check for dead if (cl.maxclients == 1) { - for (i = 0; i < 3; i++) { - r_data->refdef->vieworg[i] += scr_ofsx->value * forward[i] + - scr_ofsy->value * right[i] + - scr_ofsz->value * up[i]; - } + r_data->refdef->viewposition += scr_ofsx->value * forward + + scr_ofsy->value * right + + scr_ofsz->value * up; } V_BoundOffsets (); // set up gun position - VectorCopy (viewangles, view->angles); - CalcGunAngle (); - VectorCopy (origin, view->origin); - view->origin[2] += cl.viewheight; - - for (i = 0; i < 3; i++) { - view->origin[i] += forward[i] * bob * 0.4; -// view->origin[i] += right[i] * bob * 0.4; -// view->origin[i] += up[i] * bob * 0.8; - } - view->origin[2] += bob; + origin += (vec4f_t) { 0, 0, cl.viewheight, 0 }; + origin += forward * bob * 0.4f + (vec4f_t) { 0, 0, bob, 0 }; // fudge position around to keep amount of weapon visible // roughly equal with different FOV - if (hud_sbar->int_val == 0 && r_data->scr_viewsize->int_val >= 100) + if (hud_sbar->int_val == 0 && r_data->scr_viewsize->int_val >= 100) { ; - else if (r_data->scr_viewsize->int_val == 110) - view->origin[2] += 1; - else if (r_data->scr_viewsize->int_val == 100) - view->origin[2] += 2; - else if (r_data->scr_viewsize->int_val == 90) - view->origin[2] += 1; - else if (r_data->scr_viewsize->int_val == 80) - view->origin[2] += 0.5; + } else if (r_data->scr_viewsize->int_val == 110) { + origin += (vec4f_t) { 0, 0, 1, 0}; + } else if (r_data->scr_viewsize->int_val == 100) { + origin += (vec4f_t) { 0, 0, 2, 0}; + } else if (r_data->scr_viewsize->int_val == 90) { + origin += (vec4f_t) { 0, 0, 1, 0}; + } else if (r_data->scr_viewsize->int_val == 80) { + origin += (vec4f_t) { 0, 0, 0.5, 0}; + } view->renderer.model = cl.model_precache[cl.stats[STAT_WEAPON]]; view->animation.frame = cl.stats[STAT_WEAPONFRAME]; view->renderer.skin = 0; // set up the refresh position - VectorAdd (r_data->refdef->viewangles, cl.punchangle, - r_data->refdef->viewangles); + r_data->refdef->viewrotation = qmulf (cl.viewstate.punchangle, + r_data->refdef->viewrotation); // smooth out stair step ups if ((cl.onground != -1) && (origin[2] - oldz > 0)) { float steptime; - steptime = cl.time - cl.oldtime; - if (steptime < 0) - steptime = 0; + steptime = cl.viewstate.frametime; oldz += steptime * 80; if (oldz > origin[2]) oldz = origin[2]; if (origin[2] - oldz > 12) oldz = origin[2] - 12; - r_data->refdef->vieworg[2] += oldz - origin[2]; - view->origin[2] += oldz - origin[2]; - } else + r_data->refdef->viewposition[2] += oldz - origin[2]; + origin[2] += oldz - origin[2]; + } else { oldz = origin[2]; + } + { + // FIXME sort out the alias model specific negation + vec3_t ang = {-viewangles[0], viewangles[1], viewangles[2]}; + CL_TransformEntity (view, 1, ang, origin); + } - if (cl.chase && chase_active->int_val) + if (cl.chase && chase_active->int_val) { Chase_Update (); - - CL_TransformEntity (view, view->angles); + } } /* @@ -743,8 +701,11 @@ V_CalcRefdef (void) void V_RenderView (void) { - if (cls.state != ca_active) + if (cls.state != ca_active) { + r_data->refdef->viewposition = (vec4f_t) { 0, 0, 0, 1 }; + r_data->refdef->viewrotation = (vec4f_t) { 0, 0, 0, 1 }; return; + } if (cl.intermission) { // intermission / finale rendering V_CalcIntermissionRefdef (); diff --git a/qw/include/client.h b/qw/include/client.h index 5389579c4..8c0369fba 100644 --- a/qw/include/client.h +++ b/qw/include/client.h @@ -37,6 +37,7 @@ #include "QF/plugin/vid_render.h" #include "client/entities.h" +#include "client/view.h" #include "netchan.h" #include "qw/bothdefs.h" @@ -222,12 +223,7 @@ typedef struct { // the client simulates or interpolates movement to get these values double time; // this is the time value that the client // is rendering at. always <= realtime - vec4f_t simorg; - vec4f_t simvel; - vec3_t simangles; - - vec3_t punchangle; // temporary view kick from weapon firing - + viewstate_t viewstate; // pitch drifting vars float idealpitch; float pitchvel; @@ -342,7 +338,9 @@ extern struct cvar_s *cl_fb_players; extern client_state_t cl; -extern entityset_t cl_static_entities; +typedef struct entitystateset_s DARRAY_TYPE (struct entity_state_s) + entitystateset_t; +extern entitystateset_t cl_static_entities; extern entity_t cl_entities[512]; extern byte cl_entity_valid[2][512]; diff --git a/qw/source/cl_chase.c b/qw/source/cl_chase.c index 8a3d6419d..68c9e207a 100644 --- a/qw/source/cl_chase.c +++ b/qw/source/cl_chase.c @@ -41,16 +41,19 @@ #include "QF/mathlib.h" #include "QF/plugin/vid_render.h" +#include "QF/simd/vec4f.h" #include "qw/include/chase.h" #include "qw/include/cl_input.h" #include "qw/include/client.h" #include "world.h" -vec3_t camera_origin = {0,0,0}; -vec3_t camera_angles = {0,0,0}; -vec3_t player_origin = {0,0,0}; -vec3_t player_angles = {0,0,0}; + +vec4f_t camera_origin = {0,0,0,1}; +vec4f_t player_origin = {0,0,0,1}; +vec4f_t player_angles = {0,0,0,1}; + +vec3_t camera_angles = {0,0,0}; vec3_t chase_angles; vec3_t chase_dest; @@ -94,19 +97,17 @@ TraceLine (vec3_t start, vec3_t end, vec3_t impact) void Chase_Update (void) { - float pitch, yaw, fwd; - int i; - usercmd_t cmd; // movement direction - vec3_t forward, up, right, stop, dir; + float pitch, yaw, fwd; + usercmd_t cmd; // movement direction + vec4f_t forward = {}, up = {}, right = {}, stop = {}, dir = {}; // lazy camera, look toward player entity if (chase_active->int_val == 2 || chase_active->int_val == 3) { // control camera angles with key/mouse/joy-look - - camera_angles[PITCH] += cl.viewangles[PITCH] - player_angles[PITCH]; - camera_angles[YAW] += cl.viewangles[YAW] - player_angles[YAW]; - camera_angles[ROLL] += cl.viewangles[ROLL] - player_angles[ROLL]; + vec3_t d; + VectorSubtract (cl.viewstate.angles, player_angles, d); + VectorAdd (camera_angles, d, camera_angles); if (chase_active->int_val == 2) { if (camera_angles[PITCH] < -60) @@ -118,48 +119,48 @@ Chase_Update (void) // move camera, it's not enough to just change the angles because // the angles are automatically changed to look toward the player - if (chase_active->int_val == 3) - VectorCopy (r_data->refdef->vieworg, player_origin); + if (chase_active->int_val == 3) { + player_origin = r_data->refdef->viewposition; + } - AngleVectors (camera_angles, forward, right, up); - VectorScale (forward, chase_back->value, forward); - VectorSubtract (player_origin, forward, camera_origin); + AngleVectors (camera_angles, &forward[0], &right[0], &up[0]); + camera_origin = player_origin - chase_back->value * forward; if (chase_active->int_val == 2) { - VectorCopy (r_data->refdef->vieworg, player_origin); + player_origin = r_data->refdef->viewposition; // don't let camera get too low - if (camera_origin[2] < player_origin[2] + chase_up->value) + if (camera_origin[2] < player_origin[2] + chase_up->value) { camera_origin[2] = player_origin[2] + chase_up->value; + } } // don't let camera get too far from player - VectorSubtract (camera_origin, player_origin, dir); - VectorCopy (dir, forward); - VectorNormalize (forward); + dir = camera_origin - player_origin; + forward = normalf (dir); - if (VectorLength (dir) > chase_back->value) { - VectorScale (forward, chase_back->value, dir); - VectorAdd (player_origin, dir, camera_origin); + if (magnitudef (dir)[0] > chase_back->value) { + camera_origin = player_origin + forward * chase_back->value; } // check for walls between player and camera - VectorScale (forward, 8, forward); - VectorAdd (camera_origin, forward, camera_origin); - TraceLine (player_origin, camera_origin, stop); - if (VectorLength (stop) != 0) - VectorSubtract (stop, forward, camera_origin); + camera_origin += 8 * forward; + //FIXME + TraceLine (&player_origin[0], &camera_origin[0], &stop[0]); + stop[3] = 1; + if (magnitude3f (stop)[0] != 0) { + camera_origin = stop - forward; + } - VectorSubtract (camera_origin, r_data->refdef->vieworg, dir); - VectorCopy (dir, forward); - VectorNormalize (forward); + dir = camera_origin - r_data->refdef->viewposition; + forward = normalf (dir); if (chase_active->int_val == 2) { if (dir[1] == 0 && dir[0] == 0) { // look straight up or down -// camera_angles[YAW] = r_data->refdef->viewangles[YAW]; +// camera_angles[YAW] = r_data->refdef->viewstate.angles[YAW]; if (dir[2] > 0) camera_angles[PITCH] = 90; else @@ -182,13 +183,13 @@ Chase_Update (void) } } - VectorCopy (camera_angles, r_data->refdef->viewangles);// rotate camera - VectorCopy (camera_origin, r_data->refdef->vieworg); // move camera + AngleQuat (camera_angles, &r_data->refdef->viewrotation[0]);//FIXME rotate camera + r_data->refdef->viewposition = camera_origin; // move camera // get basic movement from keyboard memset (&cmd, 0, sizeof (cmd)); -// VectorCopy (cl.viewangles, cmd.angles); +// VectorCopy (cl.viewstate.angles, cmd.angles); if (in_strafe.state & 1) { cmd.sidemove += cl_sidespeed->value * CL_KeyState (&in_right); @@ -208,54 +209,54 @@ Chase_Update (void) } // mouse and joystick controllers add to movement - VectorSet (0, cl.viewangles[1] - camera_angles[1], 0, dir); - AngleVectors (dir, forward, right, up); - VectorScale (forward, viewdelta.position[2] * m_forward->value, - forward); - VectorScale (right, viewdelta.position[0] * m_side->value, right); - VectorAdd (forward, right, dir); + VectorSet (0, cl.viewstate.angles[1] - camera_angles[1], 0, dir); + AngleVectors (&dir[0], &forward[0], &right[0], &up[0]); //FIXME + forward *= viewdelta.position[2] * m_forward->value; + right *= viewdelta.position[0] * m_side->value; + dir = forward + right; cmd.forwardmove += dir[0]; cmd.sidemove -= dir[1]; VectorSet (0, camera_angles[1], 0, dir); - AngleVectors (dir, forward, right, up); + AngleVectors (&dir[0], &forward[0], &right[0], &up[0]); //FIXME VectorScale (forward, cmd.forwardmove, forward); VectorScale (right, cmd.sidemove, right); VectorAdd (forward, right, dir); if (dir[1] || dir[0]) { - cl.viewangles[YAW] = (atan2 (dir[1], dir[0]) * 180 / M_PI); - if (cl.viewangles[YAW] < 0) cl.viewangles[YAW] += 360; -// if (cl.viewangles[YAW] < 180) -// cl.viewangles[YAW] += 180; -// else -// cl.viewangles[YAW] -= 180; + cl.viewstate.angles[YAW] = (atan2 (dir[1], dir[0]) * 180 / M_PI); + if (cl.viewstate.angles[YAW] < 0) { + cl.viewstate.angles[YAW] += 360; + } } - cl.viewangles[PITCH] = 0; + cl.viewstate.angles[PITCH] = 0; // remember the new angle to calculate the difference next frame - VectorCopy (cl.viewangles, player_angles); + VectorCopy (cl.viewstate.angles, player_angles); return; } // regular camera, faces same direction as player - AngleVectors (cl.viewangles, forward, right, up); + //FIXME + AngleVectors (cl.viewstate.angles, &forward[0], &right[0], &up[0]); // calc exact destination - for (i = 0; i < 3; i++) - camera_origin[i] = r_data->refdef->vieworg[i] - - forward[i] * chase_back->value - right[i] * chase_right->value; + camera_origin = r_data->refdef->viewposition + - forward * chase_back->value - right * chase_right->value; + // chase_up is world up camera_origin[2] += chase_up->value; // check for walls between player and camera - TraceLine (r_data->refdef->vieworg, camera_origin, stop); - if (VectorLength (stop) != 0) - for (i = 0; i < 3; i++) - camera_origin[i] = stop[i] + forward[i] * 8; + //FIXME + TraceLine (&r_data->refdef->viewposition[0], &camera_origin[0], &stop[0]); + stop[3] = 1; + if (magnitude3f (stop)[0] != 0) { + camera_origin = stop + forward * 8; + } - VectorCopy (camera_origin, r_data->refdef->vieworg); + r_data->refdef->viewposition = camera_origin; } diff --git a/qw/source/cl_demo.c b/qw/source/cl_demo.c index 0694b5f25..7503f5c2a 100644 --- a/qw/source/cl_demo.c +++ b/qw/source/cl_demo.c @@ -652,9 +652,8 @@ demo_start_recording (int track) { byte buf_data[MAX_MSGLEN + 10]; // + 10 for header char *s; - int n, i, j; + int n, i; int seq = 1; - entity_t *ent; entity_state_t *es, blankes; player_info_t *player; sizebuf_t buf; @@ -757,23 +756,16 @@ demo_start_recording (int track) // spawnstatic for (size_t staticIndex = 0; staticIndex < cl_static_entities.size; staticIndex++) { - ent = cl_static_entities.a[staticIndex]; + entity_state_t *es = &cl_static_entities.a[staticIndex]; + MSG_WriteByte (&buf, svc_spawnstatic); - for (j = 1; j < cl.nummodels; j++) { - if (ent->renderer.model == cl.model_precache[j]) { - break; - } - } - if (j == cl.nummodels) - MSG_WriteByte (&buf, 0); - else - MSG_WriteByte (&buf, j); + MSG_WriteByte (&buf, es->modelindex); - MSG_WriteByte (&buf, ent->animation.frame); + MSG_WriteByte (&buf, es->frame); MSG_WriteByte (&buf, 0); - MSG_WriteByte (&buf, ent->renderer.skinnum); - MSG_WriteCoordAngleV (&buf, ent->origin, ent->angles); + MSG_WriteByte (&buf, es->skinnum); + MSG_WriteCoordAngleV (&buf, &es->origin[0], &es->angles[0]); if (buf.cursize > MAX_MSGLEN / 2) { CL_WriteRecordDemoMessage (&buf, seq++); diff --git a/qw/source/cl_entparse.c b/qw/source/cl_entparse.c index 60c8cf2c4..7100d2726 100644 --- a/qw/source/cl_entparse.c +++ b/qw/source/cl_entparse.c @@ -130,6 +130,8 @@ CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits) if (bits & U_ANGLE3) to->angles[2] = MSG_ReadAngle (net_message); + to->origin[3] = 1; + if (bits & U_SOLID) { // FIXME } @@ -428,6 +430,7 @@ CL_ParsePlayerinfo (void) state->messagenum = cl.parsecount; MSG_ReadCoordV (net_message, &state->pls.es.origin[0]);//FIXME + state->pls.es.origin[3] = 1; state->pls.es.frame = MSG_ReadByte (net_message); @@ -486,7 +489,7 @@ CL_ParsePlayerinfo (void) } if (bits & PF_SCALE) { val = MSG_ReadByte (net_message); - ent->scale = val / 16.0; + state->pls.es.scale = val; } if (bits & PF_EFFECTS2) { state->pls.es.effects |= MSG_ReadByte (net_message) << 8; diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index b70b143cc..8ee9440b4 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -132,7 +132,6 @@ CL_LinkPacketEntities (void) entity_state_t *new, *old; renderer_t *renderer; animation_t *animation; - vec3_t delta; frac = 1; for (i = 0; i < 512; i++) { @@ -195,7 +194,6 @@ CL_LinkPacketEntities (void) 0); } } - ent->scale = new->scale / 16.0; VectorCopy (ent_colormod[new->colormod], renderer->colormod); renderer->colormod[3] = new->alpha / 255.0; @@ -209,35 +207,31 @@ CL_LinkPacketEntities (void) } } + ent->old_origin = Transform_GetWorldPosition (ent->transform); if (forcelink) { animation->pose1 = animation->pose2 = -1; - VectorCopy (new->origin, ent->origin); - if (!(renderer->model->flags & EF_ROTATE)) - CL_TransformEntity (ent, new->angles); + CL_TransformEntity (ent, new->scale / 16, new->angles, + new->origin); if (i != cl.viewentity || chase_active->int_val) { if (ent->visibility.efrag) { r_funcs->R_RemoveEfrags (ent); } r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } - VectorCopy (ent->origin, ent->old_origin); } else { + vec4f_t delta = new->origin - old->origin; f = frac; - VectorCopy (ent->origin, ent->old_origin); - VectorSubtract (new->origin, old->origin, delta); // If the delta is large, assume a teleport and don't lerp if (fabs (delta[0]) > 100 || fabs (delta[1] > 100) || fabs (delta[2]) > 100) { // assume a teleportation, not a motion - VectorCopy (new->origin, ent->origin); - if (!(renderer->model->flags & EF_ROTATE)) { - CL_TransformEntity (ent, new->angles); - } + CL_TransformEntity (ent, new->scale / 16, new->angles, + new->origin); animation->pose1 = animation->pose2 = -1; } else { vec3_t angles, d; + vec4f_t origin = old->origin + f * delta; // interpolate the origin and angles - VectorMultAdd (old->origin, f, delta, ent->origin); if (!(renderer->model->flags & EF_ROTATE)) { VectorSubtract (new->angles, old->angles, d); for (j = 0; j < 3; j++) { @@ -247,12 +241,14 @@ CL_LinkPacketEntities (void) d[j] += 360; } VectorMultAdd (old->angles, f, d, angles); - CL_TransformEntity (ent, angles); } + CL_TransformEntity (ent, new->scale / 16.0, angles, origin); } if (i != cl.viewentity || chase_active->int_val) { if (ent->visibility.efrag) { - if (!VectorCompare (ent->origin, ent->old_origin)) { + vec4f_t org + = Transform_GetWorldPosition (ent->transform); + if (!VectorCompare (org, ent->old_origin)) {//FIXME r_funcs->R_RemoveEfrags (ent); r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } @@ -271,12 +267,13 @@ CL_LinkPacketEntities (void) angles[PITCH] = 0; angles[YAW] = anglemod (100 * cl.time); angles[ROLL] = 0; - CL_TransformEntity (ent, angles); + CL_TransformEntity (ent, new->scale / 16.0, angles, new->origin); } //CL_EntityEffects (i, ent, new); //CL_NewDlight (i, ent->origin, new->effects, 0, 0, cl.time); - if (VectorDistance_fast (old->origin, ent->origin) > (256 * 256)) - VectorCopy (ent->origin, old->origin); + vec4f_t org = Transform_GetWorldPosition (ent->transform); + if (VectorDistance_fast (old->origin, org) > (256 * 256)) + old->origin = org; if (renderer->model->flags & ~EF_ROTATE) { CL_ModelEffects (ent, -new->number, new->glow_color, cl.time); } @@ -378,7 +375,7 @@ CL_LinkPlayers (void) // spawn light flashes, even ones coming from invisible objects if (j == cl.playernum) { - org = cl.simorg; + org = cl.viewstate.origin; r_data->player_entity = &cl_player_ents[j]; clientplayer = true; } else { @@ -413,15 +410,16 @@ CL_LinkPlayers (void) // predict only half the move to minimize overruns msec = 500 * (playertime - state->state_time); if (msec <= 0 || (!cl_predict_players->int_val) || cls.demoplayback2) { - VectorCopy (state->pls.es.origin, ent->origin); + Sys_Printf("a\n"); + exact.pls.es.origin = state->pls.es.origin; } else { // predict players movement state->pls.cmd.msec = msec = min (msec, 255); oldphysent = pmove.numphysent; CL_SetSolidPlayers (j); + exact.pls.es.origin[3] = 1;//FIXME should be done by prediction CL_PredictUsercmd (state, &exact, &state->pls.cmd, clientplayer); pmove.numphysent = oldphysent; - VectorCopy (exact.pls.es.origin, ent->origin); } // angles @@ -439,7 +437,8 @@ CL_LinkPlayers (void) ent->animation.frame = state->pls.es.frame; ent->renderer.skinnum = state->pls.es.skinnum; - CL_TransformEntity (ent, ang); + //FIXME scale + CL_TransformEntity (ent, 1, ang, exact.pls.es.origin); ent->renderer.min_light = 0; ent->renderer.fullbright = 0; @@ -484,14 +483,14 @@ CL_EmitEntities (void) return; TEntContext_t tentCtx = { - {VectorExpand (cl.simorg), 1}, cl.worldmodel, cl.viewentity + cl.viewstate.origin, cl.worldmodel, cl.viewentity }; CL_LinkPlayers (); CL_LinkPacketEntities (); CL_UpdateTEnts (cl.time, &tentCtx); if (cl_draw_locs->int_val) { - locs_draw (cl.simorg); + locs_draw (cl.viewstate.origin); } } diff --git a/qw/source/cl_input.c b/qw/source/cl_input.c index 5a2fe2b6e..9b9763d46 100644 --- a/qw/source/cl_input.c +++ b/qw/source/cl_input.c @@ -530,6 +530,7 @@ CL_BaseMove (usercmd_t *cmd) IN_Move (); // adjust for chase camera angles + /*FIXME:chase figure out just what this does and get it working if (cl.chase && (chase_active->int_val == 2 || chase_active->int_val == 3)) { vec3_t forward, right, up, f, r; @@ -546,6 +547,7 @@ CL_BaseMove (usercmd_t *cmd) viewdelta.position[2] = f[0] + r[0]; viewdelta.position[0] = (f[1] + r[1]) * -1; } + */ cmd->forwardmove += viewdelta.position[2] * m_forward->value; cmd->sidemove += viewdelta.position[0] * m_side->value; diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index be73db0e7..cef24d6bd 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -1605,6 +1605,8 @@ Host_Frame (float time) oldrealtime = realtime; host_frametime = min (host_frametime, 0.2); + cl.viewstate.frametime = host_frametime; + con_frametime = con_realtime - oldcon_realtime; oldcon_realtime = con_realtime; diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index b75355fa1..b53c2beb9 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -170,7 +170,7 @@ int packet_latency[NET_TIMINGS]; extern cvar_t *hud_scoreboard_uid; -entityset_t cl_static_entities = DARRAY_STATIC_INIT (32); +entitystateset_t cl_static_entities = DARRAY_STATIC_INIT (32); static void CL_LoadSky (void) @@ -973,15 +973,14 @@ CL_ParseStatic (void) ent = r_funcs->R_AllocEntity (); CL_Init_Entity (ent); - DARRAY_APPEND (&cl_static_entities, ent); + DARRAY_APPEND (&cl_static_entities, es); // copy it to the current state ent->renderer.model = cl.model_precache[es.modelindex]; ent->animation.frame = es.frame; ent->renderer.skinnum = es.skinnum; - VectorCopy (es.origin, ent->origin); - CL_TransformEntity (ent, es.angles); + CL_TransformEntity (ent, es.scale / 16.0, es.angles, es.origin); r_funcs->R_AddEfrags (&cl.worldmodel->brush, ent); } @@ -1296,7 +1295,7 @@ CL_ParseServerMessage (void) const char *str; static dstring_t *stuffbuf; TEntContext_t tentCtx = { - {VectorExpand (cl.simorg), 1}, cl.worldmodel, cl.viewentity + cl.viewstate.origin, cl.worldmodel, cl.viewentity }; received_framecount = host_framecount; @@ -1542,17 +1541,17 @@ CL_ParseServerMessage (void) cl.completed_time = realtime; r_data->vid->recalc_refdef = true; // go to full screen Sys_MaskPrintf (SYS_DEV, "intermission simorg: "); - MSG_ReadCoordV (net_message, &cl.simorg[0]);//FIXME - cl.simorg[3] = 1; - for (i = 0; i < 3; i++) - Sys_MaskPrintf (SYS_DEV, "%f ", cl.simorg[i]); + MSG_ReadCoordV (net_message, &cl.viewstate.origin[0]);//FIXME + cl.viewstate.origin[3] = 1; + Sys_MaskPrintf (SYS_DEV, VEC4F_FMT, + VEC4_EXP (cl.viewstate.origin)); Sys_MaskPrintf (SYS_DEV, "\nintermission simangles: "); - MSG_ReadAngleV (net_message, cl.simangles); - cl.simangles[ROLL] = 0; // FIXME @@@ - for (i = 0; i < 3; i++) - Sys_MaskPrintf (SYS_DEV, "%f ", cl.simangles[i]); + MSG_ReadAngleV (net_message, cl.viewstate.angles); + cl.viewstate.angles[ROLL] = 0; // FIXME @@@ + Sys_MaskPrintf (SYS_DEV, "%f %f %f", + VectorExpand (cl.viewstate.angles)); Sys_MaskPrintf (SYS_DEV, "\n"); - VectorZero (cl.simvel); + cl.viewstate.velocity = (vec4f_t) { }; // automatic fraglogging (by elmex) // XXX: Should this _really_ called here? @@ -1585,11 +1584,17 @@ CL_ParseServerMessage (void) // svc_cutscene (same value as svc_smallkick) case svc_smallkick: - cl.punchangle[PITCH] = -2; + cl.viewstate.punchangle = (vec4f_t) { + // -2 degrees pitch + 0, -0.0174524064, 0, 0.999847695 + }; break; case svc_bigkick: - cl.punchangle[PITCH] = -4; + cl.viewstate.punchangle = (vec4f_t) { + // -4 degrees pitch + 0, -0.0348994967, 0, 0.999390827 + }; break; case svc_updateping: diff --git a/qw/source/cl_pred.c b/qw/source/cl_pred.c index f48533673..5bf79a163 100644 --- a/qw/source/cl_pred.c +++ b/qw/source/cl_pred.c @@ -47,7 +47,7 @@ cvar_t *cl_pushlatency; void -CL_PredictUsercmd (player_state_t * from, player_state_t * to, usercmd_t *u, +CL_PredictUsercmd (player_state_t *from, player_state_t *to, usercmd_t *u, qboolean clientplayer) { if (!clientplayer) { @@ -105,6 +105,8 @@ CL_PredictMove (void) float f; int oldphysent, i; frame_t *from, *to = NULL; + entity_state_t *fromes; + entity_state_t *toes; if (cl_pushlatency->value > 0) Cvar_Set (cl_pushlatency, "0"); @@ -130,15 +132,16 @@ CL_PredictMove (void) UPDATE_BACKUP - 1) return; - VectorCopy (cl.viewangles, cl.simangles); - cl.simangles[ROLL] = 0; // FIXME @@@ + VectorCopy (cl.viewangles, cl.viewstate.angles); + cl.viewstate.angles[ROLL] = 0; // FIXME @@@ // this is the last frame received from the server from = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK]; + fromes = &from->playerstate[cl.playernum].pls.es; if (!cl_predict->int_val) { - VectorCopy (from->playerstate[cl.playernum].pls.es.velocity, cl.simvel); - VectorCopy (from->playerstate[cl.playernum].pls.es.origin, cl.simorg); + cl.viewstate.velocity = fromes->velocity; + cl.viewstate.origin = fromes->origin; return; } @@ -165,6 +168,7 @@ CL_PredictMove (void) if (i == UPDATE_BACKUP - 1 || !to) return; // net hasn't deliver packets in a // long time... + toes = &to->playerstate[cl.playernum].pls.es; // now interpolate some fraction of the final frame if (to->senttime == from->senttime) @@ -175,18 +179,14 @@ CL_PredictMove (void) } for (i = 0; i < 3; i++) - if (fabs (from->playerstate[cl.playernum].pls.es.origin[i] - - to->playerstate[cl.playernum].pls.es.origin[i]) > 128) { + if (fabs (fromes->origin[i] - toes->origin[i]) > 128) { // teleported, so don't lerp - VectorCopy (to->playerstate[cl.playernum].pls.es.velocity, - cl.simvel); - VectorCopy (to->playerstate[cl.playernum].pls.es.origin, cl.simorg); + cl.viewstate.velocity = toes->velocity; + cl.viewstate.origin = toes->origin; return; } - cl.simorg = from->playerstate[cl.playernum].pls.es.origin - + f * (to->playerstate[cl.playernum].pls.es.origin - - from->playerstate[cl.playernum].pls.es.origin); + cl.viewstate.origin = fromes->origin + f * (toes->origin - fromes->origin); } void diff --git a/qw/source/cl_screen.c b/qw/source/cl_screen.c index 22c8b5b96..12cfb8441 100644 --- a/qw/source/cl_screen.c +++ b/qw/source/cl_screen.c @@ -87,7 +87,9 @@ SCR_CShift (void) int contents = CONTENTS_EMPTY; if (cls.state == ca_active && cl.worldmodel) { - leaf = Mod_PointInLeaf (r_data->refdef->vieworg, cl.worldmodel); + //FIXME + leaf = Mod_PointInLeaf (&r_data->refdef->viewposition[0], + cl.worldmodel); contents = leaf->contents; } V_SetContentsColor (contents); diff --git a/qw/source/cl_view.c b/qw/source/cl_view.c index f20d5747a..0e9162ca8 100644 --- a/qw/source/cl_view.c +++ b/qw/source/cl_view.c @@ -37,8 +37,6 @@ #include "compat.h" -#include "client/view.h" - #include "qw/bothdefs.h" #include "qw/include/chase.h" @@ -84,8 +82,9 @@ cvar_t *v_idlescale; float v_dmg_time, v_dmg_roll, v_dmg_pitch; -frame_t *view_frame; -player_state_t *view_state; +vec4f_t v_idle_yaw; +vec4f_t v_idle_roll; +vec4f_t v_idle_pitch; cshift_t cshift_empty = { {130, 80, 50}, 0}; cshift_t cshift_water = { {130, 80, 50}, 128}; @@ -119,7 +118,7 @@ V_CalcRoll (const vec3_t angles, vec4f_t velocity) static float V_CalcBob (void) { - vec4f_t velocity = cl.simvel; + vec4f_t velocity = cl.viewstate.velocity; float cycle; static double bobtime; static float bob; @@ -130,7 +129,7 @@ V_CalcBob (void) if (cl.onground == -1) return bob; // just use old value - bobtime += host_frametime; + bobtime += cl.viewstate.frametime; cycle = bobtime - (int) (bobtime / cl_bobcycle->value) * cl_bobcycle->value; cycle /= cl_bobcycle->value; @@ -189,10 +188,9 @@ static void V_DriftPitch (void) { float delta, move; - int frameno = (cls.netchan.outgoing_sequence - 1) & UPDATE_MASK; - usercmd_t *cmd = &cl.frames[frameno].cmd; + float forwardmove = cl.viewstate.movecmd[0]; - if (view_state->onground == -1 || cls.demoplayback) { + if (noclip_anglehack || cl.viewstate.onground == -1 || cls.demoplayback) { cl.driftmove = 0; cl.pitchvel = 0; return; @@ -200,10 +198,10 @@ V_DriftPitch (void) // don't count small mouse motion if (cl.nodrift) { - if (fabs (cmd->forwardmove) < cl_forwardspeed->value) + if (fabs (forwardmove) < cl_forwardspeed->value) cl.driftmove = 0; else - cl.driftmove += host_frametime; + cl.driftmove += cl.viewstate.frametime; if (cl.driftmove > v_centermove->value) { V_StartPitchDrift (); @@ -211,28 +209,28 @@ V_DriftPitch (void) return; } - delta = cl.idealpitch - cl.viewangles[PITCH]; + delta = cl.idealpitch - cl.viewstate.angles[PITCH]; if (!delta) { cl.pitchvel = 0; return; } - move = host_frametime * cl.pitchvel; - cl.pitchvel += host_frametime * v_centerspeed->value; + move = cl.viewstate.frametime * cl.pitchvel; + cl.pitchvel += cl.viewstate.frametime * v_centerspeed->value; if (delta > 0) { if (move > delta) { cl.pitchvel = 0; move = delta; } - cl.viewangles[PITCH] += move; + cl.viewstate.angles[PITCH] += move; } else if (delta < 0) { if (move > -delta) { cl.pitchvel = 0; move = -delta; } - cl.viewangles[PITCH] -= move; + cl.viewstate.angles[PITCH] -= move; } } @@ -243,8 +241,8 @@ V_ParseDamage (void) { float count, side; int armor, blood; - vec4f_t origin = cl.simorg; - vec_t *angles = cl.simangles; + vec4f_t origin = cl.viewstate.origin; + vec_t *angles = cl.viewstate.angles; vec3_t from, forward, right, up; armor = MSG_ReadByte (net_message); @@ -488,73 +486,41 @@ V_PrepBlend (void) /* VIEW RENDERING */ -static float -angledelta (float a) -{ - a = anglemod (a); - if (a > 180) - a -= 360; - return a; -} - static void CalcGunAngle (void) { - float yaw, pitch, move; - static float oldpitch = 0, oldyaw = 0; - - yaw = r_data->refdef->viewangles[YAW]; - pitch = -r_data->refdef->viewangles[PITCH]; - - yaw = angledelta (yaw - r_data->refdef->viewangles[YAW]) * 0.4; - yaw = bound (-10, yaw, 10); - pitch = angledelta (-pitch - r_data->refdef->viewangles[PITCH]) * 0.4; - pitch = bound (-10, pitch, 10); - - move = host_frametime * 20; - if (yaw > oldyaw) { - if (oldyaw + move < yaw) - yaw = oldyaw + move; - } else { - if (oldyaw - move > yaw) - yaw = oldyaw - move; - } - - if (pitch > oldpitch) { - if (oldpitch + move < pitch) - pitch = oldpitch + move; - } else { - if (oldpitch - move > pitch) - pitch = oldpitch - move; - } - - oldyaw = yaw; - oldpitch = pitch; - - cl.viewent.angles[YAW] = r_data->refdef->viewangles[YAW] + yaw; - cl.viewent.angles[PITCH] = -(r_data->refdef->viewangles[PITCH] + pitch); + vec4f_t rotation = r_data->refdef->viewrotation; + //FIXME make child of camera + Transform_SetWorldRotation (cl.viewent.transform, rotation); } static void V_BoundOffsets (void) { - vec4f_t origin = cl.simorg; + vec4f_t offset = r_data->refdef->viewposition + - cl.viewstate.origin; // absolutely bound refresh reletive to entity clipping hull // so the view can never be inside a solid wall - if (r_data->refdef->vieworg[0] < origin[0] - 14) - r_data->refdef->vieworg[0] = origin[0] - 14; - else if (r_data->refdef->vieworg[0] > origin[0] + 14) - r_data->refdef->vieworg[0] = origin[0] + 14; - if (r_data->refdef->vieworg[1] < origin[1] - 14) - r_data->refdef->vieworg[1] = origin[1] - 14; - else if (r_data->refdef->vieworg[1] > origin[1] + 14) - r_data->refdef->vieworg[1] = origin[1] + 14; - if (r_data->refdef->vieworg[2] < origin[2] - 22) - r_data->refdef->vieworg[2] = origin[2] - 22; - else if (r_data->refdef->vieworg[2] > origin[2] + 30) - r_data->refdef->vieworg[2] = origin[2] + 30; + offset[0] = bound (-14, offset[0], 14); + offset[1] = bound (-14, offset[1], 14); + offset[2] = bound (-22, offset[2], 30); + r_data->refdef->viewposition = cl.viewstate.origin + offset; +} + +static vec4f_t +idle_quat (vec4f_t axis, cvar_t *cycle, cvar_t *level) +{ + vec4f_t identity = { 0, 0, 0, 1 }; + if (!level || !cycle) { + return identity; + } + float scale = sin (cl.time * cycle->value); + float ang = scale * level->value * v_idlescale->value; + float c = cos (ang); + float s = sin (ang); + return axis * s + identity * c; } /* @@ -565,19 +531,21 @@ V_BoundOffsets (void) static void V_AddIdle (void) { - r_data->refdef->viewangles[ROLL] += v_idlescale->value * - sin (cl.time * v_iroll_cycle->value) * v_iroll_level->value; - r_data->refdef->viewangles[PITCH] += v_idlescale->value * - sin (cl.time * v_ipitch_cycle->value) * v_ipitch_level->value; - r_data->refdef->viewangles[YAW] += v_idlescale->value * - sin (cl.time * v_iyaw_cycle->value) * v_iyaw_level->value; + vec4f_t roll = idle_quat ((vec4f_t) { 1, 0, 0, 0}, + v_iroll_cycle, v_iroll_level); + vec4f_t pitch = idle_quat ((vec4f_t) { 0, 1, 0, 0}, + v_ipitch_cycle, v_ipitch_level); + vec4f_t yaw = idle_quat ((vec4f_t) { 0, 0, 1, 0}, + v_iyaw_cycle, v_iyaw_level); + vec4f_t rot = normalf (qmulf (yaw, qmulf (pitch, roll))); - cl.viewent.angles[ROLL] -= v_idlescale->value * - sin (cl.time * v_iroll_cycle->value) * v_iroll_level->value; - cl.viewent.angles[PITCH] -= v_idlescale->value * - sin (cl.time * v_ipitch_cycle->value) * v_ipitch_level->value; - cl.viewent.angles[YAW] -= v_idlescale->value * - sin (cl.time * v_iyaw_cycle->value) * v_iyaw_level->value; + // rotate the view + r_data->refdef->viewrotation = qmulf (rot, r_data->refdef->viewrotation); + + // counter-rotate the weapon + rot = qmulf (qconjf (rot), + Transform_GetWorldRotation (cl.viewent.transform)); + Transform_SetWorldRotation (cl.viewent.transform, rot); } /* @@ -588,23 +556,25 @@ V_AddIdle (void) static void V_CalcViewRoll (void) { - float side; - vec_t *angles = cl.simangles; - vec4f_t velocity = cl.simvel; + vec_t *angles = cl.viewstate.angles; + vec4f_t velocity = cl.viewstate.velocity; + vec3_t ang = { }; - side = V_CalcRoll (angles, velocity); - r_data->refdef->viewangles[ROLL] += side; + ang[ROLL] = V_CalcRoll (angles, velocity); if (v_dmg_time > 0) { - r_data->refdef->viewangles[ROLL] += - v_dmg_time / v_kicktime->value * v_dmg_roll; - r_data->refdef->viewangles[PITCH] += - v_dmg_time / v_kicktime->value * v_dmg_pitch; - v_dmg_time -= host_frametime; + ang[ROLL] += v_dmg_time / v_kicktime->value * v_dmg_roll; + ang[PITCH] += v_dmg_time / v_kicktime->value * v_dmg_pitch; + v_dmg_time -= cl.viewstate.frametime; } - if (view_state->pls.es.flags & PF_DEAD) // PF_GIB will also set PF_DEAD - r_data->refdef->viewangles[ROLL] = 80; // dead view angle + if (cl.viewstate.flags & VF_DEAD) { // VF_GIB will also set VF_DEAD + ang[ROLL] = 80; // dead view angle + } + + vec4f_t rot; + AngleQuat (ang, &rot[0]);//FIXME + r_data->refdef->viewrotation = qmulf (r_data->refdef->viewrotation, rot); } static void @@ -612,14 +582,12 @@ V_CalcIntermissionRefdef (void) { entity_t *view; float old; - vec4f_t origin = cl.simorg; - vec_t *angles = cl.simangles; // view is the weapon model (visible only from inside body) view = &cl.viewent; - VectorCopy (origin, r_data->refdef->vieworg); - VectorCopy (angles, r_data->refdef->viewangles); + r_data->refdef->viewposition = cl.viewstate.origin; + AngleQuat (cl.viewstate.angles, &r_data->refdef->viewrotation[0]);//FIXME view->renderer.model = NULL; // always idle in intermission @@ -636,113 +604,122 @@ V_CalcRefdef (void) entity_t *view = &cl.viewent; float bob; static float oldz = 0; - int i; - vec3_t forward, right, up; - vec4f_t origin = cl.simorg; - vec_t *viewangles = cl.simangles; + vec4f_t forward = {}, right = {}, up = {}; + vec4f_t origin = cl.viewstate.origin; + vec_t *viewangles = cl.viewstate.angles; V_DriftPitch (); bob = V_CalcBob (); // refresh position - VectorCopy (origin, r_data->refdef->vieworg); - r_data->refdef->vieworg[2] += cl.viewheight + bob; + r_data->refdef->viewposition = origin; + r_data->refdef->viewposition[2] += cl.viewheight + bob; // never let it sit exactly on a node line, because a water plane can // disappear when viewed with the eye exactly on it. // server protocol specifies to only 1/8 pixel, so add 1/16 in each axis - r_data->refdef->vieworg[0] += 1.0 / 16; - r_data->refdef->vieworg[1] += 1.0 / 16; - r_data->refdef->vieworg[2] += 1.0 / 16; + r_data->refdef->viewposition += (vec4f_t) { 1.0/16, 1.0/16, 1.0/16, 0}; - VectorCopy (viewangles, r_data->refdef->viewangles); + AngleQuat (cl.viewstate.angles, &r_data->refdef->viewrotation[0]);//FIXME V_CalcViewRoll (); V_AddIdle (); // offsets - AngleVectors (viewangles, forward, right, up); + //FIXME semi-duplicates AngleQuat (also, vec3_t vs vec4f_t) + AngleVectors (viewangles, &forward[0], &right[0], &up[0]); // don't allow cheats in multiplayer // FIXME check for dead if (cl.maxclients == 1) { - for (i = 0; i < 3; i++) { - r_data->refdef->vieworg[i] += scr_ofsx->value * forward[i] + - scr_ofsy->value * right[i] + - scr_ofsz->value * up[i]; - } + r_data->refdef->viewposition += scr_ofsx->value * forward + + scr_ofsy->value * right + + scr_ofsz->value * up; } V_BoundOffsets (); // set up gun position - VectorCopy (viewangles, view->angles); - CalcGunAngle (); - VectorCopy (origin, view->origin); - view->origin[2] += cl.viewheight; - - for (i = 0; i < 3; i++) { - view->origin[i] += forward[i] * bob * 0.4; -// view->origin[i] += right[i] * bob * 0.4; -// view->origin[i] += up[i] * bob * 0.8; - } - view->origin[2] += bob; + origin += (vec4f_t) { 0, 0, cl.viewheight, 0 }; + origin += forward * bob * 0.4f + (vec4f_t) { 0, 0, bob, 0 }; // fudge position around to keep amount of weapon visible // roughly equal with different FOV - if (hud_sbar->int_val == 0 && r_data->scr_viewsize->int_val >= 100) + if (hud_sbar->int_val == 0 && r_data->scr_viewsize->int_val >= 100) { ; - else if (r_data->scr_viewsize->int_val == 110) - view->origin[2] += 1; - else if (r_data->scr_viewsize->int_val == 100) - view->origin[2] += 2; - else if (r_data->scr_viewsize->int_val == 90) - view->origin[2] += 1; - else if (r_data->scr_viewsize->int_val == 80) - view->origin[2] += 0.5; + } else if (r_data->scr_viewsize->int_val == 110) { + origin += (vec4f_t) { 0, 0, 1, 0}; + } else if (r_data->scr_viewsize->int_val == 100) { + origin += (vec4f_t) { 0, 0, 2, 0}; + } else if (r_data->scr_viewsize->int_val == 90) { + origin += (vec4f_t) { 0, 0, 1, 0}; + } else if (r_data->scr_viewsize->int_val == 80) { + origin += (vec4f_t) { 0, 0, 0.5, 0}; + } - if (view_state->pls.es.flags & (PF_GIB | PF_DEAD)) { + if (cl.viewstate.flags & (VF_GIB | VF_DEAD)) { view->renderer.model = NULL; } else { view->renderer.model = cl.model_precache[cl.stats[STAT_WEAPON]]; } - view->animation.frame = view_state->pls.es.weaponframe; + view->animation.frame = cl.viewstate.weaponframe; view->renderer.skin = 0; // set up the refresh position - VectorAdd (r_data->refdef->viewangles, cl.punchangle, - r_data->refdef->viewangles); + r_data->refdef->viewrotation = qmulf (cl.viewstate.punchangle, + r_data->refdef->viewrotation); // smooth out stair step ups if ((cl.onground != -1) && (origin[2] - oldz > 0)) { float steptime; - steptime = host_frametime; + steptime = cl.viewstate.frametime; oldz += steptime * 80; if (oldz > origin[2]) oldz = origin[2]; if (origin[2] - oldz > 12) oldz = origin[2] - 12; - r_data->refdef->vieworg[2] += oldz - origin[2]; - view->origin[2] += oldz - origin[2]; - } else + r_data->refdef->viewposition[2] += oldz - origin[2]; + origin[2] += oldz - origin[2]; + } else { oldz = origin[2]; + } + { + // FIXME sort out the alias model specific negation + vec3_t ang = {-viewangles[0], viewangles[1], viewangles[2]}; + CL_TransformEntity (view, 1, ang, origin); + } - if (cl.chase && chase_active->int_val) + if (cl.chase && chase_active->int_val) { Chase_Update (); - - CL_TransformEntity (view, view->angles); + } } static void DropPunchAngle (void) { - cl.punchangle[PITCH] -= 10 * host_frametime; - if (cl.punchangle[PITCH] < 0) - cl.punchangle[PITCH] = 0; + vec4f_t punch = cl.viewstate.punchangle; + float ps = magnitude3f (punch)[0]; + if (ps < 1e-3) { + // < 0.2 degree rotation, not worth worrying about + //ensure the quaternion is normalized + cl.viewstate.punchangle = (vec4f_t) { 0, 0, 0, 1 }; + return; + } + float pc = punch[3]; + float ds = 0.0871557427 * cl.viewstate.frametime; + float dc = sqrt (1 - ds * ds); + float s = ps * dc - pc * ds; + float c = pc * dc + ps * ds; + if (s <= 0 || c >= 1) { + cl.viewstate.punchangle = (vec4f_t) { 0, 0, 0, 1 }; + } else { + punch *= s / ps; + punch[3] = c; + } } /* @@ -754,17 +731,17 @@ DropPunchAngle (void) void V_RenderView (void) { - if (cls.state != ca_active) + if (cls.state != ca_active) { + r_data->refdef->viewposition = (vec4f_t) { 0, 0, 0, 1 }; + r_data->refdef->viewrotation = (vec4f_t) { 0, 0, 0, 1 }; return; + } - view_frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK]; - view_state = &view_frame->playerstate[cl.playernum]; - - if (view_state->pls.es.flags & PF_GIB) + if (cl.viewstate.flags & VF_GIB) { cl.viewheight = 8; // gib view height - else if (view_state->pls.es.flags & PF_DEAD) + } else if (cl.viewstate.flags & VF_DEAD) { cl.viewheight = -16; // corpse view height - else { + } else { cl.viewheight = DEFAULT_VIEWHEIGHT; // view height if (cl.stdver) cl.viewheight = cl.stats[STAT_VIEWHEIGHT]; diff --git a/qw/source/teamplay.c b/qw/source/teamplay.c index 159da95f0..c3e2a0424 100644 --- a/qw/source/teamplay.c +++ b/qw/source/teamplay.c @@ -184,10 +184,10 @@ Team_ParseSay (dstring_t *buf, const char *s) case 'l': location: bracket = 0; - location = locs_find (cl.simorg); + location = locs_find (cl.viewstate.origin); if (location) { recorded_location = true; - last_recorded_location = cl.simorg; + last_recorded_location = cl.viewstate.origin; t1 = location->name; } else snprintf (t2, sizeof (t2), "Unknown!"); @@ -279,7 +279,7 @@ void Team_Dead (void) { died = true; - death_location = cl.simorg; + death_location = cl.viewstate.origin; } void @@ -370,7 +370,7 @@ locs_loc (void) if (strcasecmp (Cmd_Argv (1), "add") == 0) { if (Cmd_Argc () >= 3) - locs_mark (cl.simorg, desc); + locs_mark (cl.viewstate.origin, desc); else Sys_Printf ("loc add :marks the current location " "with the description and records the information " @@ -379,7 +379,7 @@ locs_loc (void) if (strcasecmp (Cmd_Argv (1), "rename") == 0) { if (Cmd_Argc () >= 3) - locs_edit (cl.simorg, desc); + locs_edit (cl.viewstate.origin, desc); else Sys_Printf ("loc rename :changes the description of " "the nearest location marker\n"); @@ -387,14 +387,14 @@ locs_loc (void) if (strcasecmp (Cmd_Argv (1),"delete") == 0) { if (Cmd_Argc () == 2) - locs_del (cl.simorg); + locs_del (cl.viewstate.origin); else Sys_Printf ("loc delete :removes nearest location marker\n"); } if (strcasecmp (Cmd_Argv (1),"move") == 0) { if (Cmd_Argc () == 2) - locs_edit (cl.simorg, NULL); + locs_edit (cl.viewstate.origin, NULL); else Sys_Printf ("loc move :moves the nearest location marker to your " "current location\n"); @@ -409,7 +409,7 @@ Locs_Loc_Get (void) if (GIB_Argc () != 1) GIB_USAGE (""); else { - location = locs_find (cl.simorg); + location = locs_find (cl.viewstate.origin); GIB_Return (location ? location->name : "unknown"); } } From 8f7d6b1d02b9057af7e9f93bd69dd1b0ef104403 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 19 Mar 2021 22:53:23 +0900 Subject: [PATCH 404/435] [vulkan] Initialize skins This allows the qw client to run with Vulkan. --- libs/video/renderer/vid_render_vulkan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 00c307dbc..b4f84f129 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -102,6 +102,7 @@ vulkan_R_Init (void) Vulkan_Particles_Init (vulkan_ctx); Vulkan_Lighting_Init (vulkan_ctx); Vulkan_Compose_Init (vulkan_ctx); + Skin_Init (); Sys_Printf ("R_Init %p %d", vulkan_ctx->swapchain->swapchain, vulkan_ctx->swapchain->numImages); From 82e58dae5f6adcd59df2bbc0390f0346ba8aae17 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 19 Mar 2021 22:54:20 +0900 Subject: [PATCH 405/435] [qw] Disable lerping on player model change This seems to be an ancient bug, but may have been exposed by the recent entity changes (was certainly highlighted by Vulkan) --- qw/source/cl_ents.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 8ee9440b4..26e25ad25 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -433,7 +433,11 @@ CL_LinkPlayers (void) } ang[ROLL] = V_CalcRoll (ang, state->pls.es.velocity) * 4.0; - ent->renderer.model = cl.model_precache[state->pls.es.modelindex]; + if (ent->renderer.model + != cl.model_precache[state->pls.es.modelindex]) { + ent->renderer.model = cl.model_precache[state->pls.es.modelindex]; + ent->animation.nolerp = 1; + } ent->animation.frame = state->pls.es.frame; ent->renderer.skinnum = state->pls.es.skinnum; From 5cf1da7c252dcf6b6e9f3a0bd89b66756a2dd249 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 20 Mar 2021 00:58:37 +0900 Subject: [PATCH 406/435] [client] Finish moving onground to viewstate Missed this in the entity cleanup (really, should have been separate commits, but oh well). --- include/client/view.h | 2 +- nq/include/client.h | 1 - nq/source/cl_parse.c | 4 ++-- nq/source/cl_view.c | 4 ++-- qw/include/client.h | 1 - qw/source/cl_pred.c | 4 ++-- qw/source/cl_view.c | 4 ++-- 7 files changed, 9 insertions(+), 11 deletions(-) diff --git a/include/client/view.h b/include/client/view.h index 40ad78df3..7a7f8e005 100644 --- a/include/client/view.h +++ b/include/client/view.h @@ -43,7 +43,7 @@ typedef struct viewstate_s { vec4f_t origin; vec3_t angles; int weaponframe; - int onground; + int onground; // -1 when in air uint32_t flags; float frametime; vec4f_t punchangle; diff --git a/nq/include/client.h b/nq/include/client.h index 5d98e437b..54cb937f9 100644 --- a/nq/include/client.h +++ b/nq/include/client.h @@ -178,7 +178,6 @@ typedef struct { double laststop; qboolean paused; // Sent over by server - int onground; float viewheight; float crouch; // Local amount for smoothing stepups qboolean inwater; diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index e74a65976..30e48e82a 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -692,7 +692,7 @@ CL_ParseClientdata (void) cl.stats[STAT_ITEMS] = i; } - cl.onground = (bits & SU_ONGROUND) ? 0 : -1; + cl.viewstate.onground = (bits & SU_ONGROUND) ? 0 : -1; cl.inwater = (bits & SU_INWATER) != 0; if (bits & SU_WEAPONFRAME) @@ -851,7 +851,7 @@ CL_ParseServerMessage (void) else if (cl_shownet->int_val == 2) Sys_Printf ("------------------\n"); - cl.onground = -1; // unless the server says otherwise + cl.viewstate.onground = -1; // unless the server says otherwise // parse the message MSG_BeginReading (net_message); diff --git a/nq/source/cl_view.c b/nq/source/cl_view.c index f5ba3de8f..d21f267b1 100644 --- a/nq/source/cl_view.c +++ b/nq/source/cl_view.c @@ -124,7 +124,7 @@ V_CalcBob (void) if (cl.spectator) return 0; - if (cl.onground == -1) + if (cl.viewstate.onground == -1) return bob; // just use old value bobtime += cl.viewstate.frametime; @@ -666,7 +666,7 @@ V_CalcRefdef (void) r_data->refdef->viewrotation); // smooth out stair step ups - if ((cl.onground != -1) && (origin[2] - oldz > 0)) { + if ((cl.viewstate.onground != -1) && (origin[2] - oldz > 0)) { float steptime; steptime = cl.viewstate.frametime; diff --git a/qw/include/client.h b/qw/include/client.h index 8c0369fba..f3e12fced 100644 --- a/qw/include/client.h +++ b/qw/include/client.h @@ -232,7 +232,6 @@ typedef struct { double laststop; qboolean paused; // Sent over by server - int onground; // -1 when in air float viewheight; float crouch; // local amount for smoothing stepups diff --git a/qw/source/cl_pred.c b/qw/source/cl_pred.c index 5bf79a163..58ee4a144 100644 --- a/qw/source/cl_pred.c +++ b/qw/source/cl_pred.c @@ -115,7 +115,7 @@ CL_PredictMove (void) return; // assume on ground unless prediction says different - cl.onground = 0; + cl.viewstate.onground = 0; cl.time = realtime - cls.latency - cl_pushlatency->value * 0.001; if (cl.time > realtime) @@ -157,7 +157,7 @@ CL_PredictMove (void) CL_PredictUsercmd (&from->playerstate[cl.playernum], &to->playerstate[cl.playernum], &to->cmd, true); - cl.onground = onground; + cl.viewstate.onground = onground; if (to->senttime >= cl.time) break; from = to; diff --git a/qw/source/cl_view.c b/qw/source/cl_view.c index 0e9162ca8..0da8c09cc 100644 --- a/qw/source/cl_view.c +++ b/qw/source/cl_view.c @@ -126,7 +126,7 @@ V_CalcBob (void) if (cl.spectator) return 0; - if (cl.onground == -1) + if (cl.viewstate.onground == -1) return bob; // just use old value bobtime += cl.viewstate.frametime; @@ -672,7 +672,7 @@ V_CalcRefdef (void) r_data->refdef->viewrotation); // smooth out stair step ups - if ((cl.onground != -1) && (origin[2] - oldz > 0)) { + if ((cl.viewstate.onground != -1) && (origin[2] - oldz > 0)) { float steptime; steptime = cl.viewstate.frametime; From dc7cb97481a96319462b2e42bde1dac6eaf32ef1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 20 Mar 2021 01:48:26 +0900 Subject: [PATCH 407/435] [qw] Remove viewangles from client state Other than the one line in cl_pred.c, it's redundant, but it looks to be just a redundant copy from ancient times. --- nq/source/cl_input.c | 3 ++- qw/include/client.h | 6 ++---- qw/source/cl_cam.c | 14 ++++++------- qw/source/cl_demo.c | 4 ++-- qw/source/cl_ents.c | 4 ++-- qw/source/cl_input.c | 49 ++++++++++++++++++++++++-------------------- qw/source/cl_main.c | 16 +++++++-------- qw/source/cl_parse.c | 4 ++-- qw/source/cl_pred.c | 2 +- 9 files changed, 53 insertions(+), 49 deletions(-) diff --git a/nq/source/cl_input.c b/nq/source/cl_input.c index 291f0ecac..5d471afaf 100644 --- a/nq/source/cl_input.c +++ b/nq/source/cl_input.c @@ -477,8 +477,9 @@ CL_AdjustAngles (void) void CL_BaseMove (usercmd_t *cmd) { - if (cls.state != ca_active) + if (cls.state != ca_active) { return; + } CL_AdjustAngles (); diff --git a/qw/include/client.h b/qw/include/client.h index f3e12fced..9f282717c 100644 --- a/qw/include/client.h +++ b/qw/include/client.h @@ -216,13 +216,11 @@ typedef struct { cshift_t cshifts[NUM_CSHIFTS]; // Color shifts for damage, powerups cshift_t prev_cshifts[NUM_CSHIFTS]; // and content types -// the client maintains its own idea of view angles, which are sent to the -// server each frame. And reset only at level change and teleport times - vec3_t viewangles; - // the client simulates or interpolates movement to get these values double time; // this is the time value that the client // is rendering at. always <= realtime +// the client maintains its own idea of view angles, which are sent to the +// server each frame. And reset only at level change and teleport times viewstate_t viewstate; // pitch drifting vars float idealpitch; diff --git a/qw/source/cl_cam.c b/qw/source/cl_cam.c index 1b1959f13..383bc313a 100644 --- a/qw/source/cl_cam.c +++ b/qw/source/cl_cam.c @@ -439,7 +439,7 @@ Cam_Track (usercmd_t *cmd) if (cl_chasecam->int_val) { cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; - VectorCopy (player->viewangles, cl.viewangles); + VectorCopy (player->viewangles, cl.viewstate.angles); VectorCopy (player->pls.es.origin, desired_position); if (memcmp (&desired_position, &self->pls.es.origin, sizeof (desired_position)) != 0) { @@ -468,8 +468,8 @@ Cam_Track (usercmd_t *cmd) VectorCopy (desired_position, self->pls.es.origin); VectorSubtract (player->pls.es.origin, desired_position, vec); - vectoangles (vec, cl.viewangles); - cl.viewangles[0] = -cl.viewangles[0]; + vectoangles (vec, cl.viewstate.angles); + cl.viewstate.angles[0] = -cl.viewstate.angles[0]; } } @@ -536,8 +536,8 @@ Cam_SetView (void) adjustang (cam_viewangles[YAW], vec2[YAW], cl_camera_maxyaw->value); } - VectorCopy (cam_viewangles, cl.viewangles); - VectorCopy (cl.viewangles, cl.simangles); + VectorCopy (cam_viewangles, cl.viewstate.angles); + VectorCopy (cl.viewstate.angles, cl.simangles); cl.simangles[ROLL] = 0; // FIXME @@@ } #endif @@ -576,7 +576,7 @@ Cam_FinishMove (usercmd_t *cmd) adjustang (cam_viewangles[YAW], vec2[YAW], cl_camera_maxyaw->value); } - VectorCopy (cam_viewangles, cl.viewangles); + VectorCopy (cam_viewangles, cl.viewstate.angles); } #endif @@ -587,7 +587,7 @@ Cam_FinishMove (usercmd_t *cmd) if (autocam > CAM_TRACK) { Cam_Unlock (); - VectorCopy (cl.viewangles, cmd->angles); + VectorCopy (cl.viewstate.angles, cmd->angles); return; } } else diff --git a/qw/source/cl_demo.c b/qw/source/cl_demo.c index 7503f5c2a..df54decd7 100644 --- a/qw/source/cl_demo.c +++ b/qw/source/cl_demo.c @@ -333,7 +333,7 @@ nextdemomessage: cls.netchan.outgoing_sequence++; for (i = 0; i < 3; i++) { Qread (cls.demofile, &f, 4); - cl.viewangles[i] = LittleFloat (f); + cl.viewstate.angles[i] = LittleFloat (f); } break; @@ -462,7 +462,7 @@ CL_WriteDemoCmd (usercmd_t *pcmd) Qwrite (cls.demofile, &cmd, sizeof (cmd)); for (i = 0; i < 3; i++) { - fl = LittleFloat (cl.viewangles[i]); + fl = LittleFloat (cl.viewstate.angles[i]); Qwrite (cls.demofile, &fl, 4); } diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 26e25ad25..9da38dc9c 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -425,8 +425,8 @@ CL_LinkPlayers (void) // angles if (j == cl.playernum) { - ang[PITCH] = -cl.viewangles[PITCH] / 3.0; - ang[YAW] = cl.viewangles[YAW]; + ang[PITCH] = -cl.viewstate.angles[PITCH] / 3.0; + ang[YAW] = cl.viewstate.angles[YAW]; } else { ang[PITCH] = -state->viewangles[PITCH] / 3.0; ang[YAW] = state->viewangles[YAW]; diff --git a/qw/source/cl_input.c b/qw/source/cl_input.c index 9b9763d46..7371c06cc 100644 --- a/qw/source/cl_input.c +++ b/qw/source/cl_input.c @@ -454,35 +454,35 @@ CL_AdjustAngles (void) yawspeed *= host_frametime; if (!(in_strafe.state & 1)) { - cl.viewangles[YAW] -= yawspeed * CL_KeyState (&in_right); - cl.viewangles[YAW] += yawspeed * CL_KeyState (&in_left); - cl.viewangles[YAW] = anglemod (cl.viewangles[YAW]); + cl.viewstate.angles[YAW] -= yawspeed * CL_KeyState (&in_right); + cl.viewstate.angles[YAW] += yawspeed * CL_KeyState (&in_left); + cl.viewstate.angles[YAW] = anglemod (cl.viewstate.angles[YAW]); } if (in_klook.state & 1) { V_StopPitchDrift (); - cl.viewangles[PITCH] -= pitchspeed * CL_KeyState (&in_forward); - cl.viewangles[PITCH] += pitchspeed * CL_KeyState (&in_back); + cl.viewstate.angles[PITCH] -= pitchspeed * CL_KeyState (&in_forward); + cl.viewstate.angles[PITCH] += pitchspeed * CL_KeyState (&in_back); } up = CL_KeyState (&in_lookup); down = CL_KeyState (&in_lookdown); - cl.viewangles[PITCH] -= pitchspeed * up; - cl.viewangles[PITCH] += pitchspeed * down; + cl.viewstate.angles[PITCH] -= pitchspeed * up; + cl.viewstate.angles[PITCH] += pitchspeed * down; if (up || down) V_StopPitchDrift (); // FIXME: Need to clean up view angle limits - if (cl.viewangles[PITCH] > 80) - cl.viewangles[PITCH] = 80; - if (cl.viewangles[PITCH] < -70) - cl.viewangles[PITCH] = -70; + if (cl.viewstate.angles[PITCH] > 80) + cl.viewstate.angles[PITCH] = 80; + if (cl.viewstate.angles[PITCH] < -70) + cl.viewstate.angles[PITCH] = -70; - if (cl.viewangles[ROLL] > 50) - cl.viewangles[ROLL] = 50; - if (cl.viewangles[ROLL] < -50) - cl.viewangles[ROLL] = -50; + if (cl.viewstate.angles[ROLL] > 50) + cl.viewstate.angles[ROLL] = 50; + if (cl.viewstate.angles[ROLL] < -50) + cl.viewstate.angles[ROLL] = -50; } /* @@ -493,11 +493,15 @@ CL_AdjustAngles (void) void CL_BaseMove (usercmd_t *cmd) { + if (cls.state != ca_active) { + return; + } + CL_AdjustAngles (); memset (cmd, 0, sizeof (*cmd)); - VectorCopy (cl.viewangles, cmd->angles); + VectorCopy (cl.viewstate.angles, cmd->angles); if (in_strafe.state & 1) { cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); @@ -536,7 +540,7 @@ CL_BaseMove (usercmd_t *cmd) vec3_t forward, right, up, f, r; vec3_t dir = {0, 0, 0}; - dir[1] = r_data->refdef->viewangles[1] - cl.viewangles[1]; + dir[1] = r_data->refdef->viewangles[1] - cl.viewstate.angles[1]; AngleVectors (dir, forward, right, up); VectorScale (forward, cmd->forwardmove, f); VectorScale (right, cmd->sidemove, r); @@ -552,12 +556,13 @@ CL_BaseMove (usercmd_t *cmd) cmd->forwardmove += viewdelta.position[2] * m_forward->value; cmd->sidemove += viewdelta.position[0] * m_side->value; cmd->upmove += viewdelta.position[1]; - cl.viewangles[PITCH] += viewdelta.angles[PITCH] * m_pitch->value; - cl.viewangles[YAW] += viewdelta.angles[YAW] * m_yaw->value; - cl.viewangles[ROLL] += viewdelta.angles[ROLL]; + cl.viewstate.angles[PITCH] += viewdelta.angles[PITCH] * m_pitch->value; + cl.viewstate.angles[YAW] += viewdelta.angles[YAW] * m_yaw->value; + cl.viewstate.angles[ROLL] += viewdelta.angles[ROLL]; if (freelook && !(in_strafe.state & 1)) { - cl.viewangles[PITCH] = bound (-70, cl.viewangles[PITCH], 80); + cl.viewstate.angles[PITCH] + = bound (-70, cl.viewstate.angles[PITCH], 80); } } @@ -609,7 +614,7 @@ CL_FinishMove (usercmd_t *cmd) } cmd->msec = ms; - VectorCopy (cl.viewangles, cmd->angles); + VectorCopy (cl.viewstate.angles, cmd->angles); cmd->impulse = in_impulse; in_impulse = 0; diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index cef24d6bd..ba7bfe270 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -1100,7 +1100,7 @@ CL_Download_f (void) static void Force_CenterView_f (void) { - cl.viewangles[PITCH] = 0; + cl.viewstate.angles[PITCH] = 0; } static void @@ -1109,12 +1109,12 @@ CL_PRotate_f (void) if ((cl.fpd & FPD_LIMIT_PITCH) || Cmd_Argc() < 2) return; - cl.viewangles[PITCH] += atoi (Cmd_Argv (1)); + cl.viewstate.angles[PITCH] += atoi (Cmd_Argv (1)); - if (cl.viewangles[PITCH] < -70) - cl.viewangles[PITCH] = -70; - else if (cl.viewangles[PITCH] > 80) - cl.viewangles[PITCH] = 80; + if (cl.viewstate.angles[PITCH] < -70) + cl.viewstate.angles[PITCH] = -70; + else if (cl.viewstate.angles[PITCH] > 80) + cl.viewstate.angles[PITCH] = 80; } static void @@ -1123,8 +1123,8 @@ CL_Rotate_f (void) if ((cl.fpd & FPD_LIMIT_YAW) || Cmd_Argc() < 2) return; - cl.viewangles[YAW] += atoi (Cmd_Argv (1)); - cl.viewangles[YAW] = anglemod (cl.viewangles[YAW]); + cl.viewstate.angles[YAW] += atoi (Cmd_Argv (1)); + cl.viewstate.angles[YAW] = anglemod (cl.viewstate.angles[YAW]); } void diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index b53c2beb9..b7a293f28 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -1273,7 +1273,7 @@ CL_ParseMuzzleFlash (void) pl = &cl.frames[parsecountmod].playerstate[i - 1]; if (i - 1 == cl.playernum) - AngleVectors (cl.viewangles, f, r, u); + AngleVectors (cl.viewstate.angles, f, r, u); else AngleVectors (pl->viewangles, f, r, u); @@ -1415,7 +1415,7 @@ CL_ParseServerMessage (void) case svc_setangle: { - vec_t *dest = cl.viewangles; + vec_t *dest = cl.viewstate.angles; vec3_t dummy; if (cls.demoplayback2) { diff --git a/qw/source/cl_pred.c b/qw/source/cl_pred.c index 58ee4a144..40f9f1459 100644 --- a/qw/source/cl_pred.c +++ b/qw/source/cl_pred.c @@ -132,7 +132,7 @@ CL_PredictMove (void) UPDATE_BACKUP - 1) return; - VectorCopy (cl.viewangles, cl.viewstate.angles); + //VectorCopy (cl.viewstate.angles, cl.viewstate.angles); cl.viewstate.angles[ROLL] = 0; // FIXME @@@ // this is the last frame received from the server From 0ace799b277a16d9269ac8f0fcde60f8b28630a7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 20 Mar 2021 03:56:16 +0900 Subject: [PATCH 408/435] [util] Support commands with a data parameter Useful for avoiding a pile of wrapper functions that merely pass on command-specific data to the actual implementation. Used to clean up the wrappers in nq and qw cl_input.c --- include/QF/cmd.h | 8 +- libs/util/cmd.c | 29 +++- nq/source/cl_input.c | 362 +++++++++++-------------------------------- qw/source/cl_input.c | 362 +++++++++++-------------------------------- 4 files changed, 207 insertions(+), 554 deletions(-) diff --git a/include/QF/cmd.h b/include/QF/cmd.h index 35846a063..3cd74432b 100644 --- a/include/QF/cmd.h +++ b/include/QF/cmd.h @@ -37,6 +37,7 @@ #include "QF/cbuf.h" typedef void (*xcommand_t) (void); +typedef void (*xdatacmd_t) (void *data); typedef enum { src_client, // came in over a net connection as a clc_stringcmd @@ -48,6 +49,8 @@ typedef struct cmd_function_s { struct cmd_function_s *next; const char *name; xcommand_t function; + xdatacmd_t datafunc; + void *data; const char *description; } cmd_function_t; @@ -56,7 +59,10 @@ extern cmd_source_t cmd_source; void Cmd_Init_Hash (void); void Cmd_Init (void); -int Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *description); +int Cmd_AddCommand (const char *cmd_name, xcommand_t function, + const char *description); +int Cmd_AddDataCommand (const char *cmd_name, xdatacmd_t function, + void *data, const char *description); int Cmd_RemoveCommand (const char *cmd_name); qboolean Cmd_Exists (const char *cmd_name); diff --git a/libs/util/cmd.c b/libs/util/cmd.c index aede64982..812fb55b6 100644 --- a/libs/util/cmd.c +++ b/libs/util/cmd.c @@ -118,6 +118,8 @@ Cmd_Command (cbuf_args_t *args) if (cmd) { if (cmd->function) { cmd->function (); + } else if (cmd->datafunc) { + cmd->datafunc (cmd->data); } return 0; } @@ -133,10 +135,9 @@ Cmd_Command (cbuf_args_t *args) return 0; } -/* Registers a command and handler function */ -VISIBLE int -Cmd_AddCommand (const char *cmd_name, xcommand_t function, - const char *description) +static int +add_command (const char *cmd_name, xcommand_t func, xdatacmd_t datafunc, + void *data, const char *description) { cmd_function_t *cmd; cmd_function_t **c; @@ -152,7 +153,9 @@ Cmd_AddCommand (const char *cmd_name, xcommand_t function, cmd = calloc (1, sizeof (cmd_function_t)); SYS_CHECKMEM (cmd); cmd->name = cmd_name; - cmd->function = function; + cmd->function = func; + cmd->datafunc = datafunc; + cmd->data = data; cmd->description = description; Hash_Add (cmd_hash, cmd); for (c = &cmd_functions; *c; c = &(*c)->next) @@ -163,6 +166,22 @@ Cmd_AddCommand (const char *cmd_name, xcommand_t function, return 1; } +/* Registers a command and handler function */ +VISIBLE int +Cmd_AddCommand (const char *cmd_name, xcommand_t function, + const char *description) +{ + return add_command (cmd_name, function, 0, 0, description); +} + +/* Registers a command and handler function with data */ +VISIBLE int +Cmd_AddDataCommand (const char *cmd_name, xdatacmd_t function, + void *data, const char *description) +{ + return add_command (cmd_name, 0, function, data, description); +} + /* Unregisters a command */ VISIBLE int Cmd_RemoveCommand (const char *name) diff --git a/nq/source/cl_input.c b/nq/source/cl_input.c index 5d471afaf..58787e7e7 100644 --- a/nq/source/cl_input.c +++ b/nq/source/cl_input.c @@ -77,8 +77,9 @@ int in_impulse; void (*write_angles) (sizebuf_t *sb, const vec3_t angles); static void -KeyPress (kbutton_t *b) +KeyPress (void *_b) { + kbutton_t *b = _b; const char *c; int k; @@ -107,8 +108,9 @@ KeyPress (kbutton_t *b) } static void -KeyRelease (kbutton_t *b) +KeyRelease (void *_b) { + kbutton_t *b = _b; const char *c; int k; @@ -141,25 +143,7 @@ KeyRelease (kbutton_t *b) } static void -IN_KLookPress (void) -{ - KeyPress (&in_klook); -} - -static void -IN_KLookRelease (void) -{ - KeyRelease (&in_klook); -} - -static void -IN_MLookPress (void) -{ - KeyPress (&in_mlook); -} - -static void -IN_MLookRelease (void) +IN_MLookRelease (void *data) { KeyRelease (&in_mlook); if (!freelook && lookspring->int_val) @@ -167,187 +151,7 @@ IN_MLookRelease (void) } static void -IN_UpPress (void) -{ - KeyPress (&in_up); -} - -static void -IN_UpRelease (void) -{ - KeyRelease (&in_up); -} - -static void -IN_DownPress (void) -{ - KeyPress (&in_down); -} - -static void -IN_DownRelease (void) -{ - KeyRelease (&in_down); -} - -static void -IN_LeftPress (void) -{ - KeyPress (&in_left); -} - -static void -IN_LeftRelease (void) -{ - KeyRelease (&in_left); -} - -static void -IN_RightPress (void) -{ - KeyPress (&in_right); -} - -static void -IN_RightRelease (void) -{ - KeyRelease (&in_right); -} - -static void -IN_ForwardPress (void) -{ - KeyPress (&in_forward); -} - -static void -IN_ForwardRelease (void) -{ - KeyRelease (&in_forward); -} - -static void -IN_BackPress (void) -{ - KeyPress (&in_back); -} - -static void -IN_BackRelease (void) -{ - KeyRelease (&in_back); -} - -static void -IN_LookupPress (void) -{ - KeyPress (&in_lookup); -} - -static void -IN_LookupRelease (void) -{ - KeyRelease (&in_lookup); -} - -static void -IN_LookdownPress (void) -{ - KeyPress (&in_lookdown); -} - -static void -IN_LookdownRelease (void) -{ - KeyRelease (&in_lookdown); -} - -static void -IN_MoveleftPress (void) -{ - KeyPress (&in_moveleft); -} - -static void -IN_MoveleftRelease (void) -{ - KeyRelease (&in_moveleft); -} - -static void -IN_MoverightPress (void) -{ - KeyPress (&in_moveright); -} - -static void -IN_MoverightRelease (void) -{ - KeyRelease (&in_moveright); -} - -static void -IN_SpeedPress (void) -{ - KeyPress (&in_speed); -} - -static void -IN_SpeedRelease (void) -{ - KeyRelease (&in_speed); -} - -static void -IN_StrafePress (void) -{ - KeyPress (&in_strafe); -} - -static void -IN_StrafeRelease (void) -{ - KeyRelease (&in_strafe); -} - -static void -IN_AttackPress (void) -{ - KeyPress (&in_attack); -} - -static void -IN_AttackRelease (void) -{ - KeyRelease (&in_attack); -} - -static void -IN_UsePress (void) -{ - KeyPress (&in_use); -} - -static void -IN_UseRelease (void) -{ - KeyRelease (&in_use); -} - -static void -IN_JumpPress (void) -{ - KeyPress (&in_jump); -} - -static void -IN_JumpRelease (void) -{ - KeyRelease (&in_jump); -} - -static void -IN_Impulse (void) +IN_Impulse (void *data) { in_impulse = atoi (Cmd_Argv (1)); } @@ -608,76 +412,86 @@ CL_SendMove (usercmd_t *cmd) void CL_Input_Init (void) { - Cmd_AddCommand ("+moveup", IN_UpPress, "When active the player is " - "swimming up in a liquid"); - Cmd_AddCommand ("-moveup", IN_UpRelease, "When active the player is not " - "swimming up in a liquid"); - Cmd_AddCommand ("+movedown", IN_DownPress, "When active the player is " - "swimming down in a liquid"); - Cmd_AddCommand ("-movedown", IN_DownRelease, "When active the player is " - "not swimming down in a liquid"); - Cmd_AddCommand ("+left", IN_LeftPress, "When active the player is turning " - "left"); - Cmd_AddCommand ("-left", IN_LeftRelease, "When active the player is not " - "turning left"); - Cmd_AddCommand ("+right", IN_RightPress, "When active the player is " - "turning right"); - Cmd_AddCommand ("-right", IN_RightRelease, "When active the player is not " - "turning right"); - Cmd_AddCommand ("+forward", IN_ForwardPress, "When active the player is " - "moving forward"); - Cmd_AddCommand ("-forward", IN_ForwardRelease, "When active the player is " - "not moving forward"); - Cmd_AddCommand ("+back", IN_BackPress, "When active the player is moving " - "backwards"); - Cmd_AddCommand ("-back", IN_BackRelease, "When active the player is not " - "moving backwards"); - Cmd_AddCommand ("+lookup", IN_LookupPress, "When active the player's view " - "is looking up"); - Cmd_AddCommand ("-lookup", IN_LookupRelease, "When active the player's " - "view is not looking up"); - Cmd_AddCommand ("+lookdown", IN_LookdownPress, "When active the player's " - "view is looking down"); - Cmd_AddCommand ("-lookdown", IN_LookdownRelease, "When active the " - "player's view is not looking up"); - Cmd_AddCommand ("+strafe", IN_StrafePress, "When active, +left and +right " - "function like +moveleft and +moveright"); - Cmd_AddCommand ("-strafe", IN_StrafeRelease, "When active, +left and " - "+right stop functioning like +moveleft and +moveright"); - Cmd_AddCommand ("+moveleft", IN_MoveleftPress, "When active the player is " - "strafing left"); - Cmd_AddCommand ("-moveleft", IN_MoveleftRelease, "When active the player " - "is not strafing left"); - Cmd_AddCommand ("+moveright", IN_MoverightPress, "When active the player " - "is strafing right"); - Cmd_AddCommand ("-moveright", IN_MoverightRelease, "When active the " - "player is not strafing right"); - Cmd_AddCommand ("+speed", IN_SpeedPress, "When active the player is " - "running"); - Cmd_AddCommand ("-speed", IN_SpeedRelease, "When active the player is not " - "running"); - Cmd_AddCommand ("+attack", IN_AttackPress, "When active player is " - "firing/using current weapon"); - Cmd_AddCommand ("-attack", IN_AttackRelease, "When active player is not " - "firing/using current weapon"); - Cmd_AddCommand ("+use", IN_UsePress, "Non-functional. Left over command " - "for opening doors and triggering switches"); - Cmd_AddCommand ("-use", IN_UseRelease, "Non-functional. Left over command " - "for opening doors and triggering switches"); - Cmd_AddCommand ("+jump", IN_JumpPress, "When active the player is " - "jumping"); - Cmd_AddCommand ("-jump", IN_JumpRelease, "When active the player is not " - "jumping"); - Cmd_AddCommand ("impulse", IN_Impulse, "Call a game function or QuakeC " - "function."); - Cmd_AddCommand ("+klook", IN_KLookPress, "When active, +forward and +back " - "perform +lookup and +lookdown"); - Cmd_AddCommand ("-klook", IN_KLookRelease, "When active, +forward and " - "+back don't perform +lookup and +lookdown"); - Cmd_AddCommand ("+mlook", IN_MLookPress, "When active moving the mouse or " - "joystick forwards and backwards performs +lookup and " - "+lookdown"); - Cmd_AddCommand ("-mlook", IN_MLookRelease, "When active moving the mouse " - "or joystick forwards and backwards doesn't perform " - "+lookup and +lookdown"); + Cmd_AddDataCommand ("+moveup", KeyPress, &in_up, + "When active the player is swimming up in a liquid"); + Cmd_AddDataCommand ("-moveup", KeyRelease, &in_up, + "When active the player is not swimming up in a " + "liquid"); + Cmd_AddDataCommand ("+movedown", KeyPress, &in_down, + "When active the player is swimming down in a liquid"); + Cmd_AddDataCommand ("-movedown", KeyRelease, &in_down, + "When active the player is not swimming down in a " + "liquid"); + Cmd_AddDataCommand ("+left", KeyPress, &in_left, + "When active the player is turning left"); + Cmd_AddDataCommand ("-left", KeyRelease, &in_left, + "When active the player is not turning left"); + Cmd_AddDataCommand ("+right", KeyPress, &in_right, + "When active the player is turning right"); + Cmd_AddDataCommand ("-right", KeyRelease, &in_right, + "When active the player is not turning right"); + Cmd_AddDataCommand ("+forward", KeyPress, &in_forward, + "When active the player is moving forward"); + Cmd_AddDataCommand ("-forward", KeyRelease, &in_forward, + "When active the player is not moving forward"); + Cmd_AddDataCommand ("+back", KeyPress, &in_back, + "When active the player is moving backwards"); + Cmd_AddDataCommand ("-back", KeyRelease, &in_back, + "When active the player is not moving backwards"); + Cmd_AddDataCommand ("+lookup", KeyPress, &in_lookup, + "When active the player's view is looking up"); + Cmd_AddDataCommand ("-lookup", KeyRelease, &in_lookup, + "When active the player's view is not looking up"); + Cmd_AddDataCommand ("+lookdown", KeyPress, &in_lookdown, + "When active the player's view is looking down"); + Cmd_AddDataCommand ("-lookdown", KeyRelease, &in_lookdown, + "When active the player's view is not looking up"); + Cmd_AddDataCommand ("+strafe", KeyPress, &in_strafe, + "When active, +left and +right function like " + "+moveleft and +moveright"); + Cmd_AddDataCommand ("-strafe", KeyRelease, &in_strafe, + "When active, +left and +right stop functioning like " + "+moveleft and +moveright"); + Cmd_AddDataCommand ("+moveleft", KeyPress, &in_moveleft, + "When active the player is strafing left"); + Cmd_AddDataCommand ("-moveleft", KeyRelease, &in_moveleft, + "When active the player is not strafing left"); + Cmd_AddDataCommand ("+moveright", KeyPress, &in_moveright, + "When active the player is strafing right"); + Cmd_AddDataCommand ("-moveright", KeyRelease, &in_moveright, + "When active the player is not strafing right"); + Cmd_AddDataCommand ("+speed", KeyPress, &in_speed, + "When active the player is running"); + Cmd_AddDataCommand ("-speed", KeyRelease, &in_speed, + "When active the player is not running"); + Cmd_AddDataCommand ("+attack", KeyPress, &in_attack, + "When active player is firing/using current weapon"); + Cmd_AddDataCommand ("-attack", KeyRelease, &in_attack, + "When active player is not firing/using current " + "weapon"); + Cmd_AddDataCommand ("+use", KeyPress, &in_use, + "Non-functional. Left over command for opening doors " + "and triggering switches"); + Cmd_AddDataCommand ("-use", KeyRelease, &in_use, + "Non-functional. Left over command for opening doors " + "and triggering switches"); + Cmd_AddDataCommand ("+jump", KeyPress, &in_jump, + "When active the player is jumping"); + Cmd_AddDataCommand ("-jump", KeyRelease, &in_jump, + "When active the player is not jumping"); + Cmd_AddDataCommand ("impulse", IN_Impulse, 0, + "Call a game function or QuakeC function."); + Cmd_AddDataCommand ("+klook", KeyPress, &in_klook, + "When active, +forward and +back perform +lookup and " + "+lookdown"); + Cmd_AddDataCommand ("-klook", KeyRelease, &in_klook, + "When active, +forward and +back don't perform " + "+lookup and +lookdown"); + Cmd_AddDataCommand ("+mlook", KeyPress, &in_mlook, + "When active moving the mouse or joystick forwards " + "and backwards performs +lookup and " + "+lookdown"); + Cmd_AddDataCommand ("-mlook", IN_MLookRelease, &in_mlook, + "When active moving the mouse or joystick forwards " + "and backwards doesn't perform +lookup and +lookdown"); } diff --git a/qw/source/cl_input.c b/qw/source/cl_input.c index 7371c06cc..770e16358 100644 --- a/qw/source/cl_input.c +++ b/qw/source/cl_input.c @@ -89,8 +89,9 @@ int in_impulse; static void -KeyPress (kbutton_t *b) +KeyPress (void *_b) { + kbutton_t *b = _b; const char *c; int k; @@ -119,8 +120,9 @@ KeyPress (kbutton_t *b) } static void -KeyRelease (kbutton_t *b) +KeyRelease (void *_b) { + kbutton_t *b = _b; const char *c; int k; @@ -153,25 +155,7 @@ KeyRelease (kbutton_t *b) } static void -IN_KLookPress (void) -{ - KeyPress (&in_klook); -} - -static void -IN_KLookRelease (void) -{ - KeyRelease (&in_klook); -} - -static void -IN_MLookPress (void) -{ - KeyPress (&in_mlook); -} - -static void -IN_MLookRelease (void) +IN_MLookRelease (void *data) { KeyRelease (&in_mlook); if (!freelook && lookspring->int_val) @@ -179,187 +163,7 @@ IN_MLookRelease (void) } static void -IN_UpPress (void) -{ - KeyPress (&in_up); -} - -static void -IN_UpRelease (void) -{ - KeyRelease (&in_up); -} - -static void -IN_DownPress (void) -{ - KeyPress (&in_down); -} - -static void -IN_DownRelease (void) -{ - KeyRelease (&in_down); -} - -static void -IN_LeftPress (void) -{ - KeyPress (&in_left); -} - -static void -IN_LeftRelease (void) -{ - KeyRelease (&in_left); -} - -static void -IN_RightPress (void) -{ - KeyPress (&in_right); -} - -static void -IN_RightRelease (void) -{ - KeyRelease (&in_right); -} - -static void -IN_ForwardPress (void) -{ - KeyPress (&in_forward); -} - -static void -IN_ForwardRelease (void) -{ - KeyRelease (&in_forward); -} - -static void -IN_BackPress (void) -{ - KeyPress (&in_back); -} - -static void -IN_BackRelease (void) -{ - KeyRelease (&in_back); -} - -static void -IN_LookupPress (void) -{ - KeyPress (&in_lookup); -} - -static void -IN_LookupRelease (void) -{ - KeyRelease (&in_lookup); -} - -static void -IN_LookdownPress (void) -{ - KeyPress (&in_lookdown); -} - -static void -IN_LookdownRelease (void) -{ - KeyRelease (&in_lookdown); -} - -static void -IN_MoveleftPress (void) -{ - KeyPress (&in_moveleft); -} - -static void -IN_MoveleftRelease (void) -{ - KeyRelease (&in_moveleft); -} - -static void -IN_MoverightPress (void) -{ - KeyPress (&in_moveright); -} - -static void -IN_MoverightRelease (void) -{ - KeyRelease (&in_moveright); -} - -static void -IN_SpeedPress (void) -{ - KeyPress (&in_speed); -} - -static void -IN_SpeedRelease (void) -{ - KeyRelease (&in_speed); -} - -static void -IN_StrafePress (void) -{ - KeyPress (&in_strafe); -} - -static void -IN_StrafeRelease (void) -{ - KeyRelease (&in_strafe); -} - -static void -IN_AttackPress (void) -{ - KeyPress (&in_attack); -} - -static void -IN_AttackRelease (void) -{ - KeyRelease (&in_attack); -} - -static void -IN_UsePress (void) -{ - KeyPress (&in_use); -} - -static void -IN_UseRelease (void) -{ - KeyRelease (&in_use); -} - -static void -IN_JumpPress (void) -{ - KeyPress (&in_jump); -} - -static void -IN_JumpRelease (void) -{ - KeyRelease (&in_jump); -} - -static void -IN_Impulse (void) +IN_Impulse (void *data) { in_impulse = atoi (Cmd_Argv (1)); if (Cmd_Argc () <= 2) @@ -772,78 +576,88 @@ CL_SendCmd (void) void CL_Input_Init (void) { - Cmd_AddCommand ("+moveup", IN_UpPress, "When active the player is " - "swimming up in a liquid"); - Cmd_AddCommand ("-moveup", IN_UpRelease, "When active the player is not " - "swimming up in a liquid"); - Cmd_AddCommand ("+movedown", IN_DownPress, "When active the player is " - "swimming down in a liquid"); - Cmd_AddCommand ("-movedown", IN_DownRelease, "When active the player is " - "not swimming down in a liquid"); - Cmd_AddCommand ("+left", IN_LeftPress, "When active the player is turning " - "left"); - Cmd_AddCommand ("-left", IN_LeftRelease, "When active the player is not " - "turning left"); - Cmd_AddCommand ("+right", IN_RightPress, "When active the player is " - "turning right"); - Cmd_AddCommand ("-right", IN_RightRelease, "When active the player is not " - "turning right"); - Cmd_AddCommand ("+forward", IN_ForwardPress, "When active the player is " - "moving forward"); - Cmd_AddCommand ("-forward", IN_ForwardRelease, "When active the player is " - "not moving forward"); - Cmd_AddCommand ("+back", IN_BackPress, "When active the player is moving " - "backwards"); - Cmd_AddCommand ("-back", IN_BackRelease, "When active the player is not " - "moving backwards"); - Cmd_AddCommand ("+lookup", IN_LookupPress, "When active the player's view " - "is looking up"); - Cmd_AddCommand ("-lookup", IN_LookupRelease, "When active the player's " - "view is not looking up"); - Cmd_AddCommand ("+lookdown", IN_LookdownPress, "When active the player's " - "view is looking down"); - Cmd_AddCommand ("-lookdown", IN_LookdownRelease, "When active the " - "player's view is not looking up"); - Cmd_AddCommand ("+strafe", IN_StrafePress, "When active, +left and +right " - "function like +moveleft and +moveright"); - Cmd_AddCommand ("-strafe", IN_StrafeRelease, "When active, +left and " - "+right stop functioning like +moveleft and +moveright"); - Cmd_AddCommand ("+moveleft", IN_MoveleftPress, "When active the player is " - "strafing left"); - Cmd_AddCommand ("-moveleft", IN_MoveleftRelease, "When active the player " - "is not strafing left"); - Cmd_AddCommand ("+moveright", IN_MoverightPress, "When active the player " - "is strafing right"); - Cmd_AddCommand ("-moveright", IN_MoverightRelease, "When active the " - "player is not strafing right"); - Cmd_AddCommand ("+speed", IN_SpeedPress, "When active the player is " - "running"); - Cmd_AddCommand ("-speed", IN_SpeedRelease, "When active the player is not " - "running"); - Cmd_AddCommand ("+attack", IN_AttackPress, "When active player is " - "firing/using current weapon"); - Cmd_AddCommand ("-attack", IN_AttackRelease, "When active player is not " - "firing/using current weapon"); - Cmd_AddCommand ("+use", IN_UsePress, "Non-functional. Left over command " - "for opening doors and triggering switches"); - Cmd_AddCommand ("-use", IN_UseRelease, "Non-functional. Left over command " - "for opening doors and triggering switches"); - Cmd_AddCommand ("+jump", IN_JumpPress, "When active the player is " - "jumping"); - Cmd_AddCommand ("-jump", IN_JumpRelease, "When active the player is not " - "jumping"); - Cmd_AddCommand ("impulse", IN_Impulse, "Call a game function or QuakeC " - "function."); - Cmd_AddCommand ("+klook", IN_KLookPress, "When active, +forward and +back " - "perform +lookup and +lookdown"); - Cmd_AddCommand ("-klook", IN_KLookRelease, "When active, +forward and " - "+back don't perform +lookup and +lookdown"); - Cmd_AddCommand ("+mlook", IN_MLookPress, "When active moving the mouse or " - "joystick forwards and backwards performs +lookup and " - "+lookdown"); - Cmd_AddCommand ("-mlook", IN_MLookRelease, "When active moving the mouse " - "or joystick forwards and backwards doesn't perform " - "+lookup and +lookdown"); + Cmd_AddDataCommand ("+moveup", KeyPress, &in_up, + "When active the player is swimming up in a liquid"); + Cmd_AddDataCommand ("-moveup", KeyRelease, &in_up, + "When active the player is not swimming up in a " + "liquid"); + Cmd_AddDataCommand ("+movedown", KeyPress, &in_down, + "When active the player is swimming down in a liquid"); + Cmd_AddDataCommand ("-movedown", KeyRelease, &in_down, + "When active the player is not swimming down in a " + "liquid"); + Cmd_AddDataCommand ("+left", KeyPress, &in_left, + "When active the player is turning left"); + Cmd_AddDataCommand ("-left", KeyRelease, &in_left, + "When active the player is not turning left"); + Cmd_AddDataCommand ("+right", KeyPress, &in_right, + "When active the player is turning right"); + Cmd_AddDataCommand ("-right", KeyRelease, &in_right, + "When active the player is not turning right"); + Cmd_AddDataCommand ("+forward", KeyPress, &in_forward, + "When active the player is moving forward"); + Cmd_AddDataCommand ("-forward", KeyRelease, &in_forward, + "When active the player is not moving forward"); + Cmd_AddDataCommand ("+back", KeyPress, &in_back, + "When active the player is moving backwards"); + Cmd_AddDataCommand ("-back", KeyRelease, &in_back, + "When active the player is not moving backwards"); + Cmd_AddDataCommand ("+lookup", KeyPress, &in_lookup, + "When active the player's view is looking up"); + Cmd_AddDataCommand ("-lookup", KeyRelease, &in_lookup, + "When active the player's view is not looking up"); + Cmd_AddDataCommand ("+lookdown", KeyPress, &in_lookdown, + "When active the player's view is looking down"); + Cmd_AddDataCommand ("-lookdown", KeyRelease, &in_lookdown, + "When active the player's view is not looking up"); + Cmd_AddDataCommand ("+strafe", KeyPress, &in_strafe, + "When active, +left and +right function like " + "+moveleft and +moveright"); + Cmd_AddDataCommand ("-strafe", KeyRelease, &in_strafe, + "When active, +left and +right stop functioning like " + "+moveleft and +moveright"); + Cmd_AddDataCommand ("+moveleft", KeyPress, &in_moveleft, + "When active the player is strafing left"); + Cmd_AddDataCommand ("-moveleft", KeyRelease, &in_moveleft, + "When active the player is not strafing left"); + Cmd_AddDataCommand ("+moveright", KeyPress, &in_moveright, + "When active the player is strafing right"); + Cmd_AddDataCommand ("-moveright", KeyRelease, &in_moveright, + "When active the player is not strafing right"); + Cmd_AddDataCommand ("+speed", KeyPress, &in_speed, + "When active the player is running"); + Cmd_AddDataCommand ("-speed", KeyRelease, &in_speed, + "When active the player is not running"); + Cmd_AddDataCommand ("+attack", KeyPress, &in_attack, + "When active player is firing/using current weapon"); + Cmd_AddDataCommand ("-attack", KeyRelease, &in_attack, + "When active player is not firing/using current " + "weapon"); + Cmd_AddDataCommand ("+use", KeyPress, &in_use, + "Non-functional. Left over command for opening doors " + "and triggering switches"); + Cmd_AddDataCommand ("-use", KeyRelease, &in_use, + "Non-functional. Left over command for opening doors " + "and triggering switches"); + Cmd_AddDataCommand ("+jump", KeyPress, &in_jump, + "When active the player is jumping"); + Cmd_AddDataCommand ("-jump", KeyRelease, &in_jump, + "When active the player is not jumping"); + Cmd_AddDataCommand ("impulse", IN_Impulse, 0, + "Call a game function or QuakeC function."); + Cmd_AddDataCommand ("+klook", KeyPress, &in_klook, + "When active, +forward and +back perform +lookup and " + "+lookdown"); + Cmd_AddDataCommand ("-klook", KeyRelease, &in_klook, + "When active, +forward and +back don't perform " + "+lookup and +lookdown"); + Cmd_AddDataCommand ("+mlook", KeyPress, &in_mlook, + "When active moving the mouse or joystick forwards " + "and backwards performs +lookup and " + "+lookdown"); + Cmd_AddDataCommand ("-mlook", IN_MLookRelease, &in_mlook, + "When active moving the mouse or joystick forwards " + "and backwards doesn't perform +lookup and +lookdown"); } void From e3444b726f8f4ecd5320a793481e0c1e653f6c54 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 20 Mar 2021 12:00:40 +0900 Subject: [PATCH 409/435] [model] Add a re-entrant Mod_LeafPVS Double benefit, actually: faster when building a fat PVS (don't need to copy as much) and can be used in multiple threads. Also, default visiblity can be set, and the buffer size has its own macro. --- include/QF/bspfile.h | 2 ++ include/QF/model.h | 7 ++++++- libs/models/brush/model_brush.c | 36 +++++++++++++++++++++------------ nq/source/sv_main.c | 2 +- nq/source/sv_pr_cmds.c | 2 +- qw/source/sv_ents.c | 2 +- qw/source/sv_pr_cmds.c | 2 +- tools/qfvis/source/qfvis.c | 2 +- 8 files changed, 36 insertions(+), 19 deletions(-) diff --git a/include/QF/bspfile.h b/include/QF/bspfile.h index 0d32c09e8..27648f297 100644 --- a/include/QF/bspfile.h +++ b/include/QF/bspfile.h @@ -42,6 +42,8 @@ #define MAX_MAP_FACES 65535 // format limit (u16) #define MAX_MAP_MARKSURFACES 65535 // format limit (u16) +#define MAP_PVS_BYTES (MAX_MAP_LEAFS / 8) + //============================================================================= #define BSPVERSION 29 diff --git a/include/QF/model.h b/include/QF/model.h index b65a5ad18..0a7069d3f 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -432,7 +432,12 @@ model_t *Mod_ForName (const char *name, qboolean crash); void Mod_TouchModel (const char *name); // brush specific mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model) __attribute__((pure)); -byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model); +byte *Mod_LeafPVS (const mleaf_t *leaf, const model_t *model); + +// NOTE: the buffer pointed to by out must be at least MAP_PVS_BYTES in size +void Mod_LeafPVS_r (const mleaf_t *leaf, const model_t *model, byte defvis, + byte *out); + void Mod_Print (void); extern struct cvar_s *gl_mesh_cache; diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index b18de9076..6270de72b 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -55,7 +55,7 @@ #include "compat.h" #include "mod_internal.h" -static byte mod_novis[MAX_MAP_LEAFS / 8]; +static byte mod_novis[MAP_PVS_BYTES]; VISIBLE cvar_t *gl_sky_divide; //FIXME visibility? VISIBLE int mod_lightmap_bytes = 1; //FIXME should this be visible? @@ -85,22 +85,21 @@ Mod_PointInLeaf (const vec3_t p, model_t *model) return NULL; // never reached } -static inline byte * -Mod_DecompressVis (byte * in, mod_brush_t *brush) +static inline void +Mod_DecompressVis (const byte *in, const mod_brush_t *brush, byte defvis, + byte *out) { - static byte decompressed[MAX_MAP_LEAFS / 8]; - byte *out; + byte *start = out; int row, c; row = (brush->numleafs + 7) >> 3; - out = decompressed; if (!in) { // no vis info, so make all visible while (row) { - *out++ = 0xff; + *out++ = defvis; row--; } - return decompressed; + return; } do { @@ -115,21 +114,32 @@ Mod_DecompressVis (byte * in, mod_brush_t *brush) *out++ = 0; c--; } - } while (out - decompressed < row); - - return decompressed; + } while (out - start < row); } VISIBLE byte * -Mod_LeafPVS (mleaf_t *leaf, model_t *model) +Mod_LeafPVS (const mleaf_t *leaf, const model_t *model) { + static byte decompressed[MAP_PVS_BYTES]; if (leaf == model->brush.leafs) { if (!mod_novis[0]) { memset (mod_novis, 0xff, sizeof (mod_novis)); } return mod_novis; } - return Mod_DecompressVis (leaf->compressed_vis, &model->brush); + Mod_DecompressVis (leaf->compressed_vis, &model->brush, 0xff, decompressed); + return decompressed; +} + +VISIBLE void +Mod_LeafPVS_r (const mleaf_t *leaf, const model_t *model, byte defvis, + byte *out) +{ + if (leaf == model->brush.leafs) { + memset (out, defvis, sizeof (mod_novis)); + return; + } + return Mod_DecompressVis (leaf->compressed_vis, &model->brush, defvis, out); } // BRUSHMODEL LOADING ========================================================= diff --git a/nq/source/sv_main.c b/nq/source/sv_main.c index d8a98b5b4..7d486f24b 100644 --- a/nq/source/sv_main.c +++ b/nq/source/sv_main.c @@ -389,7 +389,7 @@ SV_ClearDatagram (void) */ int fatbytes; -byte fatpvs[MAX_MAP_LEAFS / 8]; +byte fatpvs[MAP_PVS_BYTES]; static void SV_AddToFatPVS (vec3_t org, mnode_t *node) diff --git a/nq/source/sv_pr_cmds.c b/nq/source/sv_pr_cmds.c index 096010f77..0489b4f4c 100644 --- a/nq/source/sv_pr_cmds.c +++ b/nq/source/sv_pr_cmds.c @@ -539,7 +539,7 @@ PF_checkpos (progs_t *pr) { } -byte checkpvs[MAX_MAP_LEAFS / 8]; +byte checkpvs[MAP_PVS_BYTES]; static int PF_newcheckclient (progs_t *pr, int check) diff --git a/qw/source/sv_ents.c b/qw/source/sv_ents.c index ccbf9278b..5538de54b 100644 --- a/qw/source/sv_ents.c +++ b/qw/source/sv_ents.c @@ -54,7 +54,7 @@ when the bob crosses a waterline. */ -byte fatpvs[MAX_MAP_LEAFS / 8]; +byte fatpvs[MAP_PVS_BYTES]; int fatbytes; diff --git a/qw/source/sv_pr_cmds.c b/qw/source/sv_pr_cmds.c index b8dc58de0..b30664a76 100644 --- a/qw/source/sv_pr_cmds.c +++ b/qw/source/sv_pr_cmds.c @@ -460,7 +460,7 @@ PF_checkpos (progs_t *pr) { } -byte checkpvs[MAX_MAP_LEAFS / 8]; +byte checkpvs[MAP_PVS_BYTES]; static int PF_newcheckclient (progs_t *pr, int check) diff --git a/tools/qfvis/source/qfvis.c b/tools/qfvis/source/qfvis.c index 9ffb09e35..c62eabbcc 100644 --- a/tools/qfvis/source/qfvis.c +++ b/tools/qfvis/source/qfvis.c @@ -613,7 +613,7 @@ void ClusterFlow (int clusternum) { set_t *visclusters; - byte compressed[MAX_MAP_LEAFS / 8]; + byte compressed[MAP_PVS_BYTES]; byte *outbuffer; int numvis, i; cluster_t *cluster; From e0eacf401451860d86a32c3c54190f65d5adb1e1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 20 Mar 2021 16:06:15 +0900 Subject: [PATCH 410/435] [model] Make set and mix versions of Mod_LeafPVS The re-entrant version was a good start, but being able to mix while decompressing saves having to have a temporary buffer somewhere. --- include/QF/model.h | 6 ++-- libs/models/brush/model_brush.c | 57 +++++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/include/QF/model.h b/include/QF/model.h index 0a7069d3f..1c5969820 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -435,8 +435,10 @@ mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model) __attribute__((pure)); byte *Mod_LeafPVS (const mleaf_t *leaf, const model_t *model); // NOTE: the buffer pointed to by out must be at least MAP_PVS_BYTES in size -void Mod_LeafPVS_r (const mleaf_t *leaf, const model_t *model, byte defvis, - byte *out); +void Mod_LeafPVS_set (const mleaf_t *leaf, const model_t *model, byte defvis, + byte *out); +void Mod_LeafPVS_mix (const mleaf_t *leaf, const model_t *model, byte defvis, + byte *out); void Mod_Print (void); diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index 6270de72b..1e2fa81a4 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -86,8 +86,8 @@ Mod_PointInLeaf (const vec3_t p, model_t *model) } static inline void -Mod_DecompressVis (const byte *in, const mod_brush_t *brush, byte defvis, - byte *out) +Mod_DecompressVis_set (const byte *in, const mod_brush_t *brush, byte defvis, + byte *out) { byte *start = out; int row, c; @@ -117,6 +117,35 @@ Mod_DecompressVis (const byte *in, const mod_brush_t *brush, byte defvis, } while (out - start < row); } +static inline void +Mod_DecompressVis_mix (const byte *in, const mod_brush_t *brush, byte defvis, + byte *out) +{ + byte *start = out; + int row, c; + + row = (brush->numleafs + 7) >> 3; + + if (!in) { // no vis info, so make all visible + while (row) { + *out++ |= defvis; + row--; + } + return; + } + + do { + if (*in) { + *out++ |= *in++; + continue; + } + + c = in[1]; + in += 2; + out += c; + } while (out - start < row); +} + VISIBLE byte * Mod_LeafPVS (const mleaf_t *leaf, const model_t *model) { @@ -127,19 +156,35 @@ Mod_LeafPVS (const mleaf_t *leaf, const model_t *model) } return mod_novis; } - Mod_DecompressVis (leaf->compressed_vis, &model->brush, 0xff, decompressed); + Mod_DecompressVis_set (leaf->compressed_vis, &model->brush, 0xff, + decompressed); return decompressed; } VISIBLE void -Mod_LeafPVS_r (const mleaf_t *leaf, const model_t *model, byte defvis, - byte *out) +Mod_LeafPVS_set (const mleaf_t *leaf, const model_t *model, byte defvis, + byte *out) { if (leaf == model->brush.leafs) { memset (out, defvis, sizeof (mod_novis)); return; } - return Mod_DecompressVis (leaf->compressed_vis, &model->brush, defvis, out); + return Mod_DecompressVis_set (leaf->compressed_vis, &model->brush, defvis, + out); +} + +VISIBLE void +Mod_LeafPVS_mix (const mleaf_t *leaf, const model_t *model, byte defvis, + byte *out) +{ + if (leaf == model->brush.leafs) { + for (int i = MAP_PVS_BYTES; i-- > 0; ) { + *out++ |= defvis; + } + return; + } + return Mod_DecompressVis_mix (leaf->compressed_vis, &model->brush, defvis, + out); } // BRUSHMODEL LOADING ========================================================= From bab3e0720f82be00deb828c4feb8c82b036f90a6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 20 Mar 2021 16:08:44 +0900 Subject: [PATCH 411/435] [vulkan] Implement real-time lighting Light styles and shadows aren't implemented yet. The map's entities are used to create the lights, and the PVS used to determine which lights might be visible (ie, the surfaces they light). That could do with some more improvements (eg, checking if a leaf is outside a spotlight's cone), but the concept seems to work. --- include/QF/Vulkan/qf_lighting.h | 13 ++- libs/video/renderer/vulkan/qfpipeline.plist | 6 ++ .../renderer/vulkan/shader/lighting.frag | 10 +-- libs/video/renderer/vulkan/vulkan_lighting.c | 86 +++++++++++++++++-- libs/video/renderer/vulkan/vulkan_main.c | 2 +- 5 files changed, 104 insertions(+), 13 deletions(-) diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h index cd9e7d46c..c19f6ae80 100644 --- a/include/QF/Vulkan/qf_lighting.h +++ b/include/QF/Vulkan/qf_lighting.h @@ -46,8 +46,10 @@ typedef struct qfv_light_s { } qfv_light_t; typedef struct qfv_lightset_s DARRAY_TYPE (qfv_light_t) qfv_lightset_t; +typedef struct qfv_lightleafset_s DARRAY_TYPE (int) qfv_lightleafset_t; +typedef struct qfv_lightvisset_s DARRAY_TYPE (byte) qfv_lightvisset_t; -#define NUM_LIGHTS 128 +#define NUM_LIGHTS 256 typedef struct qfv_light_buffer_s { int lightCount; @@ -64,6 +66,11 @@ typedef struct lightingframe_s { VkDescriptorImageInfo imageInfo[LIGHTING_IMAGE_INFOS]; VkWriteDescriptorSet descriptors[LIGHTING_BUFFER_INFOS + LIGHTING_IMAGE_INFOS]; + // A fat PVS of leafs visible from visible leafs so hidden lights can + // illuminate the leafs visible to the player + byte pvs[MAP_PVS_BYTES]; + struct mleaf_s *leaf; // the last leaf used to generate the pvs + qfv_lightleafset_t lightvis; } lightingframe_t; typedef struct lightingframeset_s @@ -75,6 +82,7 @@ typedef struct lightingctx_s { VkPipelineLayout layout; VkDeviceMemory light_memory; qfv_lightset_t lights; + qfv_lightleafset_t lightleafs; } lightingctx_t; struct vulkan_ctx_s; @@ -82,6 +90,7 @@ struct vulkan_ctx_s; void Vulkan_Lighting_Init (struct vulkan_ctx_s *ctx); void Vulkan_Lighting_Shutdown (struct vulkan_ctx_s *ctx); void Vulkan_Lighting_Draw (struct vulkan_ctx_s *ctx); -void Vulkan_LoadLights (const char *entity_data, struct vulkan_ctx_s *ctx); +void Vulkan_LoadLights (model_t *model, const char *entity_data, + struct vulkan_ctx_s *ctx); #endif//__QF_Vulkan_qf_lighting_h diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 536c98a05..523edfbad 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -856,6 +856,12 @@ stage = fragment; name = main; module = $builtin/lighting.frag; + specializationInfo = { + mapEntries = ( + { size = 4; offset = 0; constantID = 0; }, + ); + data = <00000100>; + }; }, ); vertexInput = { diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index 7468e4dec..c48f54a2f 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -26,15 +26,15 @@ vec3 calc_light (LightData light, vec3 position, vec3 normal) { vec3 dist = light.position - position; - vec3 incoming = normalize (dist); - float spotdot = -dot (incoming, light.direction); - float lightdot = dot (incoming, normal); float d = sqrt (dot (dist, dist)); + vec3 incoming = dist / d; + float spotdot = dot (incoming, light.direction); + float lightdot = dot (incoming, normal); float r = light.radius; float intensity = light.intensity * step (d, r); intensity *= step (spotdot, light.cone) * clamp (lightdot, 0, 1); - return light.color * intensity * (r - d); + return light.color * intensity * (r - d) / 255.0; } void @@ -44,7 +44,7 @@ main (void) vec3 c = subpassLoad (color).rgb; vec3 n = subpassLoad (normal).rgb; vec3 p = subpassLoad (position).rgb; - vec3 light = vec3 (0.8); + vec3 light = vec3 (0); if (MaxLights > 0) { for (int i = 0; i < lightCount; i++) { diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 07f0f9927..4df8475c7 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -61,6 +61,51 @@ #include "r_internal.h" #include "vid_vulkan.h" +static void +find_visible_lights (vulkan_ctx_t *ctx) +{ + //qfv_device_t *device = ctx->device; + //qfv_devfuncs_t *dfunc = device->funcs; + lightingctx_t *lctx = ctx->lighting_context; + lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; + + mleaf_t *leaf = r_viewleaf; + model_t *model = r_worldentity.renderer.model; + + if (!leaf || !model) { + return; + } + + if (leaf != lframe->leaf) { + double start = Sys_DoubleTime (); + byte pvs[MAP_PVS_BYTES]; + + Mod_LeafPVS_set (leaf, model, 0, pvs); + memcpy (lframe->pvs, pvs, sizeof (pvs)); + for (int i = 0; i < model->brush.numleafs; i++) { + if (pvs[i / 8] & (1 << (i % 8))) { + Mod_LeafPVS_mix (model->brush.leafs + i, model, 0, lframe->pvs); + } + } + lframe->leaf = leaf; + + double end = Sys_DoubleTime (); + Sys_Printf ("find_visible_lights: %.5gus\n", (end - start) * 1e6); + + int visible = 0; + memset (lframe->lightvis.a, 0, lframe->lightvis.size * sizeof (byte)); + for (size_t i = 0; i < lctx->lightleafs.size; i++) { + int l = lctx->lightleafs.a[i]; + if (lframe->pvs[l / 8] & (1 << (l % 8))) { + lframe->lightvis.a[i] = 1; + visible++; + } + } + Sys_Printf ("find_visible_lights: %d / %zd visible\n", visible, + lframe->lightvis.size); + } +} + static void update_lights (vulkan_ctx_t *ctx) { @@ -69,6 +114,8 @@ update_lights (vulkan_ctx_t *ctx) lightingctx_t *lctx = ctx->lighting_context; lightingframe_t *lframe = &lctx->frames.a[ctx->curFrame]; + find_visible_lights (ctx); + dlight_t *lights[NUM_LIGHTS]; qfv_packet_t *packet = QFV_PacketAcquire (ctx->staging); qfv_light_buffer_t *light_data = QFV_PacketExtend (packet, @@ -88,6 +135,12 @@ update_lights (vulkan_ctx_t *ctx) VectorZero (light_data->lights[i].direction); light_data->lights[i].cone = 1; } + for (size_t i = 0; + i < lframe->lightvis.size && light_data->lightCount < NUM_LIGHTS; i++) { + if (lframe->lightvis.a[i]) { + light_data->lights[light_data->lightCount++] = lctx->lights.a[i]; + } + } VkBufferMemoryBarrier wr_barriers[] = { { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 0, @@ -208,6 +261,7 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx) ctx->lighting_context = lctx; DARRAY_INIT (&lctx->lights, 16); + DARRAY_INIT (&lctx->lightleafs, 16); size_t frames = ctx->frames.size; DARRAY_INIT (&lctx->frames, frames); @@ -258,6 +312,8 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx) for (size_t i = 0; i < frames; i++) { __auto_type lframe = &lctx->frames.a[i]; + DARRAY_INIT (&lframe->lightvis, 16); + QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet); lframe->cmd = cmdSet->a[0]; @@ -298,10 +354,12 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx) for (size_t i = 0; i < lctx->frames.size; i++) { lightingframe_t *lframe = &lctx->frames.a[i]; dfunc->vkDestroyBuffer (device->dev, lframe->light_buffer, 0); + DARRAY_CLEAR (&lframe->lightvis); } dfunc->vkFreeMemory (device->dev, lctx->light_memory, 0); dfunc->vkDestroyPipeline (device->dev, lctx->pipeline, 0); DARRAY_CLEAR (&lctx->lights); + DARRAY_CLEAR (&lctx->lightleafs); free (lctx->frames.a); free (lctx); } @@ -312,6 +370,14 @@ parse_light (qfv_light_t *light, const plitem_t *entity, { const char *str; + Sys_Printf ("{\n"); + for (int i = PL_D_NumKeys (entity); i-- > 0; ) { + const char *field = PL_KeyAtIndex (entity, i); + const char *value = PL_String (PL_ObjectForKey (entity, field)); + Sys_Printf ("\t%s = %s\n", field, value); + } + Sys_Printf ("}\n"); + if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) { sscanf (str, "%f %f %f", VectorExpandAddr (light->position)); } @@ -336,7 +402,7 @@ parse_light (qfv_light_t *light, const plitem_t *entity, } light->intensity = 1; - if ((str = PL_String (PL_ObjectForKey (entity, "light"))) + if ((str = PL_String (PL_ObjectForKey (entity, "light_lev"))) || (str = PL_String (PL_ObjectForKey (entity, "_light")))) { light->radius = atof (str); } @@ -345,12 +411,13 @@ parse_light (qfv_light_t *light, const plitem_t *entity, } void -Vulkan_LoadLights (const char *entity_data, vulkan_ctx_t *ctx) +Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx) { lightingctx_t *lctx = ctx->lighting_context; plitem_t *entities = 0; lctx->lights.size = 0; + lctx->lightleafs.size = 0; script_t *script = Script_New (); Script_Start (script, "ent data", entity_data); @@ -389,13 +456,22 @@ Vulkan_LoadLights (const char *entity_data, vulkan_ctx_t *ctx) qfv_light_t light = {}; parse_light (&light, entity, targets); - printf ("[%g, %g, %g] %g, [%g %g %g] %g, [%g %g %g] %g\n", + DARRAY_APPEND (&lctx->lights, light); + mleaf_t *leaf = Mod_PointInLeaf (&light.position[0], + model); + DARRAY_APPEND (&lctx->lightleafs, leaf - model->brush.leafs); + printf ("[%g, %g, %g] %g, [%g %g %g] %g, [%g %g %g] %g, %zd\n", VectorExpand (light.color), light.intensity, VectorExpand (light.position), light.radius, - VectorExpand (light.direction), light.cone); - DARRAY_APPEND (&lctx->lights, light); + VectorExpand (light.direction), light.cone, + leaf - model->brush.leafs); } } + printf ("%zd frames\n", ctx->frames.size); + for (size_t i = 0; i < ctx->frames.size; i++) { + lightingframe_t *lframe = &lctx->frames.a[i]; + DARRAY_RESIZE (&lframe->lightvis, lctx->lights.size); + } // targets does not own the objects, so need to remove them before // freeing targets for (int i = PL_D_NumKeys (targets); i-- > 0; ) { diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index a7ed49669..bf1cd3ff2 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -216,7 +216,7 @@ Vulkan_NewMap (model_t *worldmodel, struct model_s **models, int num_models, Vulkan_RegisterTextures (models, num_models, ctx); Vulkan_BuildLightmaps (models, num_models, ctx); Vulkan_BuildDisplayLists (models, num_models, ctx); - Vulkan_LoadLights (worldmodel->brush.entities, ctx); + Vulkan_LoadLights (worldmodel, worldmodel->brush.entities, ctx); } /*void From dccd6989b2d23358ee6b9e054d62ee6cd2d5ac0d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 20 Mar 2021 16:49:12 +0900 Subject: [PATCH 412/435] [vulkan] Implement gamma correction Currently hard-coded to 0.67 (1/1.5), but it does the job for now. --- libs/video/renderer/vulkan/shader/compose.frag | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/video/renderer/vulkan/shader/compose.frag b/libs/video/renderer/vulkan/shader/compose.frag index 39ac94845..631737c67 100644 --- a/libs/video/renderer/vulkan/shader/compose.frag +++ b/libs/video/renderer/vulkan/shader/compose.frag @@ -15,5 +15,6 @@ main (void) o = subpassLoad (opaque).rgb; t = subpassLoad (translucent); c = mix (o, t.rgb, t.a); + c = pow (c, vec3(0.67));//FIXME make gamma correction configurable frag_color = vec4 (c, 1); } From 0246e559832a027344895613508215656a99b515 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 20 Mar 2021 16:50:37 +0900 Subject: [PATCH 413/435] [vulkan] Support colored lights Now my dizzy map looks like it used to (more or less, possibly too dark, but I suspect I used some command-line settings to qflight). --- libs/video/renderer/vulkan/vulkan_lighting.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 4df8475c7..a9c50d27b 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -408,6 +408,10 @@ parse_light (qfv_light_t *light, const plitem_t *entity, } VectorSet (1, 1, 1, light->color); + if ((str = PL_String (PL_ObjectForKey (entity, "color"))) + || (str = PL_String (PL_ObjectForKey (entity, "_color")))) { + sscanf (str, "%f %f %f", VectorExpandAddr (light->color)); + } } void From cadea2757706b6d66c3a347030d803c02dabe8c0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 20 Mar 2021 18:02:27 +0900 Subject: [PATCH 414/435] [vulkan] Disable lightmap support Hopefully, it won't be needed. --- libs/video/renderer/Makemodule.am | 1 - libs/video/renderer/vulkan/vulkan_bsp.c | 8 ++++---- libs/video/renderer/vulkan/vulkan_main.c | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 9eb2c2354..8c459dd1c 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -270,7 +270,6 @@ libs_video_renderer_librender_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/vulkan_compose.c \ libs/video/renderer/vulkan/vulkan_draw.c \ libs/video/renderer/vulkan/vulkan_lighting.c \ - libs/video/renderer/vulkan/vulkan_lightmap.c \ libs/video/renderer/vulkan/vulkan_main.c \ libs/video/renderer/vulkan/vulkan_matrices.c \ libs/video/renderer/vulkan/vulkan_particles.c \ diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index f1ba6e472..937876dc9 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -202,7 +202,7 @@ Vulkan_ClearElements (vulkan_ctx_t *ctx) release_elechains (bctx); release_elementss (bctx); } - +/* static void update_lightmap (mod_brush_t *brush, msurface_t *surf, vulkan_ctx_t *ctx) { @@ -218,7 +218,7 @@ dynamic: Vulkan_BuildLightMap (brush, surf, ctx); } } - +*/ static inline void chain_surface (mod_brush_t *brush, msurface_t *surf, vec_t *transform, float *color, vulkan_ctx_t *ctx) @@ -241,7 +241,7 @@ chain_surface (mod_brush_t *brush, msurface_t *surf, vec_t *transform, tex = tx->render; CHAIN_SURF_F2B (surf, tex->tex_chain); - update_lightmap (brush, surf, ctx); + //update_lightmap (brush, surf, ctx); } if (!(is = surf->instsurf)) is = surf->tinst; @@ -1149,7 +1149,7 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) } } - Vulkan_FlushLightmaps (ctx); + //Vulkan_FlushLightmaps (ctx); bsp_begin (ctx); push_transform (identity, bctx->layout, dfunc, diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index bf1cd3ff2..3474b67ed 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -214,7 +214,7 @@ Vulkan_NewMap (model_t *worldmodel, struct model_s **models, int num_models, R_FreeAllEntities (); Vulkan_ClearParticles (ctx); Vulkan_RegisterTextures (models, num_models, ctx); - Vulkan_BuildLightmaps (models, num_models, ctx); + //Vulkan_BuildLightmaps (models, num_models, ctx); Vulkan_BuildDisplayLists (models, num_models, ctx); Vulkan_LoadLights (worldmodel, worldmodel->brush.entities, ctx); } From 0a79348ce92eb8995bfc05e1e63c9cc42f75e817 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 20 Mar 2021 19:15:06 +0900 Subject: [PATCH 415/435] [vulkan] Tweak the lighting to look a bit better Reduced the gamma correction a bit and increased the intensity of dynamic lights. Not sure the latter is correct, but it looks much better. --- libs/video/renderer/vulkan/shader/compose.frag | 2 +- libs/video/renderer/vulkan/shader/lighting.frag | 6 +++--- libs/video/renderer/vulkan/vulkan_lighting.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/libs/video/renderer/vulkan/shader/compose.frag b/libs/video/renderer/vulkan/shader/compose.frag index 631737c67..542ba4c1b 100644 --- a/libs/video/renderer/vulkan/shader/compose.frag +++ b/libs/video/renderer/vulkan/shader/compose.frag @@ -15,6 +15,6 @@ main (void) o = subpassLoad (opaque).rgb; t = subpassLoad (translucent); c = mix (o, t.rgb, t.a); - c = pow (c, vec3(0.67));//FIXME make gamma correction configurable + c = pow (c, vec3(0.83));//FIXME make gamma correction configurable frag_color = vec4 (c, 1); } diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index c48f54a2f..b756dd879 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -33,8 +33,8 @@ calc_light (LightData light, vec3 position, vec3 normal) float r = light.radius; float intensity = light.intensity * step (d, r); - intensity *= step (spotdot, light.cone) * clamp (lightdot, 0, 1); - return light.color * intensity * (r - d) / 255.0; + intensity *= smoothstep (spotdot, 1 - (1 - spotdot) * 0.995, light.cone) * clamp (lightdot, 0, 1); + return light.color * intensity * (r - d); } void @@ -51,5 +51,5 @@ main (void) light += calc_light (lights[i], p, n); } } - frag_color = vec4 (c * light, 1); + frag_color = vec4 (c * light / 255.0, 1); } diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index a9c50d27b..bac1843c7 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -131,7 +131,7 @@ update_lights (vulkan_ctx_t *ctx) VectorCopy (lights[i]->color, light_data->lights[i].color); VectorCopy (lights[i]->origin, light_data->lights[i].position); light_data->lights[i].radius = lights[i]->radius; - light_data->lights[i].intensity = 1; + light_data->lights[i].intensity = 16; VectorZero (light_data->lights[i].direction); light_data->lights[i].cone = 1; } @@ -370,19 +370,23 @@ parse_light (qfv_light_t *light, const plitem_t *entity, { const char *str; - Sys_Printf ("{\n"); + /*Sys_Printf ("{\n"); for (int i = PL_D_NumKeys (entity); i-- > 0; ) { const char *field = PL_KeyAtIndex (entity, i); const char *value = PL_String (PL_ObjectForKey (entity, field)); Sys_Printf ("\t%s = %s\n", field, value); } - Sys_Printf ("}\n"); + Sys_Printf ("}\n");*/ + + light->cone = 1; + light->intensity = 1; + light->radius = 300; + VectorSet (1, 1, 1, light->color); if ((str = PL_String (PL_ObjectForKey (entity, "origin")))) { sscanf (str, "%f %f %f", VectorExpandAddr (light->position)); } - light->cone = 1; if ((str = PL_String (PL_ObjectForKey (entity, "target")))) { vec3_t position = {}; plitem_t *target = PL_ObjectForKey (targets, str); @@ -401,13 +405,11 @@ parse_light (qfv_light_t *light, const plitem_t *entity, light->cone = -cos (angle * M_PI / 360); // half angle } - light->intensity = 1; if ((str = PL_String (PL_ObjectForKey (entity, "light_lev"))) || (str = PL_String (PL_ObjectForKey (entity, "_light")))) { light->radius = atof (str); } - VectorSet (1, 1, 1, light->color); if ((str = PL_String (PL_ObjectForKey (entity, "color"))) || (str = PL_String (PL_ObjectForKey (entity, "_color")))) { sscanf (str, "%f %f %f", VectorExpandAddr (light->color)); From 7650df340018480e52358e5ef456b897bcb73713 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 10:08:44 +0900 Subject: [PATCH 416/435] [model] Handle brush models with empty texture slots It seems some maps have some empty texture slots (eg, e1m2). --- libs/models/brush/model_brush.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index 1e2fa81a4..a2f02a322 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -274,7 +274,9 @@ Mod_LoadTextures (model_t *mod, bsp_t *bsp) mod->name); } for (i = 0; i < m->nummiptex; i++) { - tx = brush->textures[i]; + if (!(tx = brush->textures[i])) { + continue; + } tx->render = render_data; render_data += render_size; mod_funcs->Mod_ProcessTexture (mod, tx); From 9e633e7230f1118fe2f60a0c1c07a1468e3b30ef Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 10:11:53 +0900 Subject: [PATCH 417/435] [qflight] Remove minlights It seems to be have been DOA (even in the original qutils light). --- tools/qflight/include/light.h | 2 -- tools/qflight/source/ltface.c | 34 ---------------------------------- tools/qflight/source/qflight.c | 3 --- 3 files changed, 39 deletions(-) diff --git a/tools/qflight/include/light.h b/tools/qflight/include/light.h index 350b7e442..f558f594d 100644 --- a/tools/qflight/include/light.h +++ b/tools/qflight/include/light.h @@ -97,8 +97,6 @@ extern vec3_t bsp_yvector; extern qboolean extrasamples; -extern float minlights[MAX_MAP_FACES]; - void LoadNodes (const char *file); qboolean TestLine (lightinfo_t *l, const vec3_t start, const vec3_t stop); qboolean TestSky (lightinfo_t *l, const vec3_t start, const vec3_t stop); diff --git a/tools/qflight/source/ltface.c b/tools/qflight/source/ltface.c index 2b8eb1953..de947cfff 100644 --- a/tools/qflight/source/ltface.c +++ b/tools/qflight/source/ltface.c @@ -508,38 +508,6 @@ SkyLightFace (entity_t *ent, int sun, lightinfo_t *l) } } -#if 0 -static void -FixMinlight (lightinfo_t *l) -{ - float minlight; - int i, j; - - minlight = minlights[l->surfnum]; - - // if minlight is set, there must be a style 0 light map - if (!minlight) - return; - - for (i = 0; i < l->numlightstyles; i++) { - if (l->lightstyles[i] == 0) - break; - } - if (i == l->numlightstyles) { - if (l->numlightstyles == MAXLIGHTMAPS) - return; // oh well.. - for (j = 0; j < l->numsurfpt; j++) - l->lightmaps[i][j] = minlight; - l->lightstyles[i] = 0; - l->numlightstyles++; - } else { - for (j = 0; j < l->numsurfpt; j++) - if (l->lightmaps[i][j] < minlight) - l->lightmaps[i][j] = minlight; - } -} -#endif - void LightFace (lightinfo_t *l, int surfnum) { @@ -590,8 +558,6 @@ LightFace (lightinfo_t *l, int surfnum) SkyLightFace (world_entity, i, l); } -// FixMinlight (&l); - for (i = 0; i < MAXLIGHTMAPS; i++) if (l->lightstyles[i] == 255) break; diff --git a/tools/qflight/source/qflight.c b/tools/qflight/source/qflight.c index 75b9941d7..db133a3b4 100644 --- a/tools/qflight/source/qflight.c +++ b/tools/qflight/source/qflight.c @@ -78,9 +78,6 @@ vec3_t bsp_origin; qboolean extrasamples; -float minlights[MAX_MAP_FACES]; - - int GetFileSpace (int size) { From 6e0cc59e8f558157eeda21f0491c7229a95038c0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 11:36:18 +0900 Subject: [PATCH 418/435] [util] Make wad lump failure a soft error Can't recover from an error if the program is swept out from underneath you. --- libs/util/wad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/util/wad.c b/libs/util/wad.c index 3b4355bbb..ffb5414d3 100644 --- a/libs/util/wad.c +++ b/libs/util/wad.c @@ -118,7 +118,7 @@ W_GetLumpinfo (const char *name) return lump_p; } - Sys_Error ("W_GetLumpinfo: %s not found", name); + Sys_MaskPrintf (SYS_WARN, "W_GetLumpinfo: %s not found", name); return NULL; } From 66e66277804bc93cd8efba0415bf9b3decf1ea5a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 11:37:36 +0900 Subject: [PATCH 419/435] [vulkan] Use the correct character data I got tired of not being able to read 90% of quake's output :P --- libs/video/renderer/vulkan/vulkan_draw.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/libs/video/renderer/vulkan/vulkan_draw.c b/libs/video/renderer/vulkan/vulkan_draw.c index 4b962edd6..12b3cd11b 100644 --- a/libs/video/renderer/vulkan/vulkan_draw.c +++ b/libs/video/renderer/vulkan/vulkan_draw.c @@ -383,10 +383,20 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx) dctx->stage); dctx->sampler = Vulkan_CreateSampler (ctx, "quakepic"); - qpic_t *charspic = Draw_Font8x8Pic (); + draw_chars = W_GetLumpName ("conchars"); + if (draw_chars) { + for (int i = 0; i < 256 * 64; i++) { + if (draw_chars[i] == 0) { + draw_chars[i] = 255; // proper transparent color + } + } + dctx->conchars = pic_data ("conchars", 128, 128, draw_chars, dctx); + } else { + qpic_t *charspic = Draw_Font8x8Pic (); + dctx->conchars = pic_data ("conchars", charspic->width, + charspic->height, charspic->data, dctx); + } - dctx->conchars = pic_data ("conchars", charspic->width, charspic->height, - charspic->data, dctx); byte white_block = 0xfe; dctx->white_pic = pic_data ("white", 1, 1, &white_block, dctx); From a3c1b2e992efbf46fe68025083117d0c0d897587 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 16:13:03 +0900 Subject: [PATCH 420/435] [util] Rename qfplist.[ch] The name is a hold-over from before the current quakeforge tree and the QF include directory. --- include/QF/{qfplist.h => plist.h} | 10 +++++----- libs/audio/cd_file.c | 2 +- libs/gamecode/pr_parse.c | 2 +- libs/ruamoko/rua_plist.c | 2 +- libs/util/Makemodule.am | 2 +- libs/util/cexpr-lex.l | 2 +- libs/util/cexpr-parse.y | 2 +- libs/util/cexpr-type.c | 2 +- libs/util/{qfplist.c => plist.c} | 4 ++-- libs/util/quakefs.c | 2 +- libs/util/test/test-plist.c | 2 +- libs/video/renderer/gl/gl_fog.c | 2 +- libs/video/renderer/glsl/glsl_fog.c | 2 +- libs/video/renderer/vulkan/scrap.c | 1 - libs/video/renderer/vulkan/shader.c | 1 - libs/video/renderer/vulkan/staging.c | 1 - libs/video/renderer/vulkan/vkparse.c | 2 +- libs/video/renderer/vulkan/vkparse.h | 2 +- libs/video/renderer/vulkan/vulkan_lighting.c | 2 +- libs/video/renderer/vulkan/vulkan_texture.c | 1 - libs/video/renderer/vulkan/vulkan_vid_common.c | 2 +- nq/source/cl_ents.c | 2 +- nq/source/cl_main.c | 2 +- nq/source/cl_parse.c | 2 +- nq/source/host_cmd.c | 2 +- qw/source/cl_parse.c | 2 +- tools/qflight/source/entities.c | 2 +- tools/qflight/source/properties.c | 2 +- 28 files changed, 29 insertions(+), 33 deletions(-) rename include/QF/{qfplist.h => plist.h} (99%) rename libs/util/{qfplist.c => plist.c} (99%) diff --git a/include/QF/qfplist.h b/include/QF/plist.h similarity index 99% rename from include/QF/qfplist.h rename to include/QF/plist.h index a4994476d..b14b5e4aa 100644 --- a/include/QF/qfplist.h +++ b/include/QF/plist.h @@ -1,5 +1,5 @@ /* - qfplist.h + plist.h Property list management types and prototypes @@ -25,12 +25,12 @@ */ -#ifndef __QF_qfplist_h -#define __QF_qfplist_h +#ifndef __QF_plist_h +#define __QF_plist_h struct hashlink_s; -/** \defgroup qfplist Property lists +/** \defgroup plist Property lists \ingroup utils */ ///@{ @@ -505,4 +505,4 @@ PL_Message (plitem_t *messages, const plitem_t *item, const char *fmt, ...); ///@} -#endif//__QF_qfplist_h +#endif//__QF_plist_h diff --git a/libs/audio/cd_file.c b/libs/audio/cd_file.c index 5ffe88290..8f236ec5e 100644 --- a/libs/audio/cd_file.c +++ b/libs/audio/cd_file.c @@ -53,8 +53,8 @@ #include "QF/cmd.h" #include "QF/cvar.h" #include "QF/dstring.h" +#include "QF/plist.h" #include "QF/qargs.h" -#include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/quakeio.h" #include "QF/sound.h" diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index b33d14e6c..08f394844 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -45,8 +45,8 @@ #include "QF/dstring.h" #include "QF/mathlib.h" +#include "QF/plist.h" #include "QF/progs.h" -#include "QF/qfplist.h" #include "QF/script.h" #include "QF/sys.h" diff --git a/libs/ruamoko/rua_plist.c b/libs/ruamoko/rua_plist.c index ce5030e5c..d8b3c0da1 100644 --- a/libs/ruamoko/rua_plist.c +++ b/libs/ruamoko/rua_plist.c @@ -40,8 +40,8 @@ #include #include "QF/hash.h" +#include "QF/plist.h" #include "QF/progs.h" -#include "QF/qfplist.h" #include "rua_internal.h" diff --git a/libs/util/Makemodule.am b/libs/util/Makemodule.am index d2ad47b0c..95ce152b9 100644 --- a/libs/util/Makemodule.am +++ b/libs/util/Makemodule.am @@ -64,10 +64,10 @@ libs_util_libQFutil_la_SOURCES= \ libs/util/mersenne.c \ libs/util/msg.c \ libs/util/pakfile.c \ + libs/util/plist.c \ libs/util/plugin.c \ libs/util/qargs.c \ libs/util/qendian.c \ - libs/util/qfplist.c \ libs/util/quakefs.c \ libs/util/quakeio.c \ libs/util/riff.c \ diff --git a/libs/util/cexpr-lex.l b/libs/util/cexpr-lex.l index b82724af4..3fafef8e6 100644 --- a/libs/util/cexpr-lex.l +++ b/libs/util/cexpr-lex.l @@ -47,7 +47,7 @@ #include "QF/cmem.h" #include "QF/dstring.h" #include "QF/hash.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/sys.h" #define CEXPR_YYDEBUG 1 diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y index 4c57c98c0..fca9171af 100644 --- a/libs/util/cexpr-parse.y +++ b/libs/util/cexpr-parse.y @@ -46,7 +46,7 @@ #include "QF/cmem.h" #include "QF/dstring.h" #include "QF/hash.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/sys.h" #include "QF/cexpr.h" diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index 2aff20006..7ee34f5c2 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -32,7 +32,7 @@ #include "QF/cexpr.h" #include "QF/cmem.h" #include "QF/mathlib.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/simd/vec4f.h" #include "libs/util/cexpr-parse.h" diff --git a/libs/util/qfplist.c b/libs/util/plist.c similarity index 99% rename from libs/util/qfplist.c rename to libs/util/plist.c index 454c549f7..e41960398 100644 --- a/libs/util/qfplist.c +++ b/libs/util/plist.c @@ -1,5 +1,5 @@ /* - qfplist.c + plist.c Property list management @@ -41,7 +41,7 @@ #include "QF/darray.h" #include "QF/dstring.h" #include "QF/hash.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/qtypes.h" #include "QF/sys.h" #include "QF/va.h" diff --git a/libs/util/quakefs.c b/libs/util/quakefs.c index 569fab341..9e7c2dc63 100644 --- a/libs/util/quakefs.c +++ b/libs/util/quakefs.c @@ -82,9 +82,9 @@ #include "QF/mathlib.h" #include "QF/pak.h" #include "QF/pakfile.h" +#include "QF/plist.h" #include "QF/qargs.h" #include "QF/qendian.h" -#include "QF/qfplist.h" #include "QF/qtypes.h" #include "QF/quakefs.h" #include "QF/sys.h" diff --git a/libs/util/test/test-plist.c b/libs/util/test/test-plist.c index bc8e0457a..d3ce32715 100644 --- a/libs/util/test/test-plist.c +++ b/libs/util/test/test-plist.c @@ -2,7 +2,7 @@ # include "config.h" #endif #include -#include "QF/qfplist.h" +#include "QF/plist.h" static const char *test_strings[] = { "Guarding the entrance to the Grendal\n" diff --git a/libs/video/renderer/gl/gl_fog.c b/libs/video/renderer/gl/gl_fog.c index b8747e37b..0b74d0b80 100644 --- a/libs/video/renderer/gl/gl_fog.c +++ b/libs/video/renderer/gl/gl_fog.c @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #include "QF/cmd.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/render.h" #include "QF/sys.h" diff --git a/libs/video/renderer/glsl/glsl_fog.c b/libs/video/renderer/glsl/glsl_fog.c index 8118b8497..82777061e 100644 --- a/libs/video/renderer/glsl/glsl_fog.c +++ b/libs/video/renderer/glsl/glsl_fog.c @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #include "QF/cmd.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/render.h" #include "QF/sys.h" diff --git a/libs/video/renderer/vulkan/scrap.c b/libs/video/renderer/vulkan/scrap.c index 01eed4bf8..ab053bf10 100644 --- a/libs/video/renderer/vulkan/scrap.c +++ b/libs/video/renderer/vulkan/scrap.c @@ -43,7 +43,6 @@ #include "QF/dstring.h" #include "QF/hash.h" #include "QF/image.h" -#include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/render.h" #include "QF/sys.h" diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index 4168d9b63..d2921faca 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -42,7 +42,6 @@ #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/hash.h" -#include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/Vulkan/qf_vid.h" diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c index 759962c4d..28ea169a7 100644 --- a/libs/video/renderer/vulkan/staging.c +++ b/libs/video/renderer/vulkan/staging.c @@ -42,7 +42,6 @@ #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/hash.h" -#include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/Vulkan/qf_vid.h" diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index de12d60c0..3a9e98411 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -45,8 +45,8 @@ #include "QF/hash.h" #include "QF/input.h" #include "QF/mathlib.h" +#include "QF/plist.h" #include "QF/qargs.h" -#include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/va.h" diff --git a/libs/video/renderer/vulkan/vkparse.h b/libs/video/renderer/vulkan/vkparse.h index 2550e1b17..4f258a96f 100644 --- a/libs/video/renderer/vulkan/vkparse.h +++ b/libs/video/renderer/vulkan/vkparse.h @@ -9,7 +9,7 @@ typedef struct parsectx_s { } parsectx_t; #include "QF/cexpr.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/Vulkan/renderpass.h" #ifdef vkparse_internal #include "libs/video/renderer/vulkan/vkparse.hinc" diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index bac1843c7..01df24722 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -42,8 +42,8 @@ #include "qfalloca.h" #include "QF/dstring.h" +#include "QF/plist.h" #include "QF/progs.h" -#include "QF/qfplist.h" #include "QF/script.h" #include "QF/sys.h" #include "QF/va.h" diff --git a/libs/video/renderer/vulkan/vulkan_texture.c b/libs/video/renderer/vulkan/vulkan_texture.c index 7d8b13155..7d975298d 100644 --- a/libs/video/renderer/vulkan/vulkan_texture.c +++ b/libs/video/renderer/vulkan/vulkan_texture.c @@ -44,7 +44,6 @@ #include "QF/hash.h" #include "QF/image.h" #include "QF/mathlib.h" -#include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/render.h" #include "QF/sys.h" diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 909f26236..8c3c975ef 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -45,8 +45,8 @@ #include "QF/hash.h" #include "QF/input.h" #include "QF/mathlib.h" +#include "QF/plist.h" #include "QF/qargs.h" -#include "QF/qfplist.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/va.h" diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index 2e04ff885..d2cab9909 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -36,7 +36,7 @@ #include "QF/input.h" #include "QF/keys.h" #include "QF/msg.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/render.h" #include "QF/screen.h" #include "QF/skin.h" diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index e52eb5fea..75b4f72ea 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -39,7 +39,7 @@ #include "QF/joystick.h" #include "QF/keys.h" #include "QF/msg.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/render.h" #include "QF/screen.h" #include "QF/skin.h" diff --git a/nq/source/cl_parse.c b/nq/source/cl_parse.c index 30e48e82a..d2b5e0b2b 100644 --- a/nq/source/cl_parse.c +++ b/nq/source/cl_parse.c @@ -45,7 +45,7 @@ #include "QF/idparse.h" #include "QF/input.h" #include "QF/msg.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/sys.h" #include "QF/screen.h" #include "QF/skin.h" diff --git a/nq/source/host_cmd.c b/nq/source/host_cmd.c index c7e138f23..1ef9fcf41 100644 --- a/nq/source/host_cmd.c +++ b/nq/source/host_cmd.c @@ -44,7 +44,7 @@ #include "QF/keys.h" #include "QF/model.h" #include "QF/msg.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/screen.h" #include "QF/script.h" #include "QF/sys.h" diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index b7a293f28..4f0c93475 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -52,7 +52,7 @@ #include "QF/idparse.h" #include "QF/msg.h" #include "QF/progs.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/quakeio.h" #include "QF/screen.h" #include "QF/skin.h" diff --git a/tools/qflight/source/entities.c b/tools/qflight/source/entities.c index d3c608f6f..8c2260fcd 100644 --- a/tools/qflight/source/entities.c +++ b/tools/qflight/source/entities.c @@ -47,8 +47,8 @@ #include "QF/bspfile.h" #include "QF/dstring.h" #include "QF/mathlib.h" +#include "QF/plist.h" #include "QF/progs.h" -#include "QF/qfplist.h" #include "QF/qtypes.h" #include "QF/quakefs.h" #include "QF/script.h" diff --git a/tools/qflight/source/properties.c b/tools/qflight/source/properties.c index c9297984b..87229d05d 100644 --- a/tools/qflight/source/properties.c +++ b/tools/qflight/source/properties.c @@ -41,7 +41,7 @@ #include #include "QF/mathlib.h" -#include "QF/qfplist.h" +#include "QF/plist.h" #include "QF/quakeio.h" #include "compat.h" From cc4167668c306fa06b6e742dc3d52ed55c00e3fb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 19:56:17 +0900 Subject: [PATCH 421/435] Fix a pile of leaks and uninit errors Still "some" more to go: a pile to do with transforms and temporary entities, and a nasty one with host_cbuf. There's also all the static block-alloc lists :/ --- include/QF/Vulkan/qf_lighting.h | 2 +- include/QF/progs.h | 1 + libs/audio/cd_file.c | 1 + libs/audio/renderer/vorbis.c | 1 + libs/client/cl_temp_entities.c | 13 +- libs/gamecode/pr_builtins.c | 6 + libs/models/alias/model_alias.c | 3 + libs/models/brush/vulkan_model_brush.c | 1 + libs/util/plist.c | 1 + libs/util/quakefs.c | 22 ++- libs/video/renderer/vulkan/instance.c | 3 + libs/video/renderer/vulkan/vkparse.c | 154 +++++++++++------- libs/video/renderer/vulkan/vulkan_lighting.c | 11 +- .../video/renderer/vulkan/vulkan_vid_common.c | 6 + libs/video/targets/context_x11.c | 4 +- libs/video/targets/keys.c | 5 + 16 files changed, 153 insertions(+), 81 deletions(-) diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h index c19f6ae80..c269feaae 100644 --- a/include/QF/Vulkan/qf_lighting.h +++ b/include/QF/Vulkan/qf_lighting.h @@ -70,7 +70,7 @@ typedef struct lightingframe_s { // illuminate the leafs visible to the player byte pvs[MAP_PVS_BYTES]; struct mleaf_s *leaf; // the last leaf used to generate the pvs - qfv_lightleafset_t lightvis; + qfv_lightvisset_t lightvis; } lightingframe_t; typedef struct lightingframeset_s diff --git a/include/QF/progs.h b/include/QF/progs.h index 89fa5d181..498303c25 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1782,6 +1782,7 @@ struct progs_s { ///@{ struct hashtab_s *builtin_hash; struct hashtab_s *builtin_num_hash; + struct biblock_s *builtin_blocks; unsigned bi_next; unsigned (*bi_map) (progs_t *pr, unsigned binum); ///@} diff --git a/libs/audio/cd_file.c b/libs/audio/cd_file.c index 8f236ec5e..0e26a803a 100644 --- a/libs/audio/cd_file.c +++ b/libs/audio/cd_file.c @@ -172,6 +172,7 @@ Load_Tracklist (void) buffile = calloc (size+10, sizeof (char)); Qread (oggfile, buffile, size); + PL_Free (tracklist); tracklist = PL_GetPropertyList (buffile, 0); if (!tracklist || PL_Type (tracklist) != QFDictionary) { Sys_Printf ("Malformed or empty tracklist file. check mus_ogglist\n"); diff --git a/libs/audio/renderer/vorbis.c b/libs/audio/renderer/vorbis.c index fd14ec965..1c346a146 100644 --- a/libs/audio/renderer/vorbis.c +++ b/libs/audio/renderer/vorbis.c @@ -249,6 +249,7 @@ vorbis_stream_close (sfx_t *sfx) if (vf->data) free (vf->data); ov_clear (vf->vf); + free (vf->vf); free (vf); SND_SFX_StreamClose (sfx); } diff --git a/libs/client/cl_temp_entities.c b/libs/client/cl_temp_entities.c index 03fab9b73..11ae7632d 100644 --- a/libs/client/cl_temp_entities.c +++ b/libs/client/cl_temp_entities.c @@ -317,12 +317,13 @@ CL_ParseBeam (qmsg_t *net_message, model_t *m, double time, TEntContext_t *ctx) tent_obj_t *to; beam_t *b; int ent; - vec3_t start, end; + vec4f_t start, end; ent = MSG_ReadShort (net_message); - MSG_ReadCoordV (net_message, start); - MSG_ReadCoordV (net_message, end); + MSG_ReadCoordV (net_message, &start[0]);//FIXME + MSG_ReadCoordV (net_message, &end[0]);//FIXME + start[3] = end[3] = 1;//FIXME to = 0; if (ent) { @@ -345,10 +346,10 @@ CL_ParseBeam (qmsg_t *net_message, model_t *m, double time, TEntContext_t *ctx) b->model = m; b->endtime = time + 0.2; b->seed = rand (); - VectorCopy (end, b->end); + b->end = end; if (b->entity != ctx->playerEntity) { // this will be done in CL_UpdateBeams - VectorCopy (start, b->start); + b->start = start; beam_setup (b, true, time, ctx); } } @@ -626,7 +627,7 @@ CL_UpdateBeams (double time, TEntContext_t *ctx) // if coming from the player, update the start position if (b->entity == ctx->playerEntity) { beam_clear (b); - VectorCopy (ctx->simorg, b->start); + b->start = ctx->simorg; beam_setup (b, false, time, ctx); } diff --git a/libs/gamecode/pr_builtins.c b/libs/gamecode/pr_builtins.c index 6d738e6bc..ab159e250 100644 --- a/libs/gamecode/pr_builtins.c +++ b/libs/gamecode/pr_builtins.c @@ -40,6 +40,7 @@ #include "QF/cmd.h" #include "QF/crc.h" #include "QF/cvar.h" +#include "QF/darray.h" #include "QF/hash.h" #include "QF/progs.h" #include "QF/qdefs.h" @@ -50,6 +51,8 @@ #include "compat.h" +typedef struct biblock_s DARRAY_TYPE (builtin_t *) biblock_t; + static const char * builtin_get_key (const void *_bi, void *unused) { @@ -92,6 +95,8 @@ PR_RegisterBuiltins (progs_t *pr, builtin_t *builtins) int count; if (!pr->builtin_hash) { + pr->builtin_blocks = malloc (sizeof (biblock_t)); + DARRAY_INIT (pr->builtin_blocks, 16); pr->builtin_hash = Hash_NewTable (1021, builtin_get_key, 0, pr, pr->hashlink_freelist); pr->builtin_num_hash = Hash_NewTable (1021, 0, 0, pr, @@ -104,6 +109,7 @@ PR_RegisterBuiltins (progs_t *pr, builtin_t *builtins) for (bi = builtins, count = 1; bi->name; bi++) count++; bi = malloc (count * sizeof (builtin_t)); + DARRAY_APPEND (pr->builtin_blocks, bi); memcpy (bi, builtins, count * sizeof (builtin_t)); builtins = bi; diff --git a/libs/models/alias/model_alias.c b/libs/models/alias/model_alias.c index 727957fe5..583df43fa 100644 --- a/libs/models/alias/model_alias.c +++ b/libs/models/alias/model_alias.c @@ -387,4 +387,7 @@ Mod_LoadAliasModel (model_t *mod, void *buffer, cache_allocator_t allocator) } else { mod->aliashdr = header; } + DARRAY_CLEAR (&alias_ctx.poseverts); + DARRAY_CLEAR (&alias_ctx.stverts); + DARRAY_CLEAR (&alias_ctx.triangles); } diff --git a/libs/models/brush/vulkan_model_brush.c b/libs/models/brush/vulkan_model_brush.c index 55eacb90b..2248ccdaf 100644 --- a/libs/models/brush/vulkan_model_brush.c +++ b/libs/models/brush/vulkan_model_brush.c @@ -326,6 +326,7 @@ load_textures (model_t *mod, vulkan_ctx_t *ctx) barriers->size, barriers->a); QFV_PacketSubmit (packet); QFV_DestroyStagingBuffer (stage); + free (barriers); } void diff --git a/libs/util/plist.c b/libs/util/plist.c index e41960398..b731f982f 100644 --- a/libs/util/plist.c +++ b/libs/util/plist.c @@ -223,6 +223,7 @@ PL_Free (plitem_t *item) dict = item->data; Hash_DelTable (dict->tab); DARRAY_CLEAR (&dict->keys); + free (item->data); break; case QFArray: diff --git a/libs/util/quakefs.c b/libs/util/quakefs.c index 9e7c2dc63..e209d460a 100644 --- a/libs/util/quakefs.c +++ b/libs/util/quakefs.c @@ -252,12 +252,11 @@ static void delete_searchpath (searchpath_t *searchpath) { if (searchpath->pack) { - Qclose (searchpath->pack->handle); - free (searchpath->pack->files); - free (searchpath->pack); + pack_del (searchpath->pack); } - if (searchpath->filename) + if (searchpath->filename) { free (searchpath->filename); + } FREE (searchpaths, searchpath); } @@ -274,8 +273,9 @@ delete_vpath (vpath_t *vpath) { searchpath_t *next; - if (vpath->name) + if (vpath->name) { free (vpath->name); + } while (vpath->user) { next = vpath->user->next; delete_searchpath (vpath->user); @@ -859,6 +859,7 @@ qfs_findfile_search (const vpath_t *vpath, const searchpath_t *sp, found.ff.realname = strdup (*fn); found.path = strdup (path->str); found.fname_index = fn - fnames; + dstring_delete (path); return &found; } } @@ -1416,6 +1417,16 @@ qfs_path_cvar (cvar_t *var) free (cpath); } +static void +qfs_shutdown (void *data) +{ + while (qfs_vpaths) { + vpath_t *next = qfs_vpaths->next; + delete_vpath (qfs_vpaths); + qfs_vpaths = next; + } +} + VISIBLE void QFS_Init (const char *game) { @@ -1465,6 +1476,7 @@ QFS_Init (const char *game) } else { QFS_Gamedir (""); } + Sys_RegisterShutdown (qfs_shutdown, 0); } VISIBLE const char * diff --git a/libs/video/renderer/vulkan/instance.c b/libs/video/renderer/vulkan/instance.c index d1c845c6b..f50ec526b 100644 --- a/libs/video/renderer/vulkan/instance.c +++ b/libs/video/renderer/vulkan/instance.c @@ -285,11 +285,14 @@ void QFV_DestroyInstance (qfv_instance_t *instance) { qfv_instfuncs_t *ifunc = instance->funcs; + if (instance->debug_handle) { ifunc->vkDestroyDebugUtilsMessengerEXT (instance->instance, instance->debug_handle, 0); } instance->funcs->vkDestroyInstance (instance->instance, 0); + del_strset (instance->enabled_extensions); + free (instance->devices); free (instance); } diff --git a/libs/video/renderer/vulkan/vkparse.c b/libs/video/renderer/vulkan/vkparse.c index 3a9e98411..382d04873 100644 --- a/libs/video/renderer/vulkan/vkparse.c +++ b/libs/video/renderer/vulkan/vkparse.c @@ -252,6 +252,13 @@ parse_reference (const plitem_t *item, const char *type, plitem_t *messages, return refItem; } +static void * +vkparse_alloc (void *context, size_t size) +{ + parsectx_t *pctx = context; + return cmemalloc (pctx->ectx->memsuper, size); +} + static int parse_single (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context) @@ -269,9 +276,9 @@ parse_single (const plfield_t *field, const plitem_t *item, } plfield_t f = { 0, 0, single->type, single->parser, 0 }; - void *value = calloc (1, single->stride); + void *value = vkparse_alloc (context, single->stride); + memset (value, 0, single->stride); if (!single->parser (&f, item, value, messages, context)) { - free (value); return 0; } @@ -279,12 +286,6 @@ parse_single (const plfield_t *field, const plitem_t *item, return 1; } -static void * -array_alloc (void *context, size_t size) -{ - return malloc (size); -} - static int parse_array (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context) @@ -296,7 +297,7 @@ parse_array (const plfield_t *field, const plitem_t *item, plelement_t element = { array->type, array->stride, - array_alloc, + vkparse_alloc, array->parser, 0, }; @@ -313,12 +314,11 @@ parse_array (const plfield_t *field, const plitem_t *item, if (!PL_ParseArray (&f, item, &arr, messages, context)) { return 0; } - *value = malloc (array->stride * arr->size); + *value = vkparse_alloc (context, array->stride * arr->size); memcpy (*value, arr->a, array->stride * arr->size); if ((void *) size >= data) { *size = arr->size; } - free (arr); return 1; } @@ -339,7 +339,7 @@ parse_data (const plfield_t *field, const plitem_t *item, Sys_Printf (" %zd %zd\n", datad->value_offset, datad->size_offset); Sys_Printf (" %zd %p\n", binsize, bindata); - *value = malloc (binsize); + *value = vkparse_alloc (context, binsize); memcpy (*value, bindata, binsize); if ((void *) size > data) { *size = binsize; @@ -362,7 +362,9 @@ parse_string (const plfield_t *field, const plitem_t *item, //Sys_Printf (" %zd\n", string->value_offset); //Sys_Printf (" %s\n", str); - *value = strdup (str); + size_t len = strlen (str) + 1; + *value = vkparse_alloc (context, len); + memcpy (*value, str, len); return 1; } @@ -877,7 +879,7 @@ typedef struct qfv_renderpass_s { static plelement_t parse_qfv_renderpass_attachments_data = { QFDictionary, sizeof (VkAttachmentDescription), - array_alloc, + vkparse_alloc, parse_VkAttachmentDescription, 0, }; @@ -885,7 +887,7 @@ static plelement_t parse_qfv_renderpass_attachments_data = { static plelement_t parse_qfv_renderpass_subpasses_data = { QFDictionary, sizeof (VkSubpassDescription), - array_alloc, + vkparse_alloc, parse_VkSubpassDescription, 0, }; @@ -893,7 +895,7 @@ static plelement_t parse_qfv_renderpass_subpasses_data = { static plelement_t parse_qfv_renderpass_dependencies_data = { QFDictionary, sizeof (VkSubpassDependency), - array_alloc, + vkparse_alloc, parse_VkSubpassDependency, 0, }; @@ -953,7 +955,7 @@ QFV_GetEnum (const char *name) } static int -parse_object (vulkan_ctx_t *ctx, plitem_t *plist, +parse_object (vulkan_ctx_t *ctx, memsuper_t *memsuper, plitem_t *plist, plparser_t parser, void *object, plitem_t *properties) { plitem_t *messages = PL_NewArray (); @@ -970,9 +972,9 @@ parse_object (vulkan_ctx_t *ctx, plitem_t *plist, exprtab_t vars_tab = { var_syms, 0 }; exprctx.external_variables = &vars_tab; - exprctx.memsuper = new_memsuper (); exprctx.messages = messages; exprctx.hashlinks = &ctx->hashlinks; + exprctx.memsuper = memsuper; cexpr_init_symtab (&vars_tab, &exprctx); @@ -983,8 +985,8 @@ parse_object (vulkan_ctx_t *ctx, plitem_t *plist, } return 0; } + Hash_DelTable (vars_tab.tab); PL_Free (messages); - delete_memsuper (exprctx.memsuper); return 1; } @@ -999,12 +1001,14 @@ parse_qfv_renderpass (const plfield_t *field, const plitem_t *item, void *data, VkRenderPass QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) { + memsuper_t *memsuper = new_memsuper (); qfv_device_t *device = ctx->device; qfv_renderpass_t renderpass_data = {}; - if (!parse_object (ctx, plist, parse_qfv_renderpass, &renderpass_data, - properties)) { + if (!parse_object (ctx, memsuper, plist, parse_qfv_renderpass, + &renderpass_data, properties)) { + delete_memsuper (memsuper); return 0; } @@ -1014,29 +1018,22 @@ QFV_ParseRenderPass (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) renderpass_data.subpasses, renderpass_data.dependencies); - free (renderpass_data.attachments); - for (size_t i = 0; i < renderpass_data.subpasses->size; i++) { - free ((void *) renderpass_data.subpasses->a[i].pInputAttachments); - free ((void *) renderpass_data.subpasses->a[i].pColorAttachments); - free ((void *) renderpass_data.subpasses->a[i].pResolveAttachments); - free ((void *) renderpass_data.subpasses->a[i].pDepthStencilAttachment); - free ((void *) renderpass_data.subpasses->a[i].pPreserveAttachments); - } - free (renderpass_data.subpasses); - free (renderpass_data.dependencies); + delete_memsuper (memsuper); return renderpass; } VkPipeline QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) { + memsuper_t *memsuper = new_memsuper (); qfv_device_t *device = ctx->device; __auto_type cInfo = QFV_AllocGraphicsPipelineCreateInfoSet (1, alloca); memset (&cInfo->a[0], 0, sizeof (cInfo->a[0])); - if (!parse_object (ctx, plist, parse_VkGraphicsPipelineCreateInfo, + if (!parse_object (ctx, memsuper, plist, parse_VkGraphicsPipelineCreateInfo, &cInfo->a[0], properties)) { + delete_memsuper (memsuper); return 0; } @@ -1044,6 +1041,7 @@ QFV_ParsePipeline (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) __auto_type plSet = QFV_CreateGraphicsPipelines (device, 0, cInfo); VkPipeline pipeline = plSet->a[0]; free (plSet); + delete_memsuper (memsuper); return pipeline; } @@ -1053,17 +1051,20 @@ QFV_ParseDescriptorPool (vulkan_ctx_t *ctx, plitem_t *plist, { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); VkDescriptorPoolCreateInfo cInfo = {}; - if (!parse_object (ctx, plist, parse_VkDescriptorPoolCreateInfo, &cInfo, - properties)) { + if (!parse_object (ctx, memsuper, plist, parse_VkDescriptorPoolCreateInfo, + &cInfo, properties)) { + delete_memsuper (memsuper); return 0; } VkDescriptorPool pool; dfunc->vkCreateDescriptorPool (device->dev, &cInfo, 0, &pool); + delete_memsuper (memsuper); return pool; } @@ -1073,17 +1074,21 @@ QFV_ParseDescriptorSetLayout (vulkan_ctx_t *ctx, plitem_t *plist, { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); VkDescriptorSetLayoutCreateInfo cInfo = {}; - if (!parse_object (ctx, plist, parse_VkDescriptorSetLayoutCreateInfo, + if (!parse_object (ctx, memsuper, plist, + parse_VkDescriptorSetLayoutCreateInfo, &cInfo, properties)) { + delete_memsuper (memsuper); return 0; } VkDescriptorSetLayout setLayout; dfunc->vkCreateDescriptorSetLayout (device->dev, &cInfo, 0, &setLayout); + delete_memsuper (memsuper); return setLayout; } @@ -1093,17 +1098,20 @@ QFV_ParsePipelineLayout (vulkan_ctx_t *ctx, plitem_t *plist, { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); VkPipelineLayoutCreateInfo cInfo = {}; - if (!parse_object (ctx, plist, parse_VkPipelineLayoutCreateInfo, + if (!parse_object (ctx, memsuper, plist, parse_VkPipelineLayoutCreateInfo, &cInfo, properties)) { + delete_memsuper (memsuper); return 0; } VkPipelineLayout layout; dfunc->vkCreatePipelineLayout (device->dev, &cInfo, 0, &layout); + delete_memsuper (memsuper); return layout; } @@ -1112,17 +1120,20 @@ QFV_ParseSampler (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); VkSamplerCreateInfo cInfo = {}; - if (!parse_object (ctx, plist, parse_VkSamplerCreateInfo, &cInfo, + if (!parse_object (ctx, memsuper, plist, parse_VkSamplerCreateInfo, &cInfo, properties)) { + delete_memsuper (memsuper); return 0; } VkSampler sampler; dfunc->vkCreateSampler (device->dev, &cInfo, 0, &sampler); + delete_memsuper (memsuper); return sampler; } @@ -1131,17 +1142,20 @@ QFV_ParseImage (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); VkImageCreateInfo cInfo = {}; - if (!parse_object (ctx, plist, parse_VkImageCreateInfo, &cInfo, + if (!parse_object (ctx, memsuper, plist, parse_VkImageCreateInfo, &cInfo, properties)) { + delete_memsuper (memsuper); return 0; } VkImage image; dfunc->vkCreateImage (device->dev, &cInfo, 0, &image); + delete_memsuper (memsuper); return image; } @@ -1150,17 +1164,20 @@ QFV_ParseImageView (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); VkImageViewCreateInfo cInfo = {}; - if (!parse_object (ctx, plist, parse_VkImageViewCreateInfo, &cInfo, - properties)) { + if (!parse_object (ctx, memsuper, plist, parse_VkImageViewCreateInfo, + &cInfo, properties)) { + delete_memsuper (memsuper); return 0; } VkImageView imageView; dfunc->vkCreateImageView (device->dev, &cInfo, 0, &imageView); + delete_memsuper (memsuper); return imageView; } @@ -1177,14 +1194,14 @@ typedef struct { static plelement_t qfv_imagecreate_dict = { QFDictionary, sizeof (VkImageCreateInfo), - array_alloc, + vkparse_alloc, parse_VkImageCreateInfo, }; static plelement_t qfv_imageviewcreate_dict = { QFDictionary, sizeof (VkImageViewCreateInfo), - array_alloc, + vkparse_alloc, parse_VkImageViewCreateInfo, }; @@ -1202,11 +1219,6 @@ parse_imagecreate_dict (const plfield_t *field, const plitem_t *item, imagecreate_t *imagecreate = data; imagecreate->count = arr->size; imagecreate->info = (VkImageCreateInfo *) arr->a; - } else { - //FIXME leaky boat when succeeds - if (arr) { - free (arr); - } } return ret; } @@ -1239,18 +1251,21 @@ QFV_ParseImageSet (vulkan_ctx_t *ctx, plitem_t *item, plitem_t *properties) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); imagecreate_t create = {}; pltype_t type = PL_Type (item); if (type == QFDictionary) { - if (!parse_object (ctx, item, parse_imagecreate_dict, &create, - properties)) { + if (!parse_object (ctx, memsuper, item, parse_imagecreate_dict, + &create, properties)) { + delete_memsuper (memsuper); return 0; } } else { Sys_Printf ("Neither array nor dictionary: %d\n", PL_Line (item)); + delete_memsuper (memsuper); return 0; } @@ -1265,6 +1280,7 @@ QFV_ParseImageSet (vulkan_ctx_t *ctx, plitem_t *item, plitem_t *properties) QFV_AddHandle (ctx->images, name, (uint64_t) set->a[i]); } + delete_memsuper (memsuper); return set; } @@ -1274,18 +1290,21 @@ QFV_ParseImageViewSet (vulkan_ctx_t *ctx, plitem_t *item, { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); imageviewcreate_t create = {}; pltype_t type = PL_Type (item); if (type == QFDictionary) { - if (!parse_object (ctx, item, parse_imageviewcreate_dict, &create, - properties)) { + if (!parse_object (ctx, memsuper, item, parse_imageviewcreate_dict, + &create, properties)) { + delete_memsuper (memsuper); return 0; } } else { Sys_Printf ("Neither array nor dictionary: %d\n", PL_Line (item)); + delete_memsuper (memsuper); return 0; } @@ -1298,6 +1317,7 @@ QFV_ParseImageViewSet (vulkan_ctx_t *ctx, plitem_t *item, QFV_AddHandle (ctx->imageViews, name, (uint64_t) set->a[i]); } + delete_memsuper (memsuper); return set; } @@ -1306,11 +1326,13 @@ QFV_ParseFramebuffer (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) { qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + memsuper_t *memsuper = new_memsuper (); VkFramebufferCreateInfo cInfo = {}; - if (!parse_object (ctx, plist, parse_VkFramebufferCreateInfo, &cInfo, - properties)) { + if (!parse_object (ctx, memsuper, plist, parse_VkFramebufferCreateInfo, + &cInfo, properties)) { + delete_memsuper (memsuper); return 0; } @@ -1318,6 +1340,7 @@ QFV_ParseFramebuffer (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) dfunc->vkCreateFramebuffer (device->dev, &cInfo, 0, &framebuffer); printf ("framebuffer, renderPass: %p, %p\n", framebuffer, cInfo.renderPass); + delete_memsuper (memsuper); return framebuffer; } @@ -1325,19 +1348,16 @@ static int parse_clearvalueset (const plfield_t *field, const plitem_t *item, void *data, plitem_t *messages, void *context) { - parsectx_t *parsectx = context; - vulkan_ctx_t *ctx = parsectx->vctx; - plelement_t element = { QFDictionary, sizeof (VkClearValue), - array_alloc, + vkparse_alloc, parse_VkClearValue, 0, }; plfield_t f = { 0, 0, 0, 0, &element }; - if (!PL_ParseArray (&f, item, &ctx->clearValues, messages, context)) { + if (!PL_ParseArray (&f, item, data, messages, context)) { return 0; } return 1; @@ -1346,9 +1366,19 @@ parse_clearvalueset (const plfield_t *field, const plitem_t *item, void *data, int QFV_ParseClearValues (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties) { - if (!parse_object (ctx, plist, parse_clearvalueset, &ctx->clearValues, - properties)) { - return 0; + int ret = 0; + memsuper_t *memsuper = new_memsuper (); + clearvalueset_t *clearValues = 0; + + ctx->clearValues = 0; + if (parse_object (ctx, memsuper, plist, parse_clearvalueset, &clearValues, + properties)) { + ret = 1; + ctx->clearValues = DARRAY_ALLOCFIXED (clearvalueset_t, + clearValues->size, malloc); + memcpy (ctx->clearValues->a, clearValues->a, + clearValues->size * sizeof (clearValues->a[0])); } - return 1; + delete_memsuper (memsuper); + return ret; } diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 01df24722..b1eecf3d3 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -77,7 +77,7 @@ find_visible_lights (vulkan_ctx_t *ctx) } if (leaf != lframe->leaf) { - double start = Sys_DoubleTime (); + //double start = Sys_DoubleTime (); byte pvs[MAP_PVS_BYTES]; Mod_LeafPVS_set (leaf, model, 0, pvs); @@ -89,8 +89,8 @@ find_visible_lights (vulkan_ctx_t *ctx) } lframe->leaf = leaf; - double end = Sys_DoubleTime (); - Sys_Printf ("find_visible_lights: %.5gus\n", (end - start) * 1e6); + //double end = Sys_DoubleTime (); + //Sys_Printf ("find_visible_lights: %.5gus\n", (end - start) * 1e6); int visible = 0; memset (lframe->lightvis.a, 0, lframe->lightvis.size * sizeof (byte)); @@ -101,8 +101,8 @@ find_visible_lights (vulkan_ctx_t *ctx) visible++; } } - Sys_Printf ("find_visible_lights: %d / %zd visible\n", visible, - lframe->lightvis.size); + //Sys_Printf ("find_visible_lights: %d / %zd visible\n", visible, + // lframe->lightvis.size); } } @@ -313,6 +313,7 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx) __auto_type lframe = &lctx->frames.a[i]; DARRAY_INIT (&lframe->lightvis, 16); + lframe->leaf = 0; QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, cmdSet); lframe->cmd = cmdSet->a[0]; diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index 8c3c975ef..7c42467de 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -186,6 +186,8 @@ clear_table (hashtab_t **table) void Vulkan_Shutdown_Common (vulkan_ctx_t *ctx) { + PL_Free (ctx->pipelineDef); + PL_Free (ctx->renderpassDef); if (ctx->pipeline) { QFV_DestroyPipeline (ctx->device, ctx->pipeline); } @@ -546,6 +548,10 @@ Vulkan_DestroyFrames (vulkan_ctx_t *ctx) df->vkDestroySemaphore (dev, frame->imageAvailableSemaphore, 0); df->vkDestroySemaphore (dev, frame->renderDoneSemaphore, 0); df->vkDestroyFramebuffer (dev, frame->framebuffer, 0); + for (int j = 0; j < frame->cmdSetCount; j++) { + DARRAY_CLEAR (&frame->cmdSets[j]); + } + free (frame->cmdSets); } DARRAY_CLEAR (&ctx->frames); diff --git a/libs/video/targets/context_x11.c b/libs/video/targets/context_x11.c index c118feab2..68e3645fe 100644 --- a/libs/video/targets/context_x11.c +++ b/libs/video/targets/context_x11.c @@ -311,9 +311,9 @@ void X11_CreateNullCursor (void) { Pixmap cursormask; - XGCValues xgc; + XGCValues xgc = { }; GC gc; - XColor dummycolour; + XColor dummycolour = { }; if (nullcursor != None) return; diff --git a/libs/video/targets/keys.c b/libs/video/targets/keys.c index 5d42aadd0..92ee71fc0 100644 --- a/libs/video/targets/keys.c +++ b/libs/video/targets/keys.c @@ -842,6 +842,11 @@ Key_IMT_Drop_All_f (void) while (key_targets[kd].imts) { imt = key_targets[kd].imts; key_targets[kd].imts = imt->next; + for (int i = 0; i < QFK_LAST; i++) { + if (imt->bindings[i].str) { + free (imt->bindings[i].str); + } + } free ((char *) imt->name); free (imt); } From 1bafd88a27efe26957c055efcb05571aac1bff84 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 20:40:02 +0900 Subject: [PATCH 422/435] oops plist --- include/QF/Makemodule.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/Makemodule.am b/include/QF/Makemodule.am index aefd432f7..4c190feae 100644 --- a/include/QF/Makemodule.am +++ b/include/QF/Makemodule.am @@ -36,6 +36,7 @@ include_qf = \ include/QF/pakfile.h \ include/QF/pcx.h \ include/QF/png.h \ + include/QF/plist.h \ include/QF/plugin.h \ include/QF/pr_comp.h \ include/QF/pr_debug.h \ @@ -45,7 +46,6 @@ include_qf = \ include/QF/qargs.h \ include/QF/qdefs.h \ include/QF/qendian.h \ - include/QF/qfplist.h \ include/QF/qtypes.h \ include/QF/quakefs.h \ include/QF/quakeio.h \ From 003910612a75a16c995c1a7cd4e9d6bf7a81e65c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 20:45:43 +0900 Subject: [PATCH 423/435] [entity] Fix tests for changed forward/right I had forgotten that Quake has forward as +X and right as -Y (still a right-handed system, just that with X forward, Y points left). --- libs/entity/test/test-hierarchy.c | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/libs/entity/test/test-hierarchy.c b/libs/entity/test/test-hierarchy.c index 513f33fca..7d60f0104 100644 --- a/libs/entity/test/test-hierarchy.c +++ b/libs/entity/test/test-hierarchy.c @@ -595,11 +595,11 @@ test_frames (void) (vec4f_t) { 0, 0, 1, 1 }, "world position")) { return 1; } - if (!check_vector (root, Transform_Right, (vec4f_t) { 1, 0, 0, 0 }, - "right")) { + if (!check_vector (root, Transform_Forward, (vec4f_t) { 1, 0, 0, 0 }, + "forward")) { return 1; } - if (!check_vector (root, Transform_Forward, (vec4f_t) { 0, 1, 0, 0 }, + if (!check_vector (root, Transform_Right, (vec4f_t) { 0, -1, 0, 0 }, "right")) { return 1; } @@ -616,12 +616,12 @@ test_frames (void) "world position")) { return 1; } - if (!check_vector (A, Transform_Right, (vec4f_t) { 0, 1, 0, 0 }, - "right")) { + if (!check_vector (A, Transform_Forward, (vec4f_t) { 0, 1, 0, 0 }, + "forward")) { return 1; } - if (!check_vector (A, Transform_Forward, (vec4f_t) { 0, 0, 1, 0 }, - "forward")) { + if (!check_vector (A, Transform_Right, (vec4f_t) { 0, 0, -1, 0 }, + "right")) { return 1; } if (!check_vector (A, Transform_Up, (vec4f_t) { 1, 0, 0, 0 }, @@ -636,12 +636,12 @@ test_frames (void) "world position")) { return 1; } - if (!check_vector (A1, Transform_Right, (vec4f_t) { 1, 0, 0, 0 }, - "right")) { + if (!check_vector (A1, Transform_Forward, (vec4f_t) { 1, 0, 0, 0 }, + "forward")) { return 1; } - if (!check_vector (A1, Transform_Forward, (vec4f_t) { 0, 1, 0, 0 }, - "forward")) { + if (!check_vector (A1, Transform_Right, (vec4f_t) { 0, -1, 0, 0 }, + "right")) { return 1; } if (!check_vector (A1, Transform_Up, (vec4f_t) { 0, 0, 1, 0 }, @@ -657,12 +657,12 @@ test_frames (void) "world position")) { return 1; } - if (!check_vector (B, Transform_Right, (vec4f_t) { 0, 0, 1, 0 }, - "right")) { + if (!check_vector (B, Transform_Forward, (vec4f_t) { 0, 0, 1, 0 }, + "forward")) { return 1; } - if (!check_vector (B, Transform_Forward, (vec4f_t) {-1, 0, 0, 0 }, - "forward")) { + if (!check_vector (B, Transform_Right, (vec4f_t) { 1, 0, 0, 0 }, + "right")) { return 1; } if (!check_vector (B, Transform_Up, (vec4f_t) { 0,-1, 0, 0 }, @@ -677,12 +677,12 @@ test_frames (void) "world position")) { return 1; } - if (!check_vector (B1, Transform_Right, (vec4f_t) { 1, 0, 0, 0 }, - "right")) { + if (!check_vector (B1, Transform_Forward, (vec4f_t) { 1, 0, 0, 0 }, + "forward")) { return 1; } - if (!check_vector (B1, Transform_Forward, (vec4f_t) { 0, 1, 0, 0 }, - "forward")) { + if (!check_vector (B1, Transform_Right, (vec4f_t) { 0, -1, 0, 0 }, + "right")) { return 1; } if (!check_vector (B1, Transform_Up, (vec4f_t) { 0, 0, 1, 0 }, From 56cf181a1137f4d0412f423adc6c0868901cbb3e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 21:26:36 +0900 Subject: [PATCH 424/435] [gamecode] Make PR_RESMAP macros more function-like I never liked that some of the macros needed the type as a parameter (yay typeof and __auto_type) or those that returned a value hid the return statement so they couldn't be used in assignments. --- include/QF/progs.h | 125 +++++++++++++++-------------- libs/console/bi_inputline.c | 10 +-- libs/gamecode/pr_debug.c | 4 +- libs/ruamoko/rua_hash.c | 10 +-- libs/ruamoko/rua_msgbuf.c | 10 +-- libs/ruamoko/rua_obj.c | 8 +- libs/ruamoko/rua_plist.c | 10 +-- libs/ruamoko/rua_qfile.c | 10 +-- libs/ruamoko/rua_script.c | 10 +-- libs/ruamoko/rua_set.c | 20 ++--- libs/video/renderer/r_progs.c | 10 +-- ruamoko/qwaq/builtins/curses.c | 20 ++--- ruamoko/qwaq/builtins/debug.c | 10 +-- ruamoko/qwaq/builtins/editbuffer.c | 10 +-- 14 files changed, 136 insertions(+), 131 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 498303c25..8b1a6e118 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1532,46 +1532,44 @@ void *PR_Resources_Find (progs_t *pr, const char *name); /** Allocate a new resource from the resource map. - \param type The type of the resource. Must match the \c type parameter - used for PR_RESMAP. \param map The resource map. \return A pointer to the new resource, or null if no more could be allocated. */ -#define PR_RESNEW(type,map) \ - type *t; \ - \ - if (!map._free) { \ - int i, size; \ - map._size++; \ - size = map._size * sizeof (type *); \ - map._map = realloc (map._map, size); \ - if (!map._map) \ - return 0; \ - map._free = calloc (1024, sizeof (type)); \ - if (!map._free) \ - return 0; \ - map._map[map._size - 1] = map._free; \ - for (i = 0; i < 1023; i++) \ - *(type **) &map._free[i] = &map._free[i + 1]; \ - *(type **) &map._free[i] = 0; \ - } \ - t = map._free; \ - map._free = *(type **) t; \ - memset (t, 0, sizeof (type)); \ - return t +#define PR_RESNEW(map) \ + ({ \ + if (!map._free) { \ + int i, size; \ + map._size++; \ + size = map._size * sizeof (map._free); \ + map._map = realloc (map._map, size); \ + if (!map._map) \ + return 0; \ + map._free = calloc (1024, sizeof (*map._free)); \ + if (!map._free) \ + return 0; \ + map._map[map._size - 1] = map._free; \ + for (i = 0; i < 1023; i++) \ + *(typeof (map._free) *) &map._free[i] = &map._free[i + 1]; \ + *(typeof (map._free) *) &map._free[i] = 0; \ + } \ + __auto_type t = map._free; \ + map._free = *(typeof (map._free) *) t; \ + memset (t, 0, sizeof (*map._free)); \ + t; \ + }) /** Free a resource returning it to the resource map. - \param type The type of the resource. Must match the \c type parameter - used for PR_RESMAP. \param map The resource map. \param t Pointer to the resource to be freed. */ -#define PR_RESFREE(type,map,t) \ - memset (t, 0, sizeof (type)); \ - *(type **) t = map._free; \ - map._free = t +#define PR_RESFREE(map,t) \ + do { \ + memset (t, 0, sizeof (*map._free)); \ + *(typeof (map._free) *) t = map._free; \ + map._free = t; \ + } while (0) /** Free all resources in the resource map. @@ -1580,24 +1578,24 @@ void *PR_Resources_Find (progs_t *pr, const char *name); A reset resource map is guaranteed to allocate elements sequentially. - \param type The type of the resource. Must match the \c type parameter - used for PR_RESMAP. \param map The resource map. */ -#define PR_RESRESET(type,map) \ - unsigned i, j; \ - if (!map._size) \ - return; \ - for (i = 0; i < map._size; i++) { \ - map._free = map._map[i]; \ - for (j = 0; j < 1023; j++) \ - *(type **) &map._free[j] = &map._free[j + 1]; \ - if (i < map._size - 1) \ - *(type **) &map._free[j] = &map._map[i + 1][0]; \ - else \ - *(type **) &map._free[j] = 0; \ - } \ - map._free = map._map[0]; +#define PR_RESRESET(map) \ + do { \ + unsigned i, j; \ + if (!map._size) \ + return; \ + for (i = 0; i < map._size; i++) { \ + map._free = map._map[i]; \ + for (j = 0; j < 1023; j++) \ + *(typeof (map._free) *) &map._free[j] = &map._free[j + 1]; \ + if (i < map._size - 1) \ + *(typeof (map._free) *) &map._free[j] = &map._map[i + 1][0];\ + else \ + *(typeof (map._free) *) &map._free[j] = 0; \ + } \ + map._free = map._map[0]; \ + } while (0) /** Retrieve a resource from the resource map using a handle. @@ -1606,12 +1604,14 @@ void *PR_Resources_Find (progs_t *pr, const char *name); \return A pointer to the resource, or NULL if the handle is invalid. */ -#define PR_RESGET(map,col) \ - unsigned row = ~col / 1024; \ - col = ~col % 1024; \ - if (row >= map._size) \ - return 0; \ - return &map._map[row][col] +#define PR_RESGET(map,col) \ + ({ \ + unsigned row = ~col / 1024; \ + col = ~col % 1024; \ + if (row >= map._size) \ + return 0; \ + &map._map[row][col]; \ + }) /** Convert a resource pointer to a handle. @@ -1619,14 +1619,19 @@ void *PR_Resources_Find (progs_t *pr, const char *name); \param ptr The resource pointer. \return The handle or 0 if the pointer is invalid. */ -#define PR_RESINDEX(map,ptr) \ - unsigned i; \ - for (i = 0; i < map._size; i++) { \ - long d = ptr - map._map[i]; \ - if (d >= 0 && d < 1024) \ - return ~(i * 1024 + d); \ - } \ - return 0 +#define PR_RESINDEX(map,ptr) \ + ({ \ + unsigned i; \ + unsigned index = 0; \ + for (i = 0; i < map._size; i++) { \ + long d = ptr - map._map[i]; \ + if (d >= 0 && d < 1024) { \ + index = ~(i * 1024 + d); \ + break; \ + } \ + } \ + index; \ + }) ///@} ///@} diff --git a/libs/console/bi_inputline.c b/libs/console/bi_inputline.c index 7e4e743a2..b55cfa034 100644 --- a/libs/console/bi_inputline.c +++ b/libs/console/bi_inputline.c @@ -62,31 +62,31 @@ typedef struct { static il_data_t * il_data_new (il_resources_t *res) { - PR_RESNEW (il_data_t, res->line_map); + return PR_RESNEW (res->line_map); } static void il_data_free (il_resources_t *res, il_data_t *line) { - PR_RESFREE (il_data_t, res->line_map, line); + PR_RESFREE (res->line_map, line); } static void il_data_reset (il_resources_t *res) { - PR_RESRESET (il_data_t, res->line_map); + PR_RESRESET (res->line_map); } static inline il_data_t * il_data_get (il_resources_t *res, unsigned index) { - PR_RESGET (res->line_map, index); + return PR_RESGET (res->line_map, index); } static inline int __attribute__((pure)) il_data_index (il_resources_t *res, il_data_t *line) { - PR_RESINDEX (res->line_map, line); + return PR_RESINDEX (res->line_map, line); } static void diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index a272babf8..e8aa20e66 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -373,7 +373,7 @@ pr_debug_clear (progs_t *pr, void *data) Hash_FlushTable (res->file_hash); Hash_FlushTable (res->debug_syms); Hash_FlushTable (res->compunits); - PR_RESRESET (compunit_t, res->compmap); + PR_RESRESET (res->compmap); res->debug = 0; res->auxfunctions = 0; if (res->auxfunction_map) @@ -461,7 +461,7 @@ byteswap_def (pr_def_t *def) static compunit_t * new_compunit (prdeb_resources_t *res) { - PR_RESNEW (compunit_t, res->compmap); + return PR_RESNEW (res->compmap); } static void diff --git a/libs/ruamoko/rua_hash.c b/libs/ruamoko/rua_hash.c index 98d9722ba..6448e0b1c 100644 --- a/libs/ruamoko/rua_hash.c +++ b/libs/ruamoko/rua_hash.c @@ -64,31 +64,31 @@ typedef struct { static bi_hashtab_t * table_new (hash_resources_t *res) { - PR_RESNEW (bi_hashtab_t, res->table_map); + return PR_RESNEW (res->table_map); } static void table_free (hash_resources_t *res, bi_hashtab_t *table) { - PR_RESFREE (bi_hashtab_t, res->table_map, table); + PR_RESFREE (res->table_map, table); } static void table_reset (hash_resources_t *res) { - PR_RESRESET (bi_hashtab_t, res->table_map); + PR_RESRESET (res->table_map); } static inline bi_hashtab_t * table_get (hash_resources_t *res, int index) { - PR_RESGET(res->table_map, index); + return PR_RESGET(res->table_map, index); } static inline int __attribute__((pure)) table_index (hash_resources_t *res, bi_hashtab_t *table) { - PR_RESINDEX(res->table_map, table); + return PR_RESINDEX(res->table_map, table); } static const char * diff --git a/libs/ruamoko/rua_msgbuf.c b/libs/ruamoko/rua_msgbuf.c index 51c7bcf16..e16525053 100644 --- a/libs/ruamoko/rua_msgbuf.c +++ b/libs/ruamoko/rua_msgbuf.c @@ -58,32 +58,32 @@ typedef struct { static msgbuf_t * msgbuf_new (msgbuf_resources_t *res) { - PR_RESNEW (msgbuf_t, res->msgbuf_map); + return PR_RESNEW (res->msgbuf_map); } static void msgbuf_free (progs_t *pr, msgbuf_resources_t *res, msgbuf_t *msgbuf) { PR_Zone_Free (pr, msgbuf->sizebuf.data); - PR_RESFREE (msgbuf_t, res->msgbuf_map, msgbuf); + PR_RESFREE (res->msgbuf_map, msgbuf); } static void msgbuf_reset (msgbuf_resources_t *res) { - PR_RESRESET (msgbuf_t, res->msgbuf_map); + PR_RESRESET (res->msgbuf_map); } static inline msgbuf_t * msgbuf_get (msgbuf_resources_t *res, int index) { - PR_RESGET(res->msgbuf_map, index); + return PR_RESGET(res->msgbuf_map, index); } static inline int __attribute__((pure)) msgbuf_index (msgbuf_resources_t *res, msgbuf_t *msgbuf) { - PR_RESINDEX(res->msgbuf_map, msgbuf); + return PR_RESINDEX(res->msgbuf_map, msgbuf); } static void diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index 8612cd6f0..a901823b0 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -93,25 +93,25 @@ typedef struct probj_resources_s { static dtable_t * dtable_new (probj_t *probj) { - PR_RESNEW (dtable_t, probj->dtables); + return PR_RESNEW (probj->dtables); } static void dtable_reset (probj_t *probj) { - PR_RESRESET (dtable_t, probj->dtables); + PR_RESRESET (probj->dtables); } static inline dtable_t * dtable_get (probj_t *probj, int index) { - PR_RESGET (probj->dtables, index); + return PR_RESGET (probj->dtables, index); } static inline int __attribute__((pure)) dtable_index (probj_t *probj, dtable_t *dtable) { - PR_RESINDEX (probj->dtables, dtable); + return PR_RESINDEX (probj->dtables, dtable); } static always_inline dtable_t * __attribute__((pure)) diff --git a/libs/ruamoko/rua_plist.c b/libs/ruamoko/rua_plist.c index d8b3c0da1..afccba62e 100644 --- a/libs/ruamoko/rua_plist.c +++ b/libs/ruamoko/rua_plist.c @@ -63,31 +63,31 @@ typedef struct { static bi_plist_t * plist_new (plist_resources_t *res) { - PR_RESNEW (bi_plist_t, res->plist_map); + return PR_RESNEW (res->plist_map); } static void plist_free (plist_resources_t *res, bi_plist_t *plist) { - PR_RESFREE (bi_plist_t, res->plist_map, plist); + PR_RESFREE (res->plist_map, plist); } static void plist_reset (plist_resources_t *res) { - PR_RESRESET (bi_plist_t, res->plist_map); + PR_RESRESET (res->plist_map); } static inline bi_plist_t * plist_get (plist_resources_t *res, unsigned index) { - PR_RESGET(res->plist_map, index); + return PR_RESGET(res->plist_map, index); } static inline int __attribute__((pure)) plist_index (plist_resources_t *res, bi_plist_t *plist) { - PR_RESINDEX(res->plist_map, plist); + return PR_RESINDEX(res->plist_map, plist); } static void diff --git a/libs/ruamoko/rua_qfile.c b/libs/ruamoko/rua_qfile.c index 2f625a949..8c6c45ef1 100644 --- a/libs/ruamoko/rua_qfile.c +++ b/libs/ruamoko/rua_qfile.c @@ -56,31 +56,31 @@ typedef struct { static qfile_t * handle_new (qfile_resources_t *res) { - PR_RESNEW (qfile_t, res->handle_map); + return PR_RESNEW (res->handle_map); } static void handle_free (qfile_resources_t *res, qfile_t *handle) { - PR_RESFREE (qfile_t, res->handle_map, handle); + PR_RESFREE (res->handle_map, handle); } static void handle_reset (qfile_resources_t *res) { - PR_RESRESET (qfile_t, res->handle_map); + PR_RESRESET (res->handle_map); } static inline qfile_t * handle_get (qfile_resources_t *res, int index) { - PR_RESGET(res->handle_map, index); + return PR_RESGET(res->handle_map, index); } static inline int __attribute__((pure)) handle_index (qfile_resources_t *res, qfile_t *handle) { - PR_RESINDEX(res->handle_map, handle); + return PR_RESINDEX(res->handle_map, handle); } static void diff --git a/libs/ruamoko/rua_script.c b/libs/ruamoko/rua_script.c index 7c2cd6666..4723bfcbe 100644 --- a/libs/ruamoko/rua_script.c +++ b/libs/ruamoko/rua_script.c @@ -57,31 +57,31 @@ typedef struct { static rua_script_t * script_new (script_resources_t *res) { - PR_RESNEW (rua_script_t, res->scripts); + return PR_RESNEW (res->scripts); } static void script_free (script_resources_t *res, rua_script_t *script) { - PR_RESFREE (rua_script_t, res->scripts, script); + PR_RESFREE (res->scripts, script); } static void script_reset (script_resources_t *res) { - PR_RESRESET (rua_script_t, res->scripts); + PR_RESRESET (res->scripts); } static inline rua_script_t * script_get (script_resources_t *res, int index) { - PR_RESGET(res->scripts, index); + return PR_RESGET(res->scripts, index); } static inline int __attribute__((pure)) script_index (script_resources_t *res, rua_script_t *script) { - PR_RESINDEX(res->scripts, script); + return PR_RESINDEX(res->scripts, script); } static void diff --git a/libs/ruamoko/rua_set.c b/libs/ruamoko/rua_set.c index 3bc36c06b..343e0ced0 100644 --- a/libs/ruamoko/rua_set.c +++ b/libs/ruamoko/rua_set.c @@ -77,61 +77,61 @@ typedef struct { static bi_set_t * res_set_new (set_resources_t *res) { - PR_RESNEW (bi_set_t, res->set_map); + return PR_RESNEW (res->set_map); } static void res_set_free (set_resources_t *res, bi_set_t *set) { - PR_RESFREE (bi_set_t, res->set_map, set); + PR_RESFREE (res->set_map, set); } static void res_set_reset (set_resources_t *res) { - PR_RESRESET (bi_set_t, res->set_map); + PR_RESRESET (res->set_map); } static inline bi_set_t * res_set_get (set_resources_t *res, int index) { - PR_RESGET(res->set_map, index); + return PR_RESGET(res->set_map, index); } static inline int __attribute__((pure)) res_set_index (set_resources_t *res, bi_set_t *set) { - PR_RESINDEX(res->set_map, set); + return PR_RESINDEX(res->set_map, set); } static bi_set_iter_t * res_set_iter_new (set_resources_t *res) { - PR_RESNEW (bi_set_iter_t, res->set_iter_map); + return PR_RESNEW (res->set_iter_map); } static void res_set_iter_free (set_resources_t *res, bi_set_iter_t *set_iter) { - PR_RESFREE (bi_set_iter_t, res->set_iter_map, set_iter); + PR_RESFREE (res->set_iter_map, set_iter); } static void res_set_iter_reset (set_resources_t *res) { - PR_RESRESET (bi_set_iter_t, res->set_iter_map); + PR_RESRESET (res->set_iter_map); } static inline bi_set_iter_t * res_set_iter_get (set_resources_t *res, int index) { - PR_RESGET(res->set_iter_map, index); + return PR_RESGET(res->set_iter_map, index); } static inline int __attribute__((pure)) res_set_iter_index (set_resources_t *res, bi_set_iter_t *set_iter) { - PR_RESINDEX(res->set_iter_map, set_iter); + return PR_RESINDEX(res->set_iter_map, set_iter); } static bi_set_t * diff --git a/libs/video/renderer/r_progs.c b/libs/video/renderer/r_progs.c index 3f2925fba..c09569c56 100644 --- a/libs/video/renderer/r_progs.c +++ b/libs/video/renderer/r_progs.c @@ -68,7 +68,7 @@ typedef struct { static qpic_res_t * qpic_new (draw_resources_t *res) { - PR_RESNEW (qpic_res_t, res->qpic_map); + return PR_RESNEW (res->qpic_map); } static void @@ -86,25 +86,25 @@ static void qpic_free (draw_resources_t *res, qpic_res_t *qp) { bi_draw_free_qpic (qp); - PR_RESFREE (qpic_res_t, res->qpic_map, qp); + PR_RESFREE (res->qpic_map, qp); } static void qpic_reset (draw_resources_t *res) { - PR_RESRESET (qpic_res_t, res->qpic_map); + PR_RESRESET (res->qpic_map); } static inline qpic_res_t * qpic_get (draw_resources_t *res, int index) { - PR_RESGET (res->qpic_map, index); + return PR_RESGET (res->qpic_map, index); } static inline int __attribute__((pure)) qpic_index (draw_resources_t *res, qpic_res_t *qp) { - PR_RESINDEX (res->qpic_map, qp); + return PR_RESINDEX (res->qpic_map, qp); } static qpic_res_t * diff --git a/ruamoko/qwaq/builtins/curses.c b/ruamoko/qwaq/builtins/curses.c index 0848158f7..cf4f1ebe3 100644 --- a/ruamoko/qwaq/builtins/curses.c +++ b/ruamoko/qwaq/builtins/curses.c @@ -127,31 +127,31 @@ static const char *qwaq_command_names[]= { static window_t * window_new (qwaq_resources_t *res) { - PR_RESNEW (window_t, res->window_map); + return PR_RESNEW (res->window_map); } static void window_free (qwaq_resources_t *res, window_t *win) { - PR_RESFREE (window_t, res->window_map, win); + PR_RESFREE (res->window_map, win); } static void window_reset (qwaq_resources_t *res) { - PR_RESRESET (window_t, res->window_map); + PR_RESRESET (res->window_map); } static inline window_t * window_get (qwaq_resources_t *res, unsigned index) { - PR_RESGET(res->window_map, index); + return PR_RESGET(res->window_map, index); } static inline int __attribute__((pure)) window_index (qwaq_resources_t *res, window_t *win) { - PR_RESINDEX (res->window_map, win); + return PR_RESINDEX (res->window_map, win); } static always_inline window_t * __attribute__((pure)) @@ -173,31 +173,31 @@ get_window (qwaq_resources_t *res, const char *name, int handle) static panel_t * panel_new (qwaq_resources_t *res) { - PR_RESNEW (panel_t, res->panel_map); + return PR_RESNEW (res->panel_map); } static void panel_free (qwaq_resources_t *res, panel_t *win) { - PR_RESFREE (panel_t, res->panel_map, win); + PR_RESFREE (res->panel_map, win); } static void panel_reset (qwaq_resources_t *res) { - PR_RESRESET (panel_t, res->panel_map); + PR_RESRESET (res->panel_map); } static inline panel_t * panel_get (qwaq_resources_t *res, unsigned index) { - PR_RESGET(res->panel_map, index); + return PR_RESGET(res->panel_map, index); } static inline int __attribute__((pure)) panel_index (qwaq_resources_t *res, panel_t *win) { - PR_RESINDEX (res->panel_map, win); + return PR_RESINDEX (res->panel_map, win); } static always_inline panel_t * __attribute__((pure)) diff --git a/ruamoko/qwaq/builtins/debug.c b/ruamoko/qwaq/builtins/debug.c index 19b215e38..a8c56f280 100644 --- a/ruamoko/qwaq/builtins/debug.c +++ b/ruamoko/qwaq/builtins/debug.c @@ -73,31 +73,31 @@ typedef struct qwaq_debug_s { static qwaq_target_t * target_new (qwaq_debug_t *debug) { - PR_RESNEW (qwaq_target_t, debug->targets); + return PR_RESNEW (debug->targets); } static void target_free (qwaq_debug_t *debug, qwaq_target_t *target) { - PR_RESFREE (qwaq_target_t, debug->targets, target); + PR_RESFREE (debug->targets, target); } static void target_reset (qwaq_debug_t *debug) { - PR_RESRESET (qwaq_target_t, debug->targets); + PR_RESRESET (debug->targets); } static inline qwaq_target_t * target_get (qwaq_debug_t *debug, unsigned index) { - PR_RESGET (debug->targets, index); + return PR_RESGET (debug->targets, index); } static inline int __attribute__((pure)) target_index (qwaq_debug_t *debug, qwaq_target_t *target) { - PR_RESINDEX (debug->targets, target); + return PR_RESINDEX (debug->targets, target); } static always_inline qwaq_target_t * __attribute__((pure)) diff --git a/ruamoko/qwaq/builtins/editbuffer.c b/ruamoko/qwaq/builtins/editbuffer.c index d687103d3..666632944 100644 --- a/ruamoko/qwaq/builtins/editbuffer.c +++ b/ruamoko/qwaq/builtins/editbuffer.c @@ -31,31 +31,31 @@ typedef struct qwaq_ebresources_s { static editbuffer_t * editbuffer_new (qwaq_ebresources_t *res) { - PR_RESNEW (editbuffer_t, res->buffers); + return PR_RESNEW (res->buffers); } static void editbuffer_free (qwaq_ebresources_t *res, editbuffer_t *buffer) { - PR_RESFREE (editbuffer_t, res->buffers, buffer); + PR_RESFREE (res->buffers, buffer); } static void editbuffer_reset (qwaq_ebresources_t *res) { - PR_RESRESET (editbuffer_t, res->buffers); + PR_RESRESET (res->buffers); } static inline editbuffer_t * editbuffer_get (qwaq_ebresources_t *res, unsigned index) { - PR_RESGET (res->buffers, index); + return PR_RESGET (res->buffers, index); } static inline int __attribute__((pure)) editbuffer_index (qwaq_ebresources_t *res, editbuffer_t *buffer) { - PR_RESINDEX (res->buffers, buffer); + return PR_RESINDEX (res->buffers, buffer); } static always_inline editbuffer_t * __attribute__((pure)) From ce2ffac078df0179f643ae7fe7f54cf753fee7ae Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 22:33:57 +0900 Subject: [PATCH 425/435] [entity] Free all memory in the unit test Now I know that deleting transforms works properly. --- libs/entity/test/test-hierarchy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/entity/test/test-hierarchy.c b/libs/entity/test/test-hierarchy.c index 7d60f0104..428dfcc5c 100644 --- a/libs/entity/test/test-hierarchy.c +++ b/libs/entity/test/test-hierarchy.c @@ -690,6 +690,8 @@ test_frames (void) return 1; } + Transform_Delete (root); + return 0; } From 1f8c4465a26fe24fe812b19f476baefa9d7bff25 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 23:03:11 +0900 Subject: [PATCH 426/435] [gamecode] Make non-clearing version of PR_RESNEW --- include/QF/progs.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 8b1a6e118..52e81d8a4 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -118,7 +118,7 @@ typedef struct pr_stashed_params_s { alloca(). \param pr pointer to ::progs_t VM struct - \return Pointer to a newly allocated and initialized parameter + \return Pointer to a newly allocated and initialized parameter stash that has the current parameters saved to it. \hideinitializer */ @@ -137,7 +137,7 @@ typedef struct pr_stashed_params_s { \param pr pointer to ::progs_t VM struct \param params location to save the parameters, must be of adequade size to hold \a pr_argc * \a pr_param_size words in \a params - \return \a params Allows the likes of: + \return \a params Allows the likes of: __auto_type params = PR_SaveParams (pr); */ pr_stashed_params_t *_PR_SaveParams (progs_t *pr, pr_stashed_params_t *params); @@ -1536,7 +1536,7 @@ void *PR_Resources_Find (progs_t *pr, const char *name); \return A pointer to the new resource, or null if no more could be allocated. */ -#define PR_RESNEW(map) \ +#define PR_RESNEW_NC(map) \ ({ \ if (!map._free) { \ int i, size; \ @@ -1545,7 +1545,7 @@ void *PR_Resources_Find (progs_t *pr, const char *name); map._map = realloc (map._map, size); \ if (!map._map) \ return 0; \ - map._free = calloc (1024, sizeof (*map._free)); \ + map._free = malloc (1024 * sizeof (*map._free)); \ if (!map._free) \ return 0; \ map._map[map._size - 1] = map._free; \ @@ -1555,6 +1555,12 @@ void *PR_Resources_Find (progs_t *pr, const char *name); } \ __auto_type t = map._free; \ map._free = *(typeof (map._free) *) t; \ + t; \ + }) + +#define PR_RESNEW(map) \ + ({ \ + __auto_type t = PR_RESNEW_NC (map); \ memset (t, 0, sizeof (*map._free)); \ t; \ }) From 410fecd67b097184cbcbfab8ae14b01fc774acad Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 21 Mar 2021 23:05:13 +0900 Subject: [PATCH 427/435] [client] Fix the transform memory leak The transforms aren't actually freed at the end (more work), but at least they aren't lost any more, though one is still lost for the viewent (weapon). The obvious fix didn't work. --- libs/client/cl_temp_entities.c | 80 ++++++++-------------------------- nq/source/cl_ents.c | 8 ++-- 2 files changed, 23 insertions(+), 65 deletions(-) diff --git a/libs/client/cl_temp_entities.c b/libs/client/cl_temp_entities.c index 11ae7632d..fdffbf985 100644 --- a/libs/client/cl_temp_entities.c +++ b/libs/client/cl_temp_entities.c @@ -40,6 +40,7 @@ #include "QF/entity.h" #include "QF/msg.h" +#include "QF/progs.h" // for PR_RESMAP #include "QF/quakefs.h" #include "QF/render.h" #include "QF/sound.h" @@ -54,9 +55,6 @@ typedef struct tent_s { entity_t ent; } tent_t; -#define TEMP_BATCH 64 -static tent_t *temp_entities = 0; - typedef struct { int entity; struct model_s *model; @@ -83,9 +81,11 @@ typedef struct tent_obj_s { } to; } tent_obj_t; -static tent_obj_t *tent_objects; +static PR_RESMAP (tent_t) temp_entities; +static PR_RESMAP (tent_obj_t) tent_objects; static tent_obj_t *cl_beams; static tent_obj_t *cl_explosions; + static tent_t *cl_projectiles; static sfx_t *cl_sfx_wizhit; @@ -158,20 +158,8 @@ CL_Init_Entity (entity_t *ent) static tent_t * new_temp_entity (void) { - tent_t *tent; - if (!temp_entities) { - int i; - - temp_entities = malloc (TEMP_BATCH * sizeof (tent_t)); - for (i = 0; i < TEMP_BATCH - 1; i++) { - temp_entities[i].next = &temp_entities[i + 1]; - temp_entities[i].ent.transform = 0; - } - temp_entities[i].next = 0; - temp_entities[i].ent.transform = 0; - } - tent = temp_entities; - temp_entities = tent->next; + tent_t *tent = PR_RESNEW_NC (temp_entities); + tent->ent.transform = 0; tent->next = 0; CL_Init_Entity (&tent->ent); return tent; @@ -182,63 +170,35 @@ free_temp_entities (tent_t *tents) { tent_t **t = &tents; - while (*t) + while (*t) { + Transform_Delete ((*t)->ent.transform);//FIXME reuse? t = &(*t)->next; - *t = temp_entities; - temp_entities = tents; + } + *t = temp_entities._free; + temp_entities._free = tents; } static tent_obj_t * new_tent_object (void) { - tent_obj_t *tobj; - if (!tent_objects) { - int i; - - tent_objects = malloc (TEMP_BATCH * sizeof (tent_obj_t)); - for (i = 0; i < TEMP_BATCH - 1; i++) - tent_objects[i].next = &tent_objects[i + 1]; - tent_objects[i].next = 0; - } - tobj = tent_objects; - tent_objects = tobj->next; + tent_obj_t *tobj = PR_RESNEW_NC (tent_objects); tobj->next = 0; return tobj; } static void -free_tent_objects (tent_obj_t *tobjs) +free_tent_object (tent_obj_t *tobj) { - tent_obj_t **t = &tobjs; - - while (*t) - t = &(*t)->next; - *t = tent_objects; - tent_objects = tobjs; + tobj->next = tent_objects._free; + tent_objects._free = tobj; } void CL_ClearTEnts (void) { - tent_t *tent; - tent_obj_t *tobj; - - for (tobj = cl_beams; tobj; tobj = tobj->next) { - for (tent = tobj->to.beam.tents; tent; tent = tent->next) { - tent->ent.visibility.efrag = 0; - } - free_temp_entities (tobj->to.beam.tents); - } - free_tent_objects (cl_beams); + PR_RESRESET (temp_entities); + PR_RESRESET (tent_objects); cl_beams = 0; - - for (tobj = cl_explosions; tobj; tobj = tobj->next) { - for (tent = tobj->to.ex.tent; tent; tent = tent->next) { - tent->ent.visibility.efrag = 0; - } - free_temp_entities (tobj->to.ex.tent); - } - free_tent_objects (cl_explosions); cl_explosions = 0; } @@ -618,8 +578,7 @@ CL_UpdateBeams (double time, TEntContext_t *ctx) beam_clear (b); _to = *to; *to = _to->next; - _to->next = tent_objects; - tent_objects = _to; + free_tent_object (_to); continue; } to = &(*to)->next; @@ -663,8 +622,7 @@ CL_UpdateExplosions (double time, TEntContext_t *ctx) free_temp_entities (ex->tent); _to = *to; *to = _to->next; - _to->next = tent_objects; - tent_objects = _to; + free_tent_object (_to); continue; } to = &(*to)->next; diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index d2cab9909..d5c564f28 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -65,15 +65,15 @@ CL_ClearEnts (void) { size_t i; + for (i = 0; i < MAX_EDICTS; i++) { + CL_Init_Entity (cl_entities + i); + } + // clear other arrays - memset (cl_entities, 0, sizeof (cl_entities)); i = nq_entstates.num_frames * nq_entstates.num_entities; memset (nq_entstates.frame[0], 0, i * sizeof (entity_state_t)); memset (cl_msgtime, 0, sizeof (cl_msgtime)); memset (cl_forcelink, 0, sizeof (cl_forcelink)); - - for (i = 0; i < MAX_EDICTS; i++) - CL_Init_Entity (cl_entities + i); } /* From 5173414d97b6093e795a64d24ee9182dad3ca9d5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 22 Mar 2021 13:13:26 +0900 Subject: [PATCH 428/435] [vulkan] Implement light styles Other than dealing with shader data alignment issues, that went well :). Nicely, the implementation gets the explicit scaling out of the shader, and allows for a directional flag. --- include/QF/Vulkan/qf_lighting.h | 4 +++- .../renderer/vulkan/shader/lighting.frag | 15 +++++++++----- libs/video/renderer/vulkan/vulkan_lighting.c | 20 +++++++++++++++---- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h index c269feaae..f6aa67a94 100644 --- a/include/QF/Vulkan/qf_lighting.h +++ b/include/QF/Vulkan/qf_lighting.h @@ -38,7 +38,7 @@ typedef struct qfv_light_s { vec3_t color; - float intensity; + int data; vec3_t position; float radius; vec3_t direction; @@ -50,8 +50,10 @@ typedef struct qfv_lightleafset_s DARRAY_TYPE (int) qfv_lightleafset_t; typedef struct qfv_lightvisset_s DARRAY_TYPE (byte) qfv_lightvisset_t; #define NUM_LIGHTS 256 +#define NUM_STYLES 64 typedef struct qfv_light_buffer_s { + float intensity[NUM_STYLES + 3]; int lightCount; qfv_light_t lights[NUM_LIGHTS] __attribute__((aligned(16))); } qfv_light_buffer_t; diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index b756dd879..98f5b20a6 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -7,7 +7,7 @@ layout (input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput p struct LightData { vec3 color; - float intensity; + int data;// bits 0-6: intensity key (however, values 0-66) vec3 position; float radius; vec3 direction; @@ -16,6 +16,8 @@ struct LightData { layout (constant_id = 0) const int MaxLights = 128; layout (set = 1, binding = 0) uniform Lights { + vec4 intensity[16]; // 64 floats + vec3 intensity2; int lightCount; LightData lights[MaxLights]; }; @@ -32,9 +34,12 @@ calc_light (LightData light, vec3 position, vec3 normal) float lightdot = dot (incoming, normal); float r = light.radius; - float intensity = light.intensity * step (d, r); - intensity *= smoothstep (spotdot, 1 - (1 - spotdot) * 0.995, light.cone) * clamp (lightdot, 0, 1); - return light.color * intensity * (r - d); + int style = light.data & 0x7f; + // deliberate array index error: access intensity2 as well + float i = intensity[style / 4][style % 4]; + i *= step (d, r) * clamp (lightdot, 0, 1); + i *= smoothstep (spotdot, 1 - (1 - spotdot) * 0.995, light.cone); + return light.color * i * (r - d); } void @@ -51,5 +56,5 @@ main (void) light += calc_light (lights[i], p, n); } } - frag_color = vec4 (c * light / 255.0, 1); + frag_color = vec4 (c * light, 1); } diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index b1eecf3d3..56c14387a 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -121,6 +121,14 @@ update_lights (vulkan_ctx_t *ctx) qfv_light_buffer_t *light_data = QFV_PacketExtend (packet, sizeof (*light_data)); + for (int i = 0; i < NUM_STYLES; i++) { + light_data->intensity[i] = d_lightstylevalue[i] / 65536.0; + } + // dynamic lights seem a tad fiant, so 16x map lights + light_data->intensity[64] = 1 / 16.0; + light_data->intensity[65] = 1 / 16.0; + light_data->intensity[66] = 1 / 16.0; + light_data->lightCount = 0; R_FindNearLights (r_origin, NUM_LIGHTS - 1, lights); for (int i = 0; i < NUM_LIGHTS - 1; i++) { @@ -131,7 +139,7 @@ update_lights (vulkan_ctx_t *ctx) VectorCopy (lights[i]->color, light_data->lights[i].color); VectorCopy (lights[i]->origin, light_data->lights[i].position); light_data->lights[i].radius = lights[i]->radius; - light_data->lights[i].intensity = 16; + light_data->lights[i].data = 64; // default dynamic light VectorZero (light_data->lights[i].direction); light_data->lights[i].cone = 1; } @@ -380,7 +388,7 @@ parse_light (qfv_light_t *light, const plitem_t *entity, Sys_Printf ("}\n");*/ light->cone = 1; - light->intensity = 1; + light->data = 0; light->radius = 300; VectorSet (1, 1, 1, light->color); @@ -411,6 +419,10 @@ parse_light (qfv_light_t *light, const plitem_t *entity, light->radius = atof (str); } + if ((str = PL_String (PL_ObjectForKey (entity, "style")))) { + light->data = atoi (str) & 0x3f; + } + if ((str = PL_String (PL_ObjectForKey (entity, "color"))) || (str = PL_String (PL_ObjectForKey (entity, "_color")))) { sscanf (str, "%f %f %f", VectorExpandAddr (light->color)); @@ -467,8 +479,8 @@ Vulkan_LoadLights (model_t *model, const char *entity_data, vulkan_ctx_t *ctx) mleaf_t *leaf = Mod_PointInLeaf (&light.position[0], model); DARRAY_APPEND (&lctx->lightleafs, leaf - model->brush.leafs); - printf ("[%g, %g, %g] %g, [%g %g %g] %g, [%g %g %g] %g, %zd\n", - VectorExpand (light.color), light.intensity, + printf ("[%g, %g, %g] %d, [%g %g %g] %g, [%g %g %g] %g, %zd\n", + VectorExpand (light.color), light.data, VectorExpand (light.position), light.radius, VectorExpand (light.direction), light.cone, leaf - model->brush.leafs); From 4eecbe867d8b57afe01b5f8431b22eaaa6bc11b9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 22 Mar 2021 19:08:16 +0900 Subject: [PATCH 429/435] [vulkan] Implement deferred emission (fullbrights) That was... easier than expected. A little more tedious that I would have liked, but my scripting system isn't perfect (I suspect it's best suited as the output of a code generator), and the C side could do with a little more automation. --- include/QF/Vulkan/qf_lighting.h | 2 +- include/QF/Vulkan/qf_vid.h | 1 + libs/video/renderer/vulkan/deferred.plist | 80 +++++++++++++++---- libs/video/renderer/vulkan/qfpipeline.plist | 28 ++++++- .../renderer/vulkan/shader/alias_gbuf.frag | 8 +- .../renderer/vulkan/shader/bsp_gbuf.frag | 13 +-- .../renderer/vulkan/shader/lighting.frag | 8 +- libs/video/renderer/vulkan/vulkan_lighting.c | 4 +- 8 files changed, 116 insertions(+), 28 deletions(-) diff --git a/include/QF/Vulkan/qf_lighting.h b/include/QF/Vulkan/qf_lighting.h index f6aa67a94..8541d367e 100644 --- a/include/QF/Vulkan/qf_lighting.h +++ b/include/QF/Vulkan/qf_lighting.h @@ -59,7 +59,7 @@ typedef struct qfv_light_buffer_s { } qfv_light_buffer_t; #define LIGHTING_BUFFER_INFOS 1 -#define LIGHTING_IMAGE_INFOS 4 +#define LIGHTING_IMAGE_INFOS 5 typedef struct lightingframe_s { VkCommandBuffer cmd; diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index 5ac5dddd4..e41d91890 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -49,6 +49,7 @@ enum { enum { QFV_attachDepth, QFV_attachColor, + QFV_attachEmission, QFV_attachNormal, QFV_attachPosition, QFV_attachOpaque, diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index 6eded7acb..229c24c10 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -30,6 +30,21 @@ usage = color_attachment|input_attachment|transient_attachment; initialLayout = undefined; }; + emission = { + imageType = VK_IMAGE_TYPE_2D; + format = r16g16b16a16_sfloat; + samples = 1; + extent = { + width = $swapchain.extent.width; + height = $swapchain.extent.height; + depth = 1; + }; + mipLevels = 1; + arrayLayers = 1; + tiling = optimal; + usage = color_attachment|input_attachment|transient_attachment; + initialLayout = undefined; + }; normal = { imageType = VK_IMAGE_TYPE_2D; format = r16g16b16a16_sfloat; @@ -124,6 +139,22 @@ layerCount = 1; }; }; + emission = { + image = emission; + viewType = VK_IMAGE_VIEW_TYPE_2D; + format = $properties.images.emission.format; + components = { + r = identity; + g = identity; + b = identity; + a = identity; + }; + subresourceRange = { + aspectMask = color; + levelCount = 1; + layerCount = 1; + }; + }; normal = { image = normal; viewType = VK_IMAGE_VIEW_TYPE_2D; @@ -191,8 +222,8 @@ }; framebuffer = { renderPass = $properties.renderpass; - attachments = (depth, color, normal, position, opaque, translucent, - "$swapchain.views[$swapImageIndex]"); + attachments = (depth, color, emission, normal, position, opaque, + translucent, "$swapchain.views[$swapImageIndex]"); width = $swapchain.extent.width; height = $swapchain.extent.height; layers = 1; @@ -200,6 +231,7 @@ clearValues = ( { depthStencil = { depth = 1; stencil = 0; }; }, { color = "[0, 0, 0, 1]"; }, // color + { color = "[0, 0, 0, 1]"; }, // emission { color = "[0, 0, 0, 1]"; }, // normal { color = "[0, 0, 0, 1]"; }, // position { color = "[0, 0, 0, 1]"; }, // opaque @@ -228,6 +260,16 @@ initialLayout = undefined; finalLayout = color_attachment_optimal; }, + { + format = $properties.images.emission.format; + samples = 1; + loadOp = dont_care; + storeOp = dont_care; + stencilLoadOp = dont_care; + stencilStoreOp = dont_care; + initialLayout = undefined; + finalLayout = color_attachment_optimal; + }, { format = $properties.images.normal.format; samples = 1; @@ -294,20 +336,24 @@ attachment = 1; layout = color_attachment_optimal; }, - { // normal + { // emission attachment = 2; layout = color_attachment_optimal; }, - { // position + { // normal attachment = 3; layout = color_attachment_optimal; }, + { // position + attachment = 4; + layout = color_attachment_optimal; + }, ); depthStencilAttachment = { attachment = 0; layout = depth_stencil_attachment_optimal; }; - preserveAttachments = (5); + preserveAttachments = (6); }, { // 2 lighting pipelineBindPoint = graphics; @@ -320,52 +366,56 @@ attachment = 1; layout = shader_read_only_optimal; }, - { // normal + { // emission attachment = 2; layout = shader_read_only_optimal; }, - { // position + { // normal attachment = 3; layout = shader_read_only_optimal; }, + { // position + attachment = 4; + layout = shader_read_only_optimal; + }, ); colorAttachments = ( { // opaque - attachment = 4; + attachment = 5; layout = color_attachment_optimal; }, ); - preserveAttachments = (5); + preserveAttachments = (6); }, { // 3 translucent pipelineBindPoint = graphics; colorAttachments = ( { // translucent - attachment = 5; + attachment = 6; layout = color_attachment_optimal; }, ); - preserveAttachments = (0, 1, 2, 3, 4); + preserveAttachments = (0, 1, 2, 3, 4, 5); }, { // 4 compose pipelineBindPoint = graphics; inputAttachments = ( { // opaque - attachment = 4; + attachment = 5; layout = shader_read_only_optimal; }, { // translucent - attachment = 5; + attachment = 6; layout = shader_read_only_optimal; }, ); colorAttachments = ( { // swapchain - attachment = 6; + attachment = 7; layout = color_attachment_optimal; }, ); - preserveAttachments = (0, 1, 2, 3); + preserveAttachments = (0, 1, 2, 3, 4); }, ); dependencies = ( diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 523edfbad..3e8f79274 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -83,7 +83,7 @@ bindings = ( { type = input_attachment; - descriptorCount = "4z * $frames.size"; + descriptorCount = "5z * $frames.size"; }, ); }; @@ -258,6 +258,12 @@ descriptorCount = 1; stageFlags = fragment; }, + { + binding = 4; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, ); }; lighting_lights = { @@ -515,6 +521,16 @@ alphaBlendOp = add; colorWriteMask = r|g|b|a; }, + { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }, ); }; dynamic = { @@ -674,6 +690,16 @@ alphaBlendOp = add; colorWriteMask = r|g|b|a; }, + { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }, { blendEnable = false; srcColorBlendFactor = src_alpha; diff --git a/libs/video/renderer/vulkan/shader/alias_gbuf.frag b/libs/video/renderer/vulkan/shader/alias_gbuf.frag index 0808b87f7..c9cc81db0 100644 --- a/libs/video/renderer/vulkan/shader/alias_gbuf.frag +++ b/libs/video/renderer/vulkan/shader/alias_gbuf.frag @@ -15,20 +15,24 @@ layout (location = 1) in vec4 position; layout (location = 2) in vec3 normal; layout (location = 0) out vec4 frag_color; -layout (location = 1) out vec4 frag_normal; -layout (location = 2) out vec4 frag_position; +layout (location = 1) out vec4 frag_emission; +layout (location = 2) out vec4 frag_normal; +layout (location = 3) out vec4 frag_position; void main (void) { vec4 c; + vec4 e; int i; vec3 light = vec3 (0); c = texture (Skin, vec3 (st, 0)) * unpackUnorm4x8(base_color); c += texture (Skin, vec3 (st, 1)) * unpackUnorm4x8(colorA); c += texture (Skin, vec3 (st, 2)) * unpackUnorm4x8(colorB); + e = texture (Skin, vec3 (st, 3)); frag_color = c; + frag_emission = e; frag_normal = vec4(normal, 1); frag_position = position; } diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.frag b/libs/video/renderer/vulkan/shader/bsp_gbuf.frag index e4578ce5e..c00c0d72d 100644 --- a/libs/video/renderer/vulkan/shader/bsp_gbuf.frag +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.frag @@ -18,8 +18,9 @@ layout (location = 2) in vec3 normal; layout (location = 3) in vec4 position; layout (location = 0) out vec4 frag_color; -layout (location = 1) out vec4 frag_normal; -layout (location = 2) out vec4 frag_position; +layout (location = 1) out vec4 frag_emission; +layout (location = 2) out vec4 frag_normal; +layout (location = 3) out vec4 frag_position; layout (constant_id = 0) const bool doWarp = false; layout (constant_id = 1) const bool doLight = true; @@ -107,7 +108,8 @@ sky_color (vec3 dir, float time) void main (void) { - vec4 c; + vec4 c = vec4 (0); + vec4 e; vec2 t_st = tl_st.xy; vec2 l_st = tl_st.zw; @@ -115,15 +117,16 @@ main (void) t_st = warp_st (t_st, time); } if (doSkyCube || doSkySheet) { - c = sky_color (direction, time); + e = sky_color (direction, time); } else { c = texture (Texture, t_st); if (doLight) { c *= vec4 (texture (LightMap, l_st).xyz, 1); } - c += texture (GlowMap, t_st); + e = texture (GlowMap, t_st); } frag_color = c;//fogBlend (c); + frag_emission = e; frag_normal = vec4 (normal, 0); frag_position = position; } diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index 98f5b20a6..86e496991 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -2,8 +2,9 @@ layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput depth; layout (input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput color; -layout (input_attachment_index = 2, set = 0, binding = 2) uniform subpassInput normal; -layout (input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput position; +layout (input_attachment_index = 2, set = 0, binding = 2) uniform subpassInput emission; +layout (input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput normal; +layout (input_attachment_index = 4, set = 0, binding = 4) uniform subpassInput position; struct LightData { vec3 color; @@ -47,6 +48,7 @@ main (void) { //float d = subpassLoad (depth).r; vec3 c = subpassLoad (color).rgb; + vec3 e = subpassLoad (emission).rgb; vec3 n = subpassLoad (normal).rgb; vec3 p = subpassLoad (position).rgb; vec3 light = vec3 (0); @@ -56,5 +58,5 @@ main (void) light += calc_light (lights[i], p, n); } } - frag_color = vec4 (c * light, 1); + frag_color = vec4 (c * light + e, 1); } diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 56c14387a..69c6faa69 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -214,8 +214,10 @@ Vulkan_Lighting_Draw (vulkan_ctx_t *ctx) lframe->imageInfo[0].imageView = ctx->attachment_views->a[QFV_attachDepth]; lframe->imageInfo[1].imageView = ctx->attachment_views->a[QFV_attachColor]; lframe->imageInfo[2].imageView - = ctx->attachment_views->a[QFV_attachNormal]; + = ctx->attachment_views->a[QFV_attachEmission]; lframe->imageInfo[3].imageView + = ctx->attachment_views->a[QFV_attachNormal]; + lframe->imageInfo[4].imageView = ctx->attachment_views->a[QFV_attachPosition]; dfunc->vkUpdateDescriptorSets (device->dev, LIGHTING_BUFFER_INFOS + LIGHTING_IMAGE_INFOS, From de581501fb257bef2b65a9abcf63f51e0d1f5a79 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 22 Mar 2021 20:33:42 +0900 Subject: [PATCH 430/435] [vulkan] Early out from lights that are too distant Gives a 43% speed boost to bigass1 timedemo (366 -> 525 fps). --- libs/video/renderer/vulkan/shader/lighting.frag | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/video/renderer/vulkan/shader/lighting.frag b/libs/video/renderer/vulkan/shader/lighting.frag index 86e496991..3be1485ee 100644 --- a/libs/video/renderer/vulkan/shader/lighting.frag +++ b/libs/video/renderer/vulkan/shader/lighting.frag @@ -28,12 +28,17 @@ layout (location = 0) out vec4 frag_color; vec3 calc_light (LightData light, vec3 position, vec3 normal) { + float r = light.radius; vec3 dist = light.position - position; float d = sqrt (dot (dist, dist)); + if (d > r) { + // the light is too far away + return vec3 (0); + } + vec3 incoming = dist / d; float spotdot = dot (incoming, light.direction); float lightdot = dot (incoming, normal); - float r = light.radius; int style = light.data & 0x7f; // deliberate array index error: access intensity2 as well From 81956095f1e278b2864a3babb2663a37bf48b3d8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Mar 2021 08:25:56 +0900 Subject: [PATCH 431/435] [vulkan] Use correct vertex shader for skys This gets skys rendering again, but their depth is incorrect. --- include/QF/Vulkan/qf_vid.h | 4 ++-- libs/video/renderer/vulkan/qfpipeline.plist | 4 ++-- libs/video/renderer/vulkan/vulkan_bsp.c | 21 +++++++++++---------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index e41d91890..f2d9bf0ec 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -36,7 +36,7 @@ #include //FIXME location -enum { +typedef enum { QFV_passDepth, // geometry QFV_passGBuffer, // geometry QFV_passLighting, // single quad @@ -44,7 +44,7 @@ enum { QFV_passCompose, // single quad QFV_NumPasses -}; +} QFV_Subpass; enum { QFV_attachDepth, diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 3e8f79274..61687a721 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -719,12 +719,12 @@ //renderPass = renderpass; }; bsp_skysheet = { - subpass = 2; + subpass = 3; stages = ( { stage = vertex; name = main; - module = $builtin/bsp_gbuf.vert; + module = $builtin/quakebsp.vert; }, { stage = fragment; diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index 937876dc9..cd5b1e022 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -75,6 +75,12 @@ static const char *bsp_pass_names[] = { "translucent", }; +static QFV_Subpass subpass_map[] = { + QFV_passDepth, // QFV_bspDepth + QFV_passGBuffer, // QFV_bspGBuffer + QFV_passTranslucent, // QFV_bspTranslucent +}; + static float identity[] = { 1, 0, 0, 0, 0, 1, 0, 0, @@ -872,7 +878,7 @@ bsp_begin_subpass (QFV_BspSubpass subpass, VkPipeline pipeline, dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, - ctx->renderpass, subpass, + ctx->renderpass, subpass_map[subpass], cframe->framebuffer, 0, 0, 0, }; @@ -883,6 +889,9 @@ bsp_begin_subpass (QFV_BspSubpass subpass, VkPipeline pipeline, }; dfunc->vkBeginCommandBuffer (cmd, &beginInfo); + QFV_duCmdBeginLabel (device, cmd, bsp_pass_names[subpass], + {0, 0.5, 0.6, 1}); + dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); VkViewport viewport = {0, 0, vid.width, vid.height, 0, 1}; @@ -914,6 +923,7 @@ bsp_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx) qfv_device_t *device = ctx->device; qfv_devfuncs_t *dfunc = device->funcs; + QFV_duCmdEndLabel (device, cmd); dfunc->vkEndCommandBuffer (cmd); } @@ -1274,15 +1284,6 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) fragconst_t frag_constants = { time: vr_data.realtime }; push_fragconst (&frag_constants, bctx->layout, dfunc, bframe->cmdSet.a[QFV_bspTranslucent]); - bind_view (qfv_bsp_texture, ctx->default_black->view, bframe, - bframe->cmdSet.a[QFV_bspTranslucent],//FIXME - bctx->layout, dfunc); - bind_view (qfv_bsp_glowmap, ctx->default_black->view, bframe, - bframe->cmdSet.a[QFV_bspTranslucent],//FIXME - bctx->layout, dfunc); - bind_view (qfv_bsp_lightmap, ctx->default_black->view, bframe, - bframe->cmdSet.a[QFV_bspTranslucent],//FIXME - bctx->layout, dfunc); for (is = bctx->sky_chain; is; is = is->tex_chain) { surf = is->surface; if (tex != surf->texinfo->texture->render) { From d4e1bfb8b82939189dee8c98b491c163a2deebf5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Mar 2021 10:01:13 +0900 Subject: [PATCH 432/435] [vulkan] Clean up the pipeline specifications While being able to write pipeline specs like this was the end goal of the parsing sub-project, I didn't realize it was already usable. This sure makes going through the pipeline specs much easier. --- libs/video/renderer/vulkan/qfpipeline.plist | 751 ++++++-------------- 1 file changed, 233 insertions(+), 518 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 61687a721..138d80855 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -335,6 +335,169 @@ setLayouts = (compose_attach); }; }; + + depthStencil = { + test_and_write = { + depthTestEnable = true; + depthWriteEnable = true; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + test_only = { + depthTestEnable = true; + depthWriteEnable = false; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + disable = { + depthTestEnable = false; + depthWriteEnable = false; + depthCompareOp = less_or_equal; + depthBoundsTestEnable = false; + stencilTestEnable = false; + }; + }; + + inputAssembly = { + alias = { + topology = triangle_list; + primitiveRestartEnable = false; + }; + brush = { + topology = triangle_fan; + primitiveRestartEnable = true; + }; + twod = { + topology = triangle_strip; + primitiveRestartEnable = true; + }; + }; + + vertexInput = { + alias = { + bindings = ( + { binding = 0; stride = "2 * 4 * 4"; inputRate = vertex; }, + { binding = 1; stride = "2 * 4 * 4"; inputRate = vertex; }, + { binding = 2; stride = "2 * 4"; inputRate = vertex; }, + ); + attributes = ( + { location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0; }, + { location = 1; binding = 0; format = r32g32b32a32_sfloat; offset = 16; }, + { location = 2; binding = 1; format = r32g32b32a32_sfloat; offset = 0; }, + { location = 3; binding = 1; format = r32g32b32a32_sfloat; offset = 16; }, + { location = 4; binding = 2; format = r32g32_sfloat; offset = 0; }, + ); + }; + brush = { + bindings = ( + { binding = 0; stride = "2 * 4 * 4"; inputRate = vertex; }, + ); + attributes = ( + { location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0; }, + { location = 1; binding = 0; format = r32g32b32a32_sfloat; offset = 16; }, + ); + }; + twod = { + bindings = ( + { binding = 0; stride = "2 * 4 * 4"; inputRate = vertex; }, + ); + attributes = ( + { location = 0; binding = 0; format = r32g32_sfloat; offset = 0; }, + { location = 1; binding = 0; format = r32g32_sfloat; offset = 8; }, + { location = 2; binding = 0; format = r32g32b32a32_sfloat; offset = 16; }, + ); + }; + }; + + rasterization = { + cw_cull_back = { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = fill; + cullMode = back; + frontFace = clockwise; + depthBiasEnable = false; + lineWidth = 1; + }; + counter_cw_cull_back = { + depthClampEnable = false; + rasterizerDiscardEnable = false; + polygonMode = fill; + cullMode = back; + frontFace = counter_clockwise; + depthBiasEnable = false; + lineWidth = 1; + }; + }; + + multisample = { + rasterizationSamples = $msaaSamples; + sampleShadingEnable = false; + minSampleShading = 0.5f; + alphaToCoverageEnable = false; + alphaToOneEnable = false; + }; + + viewport = { + viewports = ( + { + x = 0; y = 0; + width = 640; height = 480; + minDepth = 0; maxDepth = 1; + } + ); + scissors = ( + { + offset = { x = 0; y = 0 }; + extent = { width = 640; height = 480; }; + }, + ); + }; + + attachmentBlendOp = { + disabled = { + blendEnable = false; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }; + alpha_blend = { + blendEnable = true; + srcColorBlendFactor = src_alpha; + dstColorBlendFactor = one_minus_src_alpha; + colorBlendOp = add; + srcAlphaBlendFactor = src_alpha; + dstAlphaBlendFactor = one_minus_src_alpha; + alphaBlendOp = add; + colorWriteMask = r|g|b|a; + }; + }; + + fsquad = { + vertexInput = { + bindings = ( + { binding = 0; stride = "4 * 4"; inputRate = vertex; }, + ); + attributes = ( + { location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0; }, + ); + }; + inputAssembly = { + topology = triangle_strip; + primitiveRestartEnable = false; + }; + colorBlend = { + logicOpEnable = false; + attachments = ($properties.attachmentBlendOp.disabled); + }; + }; + pipelines = { alias_depth = { subpass = 0; @@ -346,29 +509,24 @@ }, ); vertexInput = { + // depth pass doesn't use UVs bindings = ( - "$properties.pipelines.alias_gbuf.vertexInput.bindings[0]", - "$properties.pipelines.alias_gbuf.vertexInput.bindings[1]", + "$properties.vertexInput.alias.bindings[0]", + "$properties.vertexInput.alias.bindings[1]", ); attributes = ( - "$properties.pipelines.alias_gbuf.vertexInput.attributes[0]", - "$properties.pipelines.alias_gbuf.vertexInput.attributes[1]", - "$properties.pipelines.alias_gbuf.vertexInput.attributes[2]", - "$properties.pipelines.alias_gbuf.vertexInput.attributes[3]", + "$properties.vertexInput.alias.attributes[0]", + "$properties.vertexInput.alias.attributes[1]", + "$properties.vertexInput.alias.attributes[2]", + "$properties.vertexInput.alias.attributes[3]", ); }; - inputAssembly = $properties.pipelines.alias_gbuf.inputAssembly; - viewport = $properties.pipelines.alias_gbuf.viewport; - rasterization = $properties.pipelines.alias_gbuf.rasterization; - multisample = $properties.pipelines.alias_gbuf.multisample; - depthStencil = { - depthTestEnable = true; - depthWriteEnable = true; - depthCompareOp = less_or_equal; - depthBoundsTestEnable = false; - stencilTestEnable = false; - }; - colorBlend = $properties.pipelines.alias_gbuf.colorBlend; + inputAssembly = $properties.inputAssembly.alias; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_and_write; + colorBlend = $properties.pipelines.alias_gbuf.colorBlend; dynamic = { dynamicState = ( viewport, scissor ); }; @@ -395,142 +553,19 @@ }; }, ); - vertexInput = { - bindings = ( - { - binding = 0; - stride = "2 * 4 * 4"; - inputRate = vertex; - }, - { - binding = 1; - stride = "2 * 4 * 4"; - inputRate = vertex; - }, - { - binding = 2; - stride = "2 * 4"; - inputRate = vertex; - }, - ); - attributes = ( - { - location = 0; - binding = 0; - format = r32g32b32a32_sfloat; - offset = 0; - }, - { - location = 1; - binding = 0; - format = r32g32b32a32_sfloat; - offset = 16; - }, - { - location = 2; - binding = 1; - format = r32g32b32a32_sfloat; - offset = 0; - }, - { - location = 3; - binding = 1; - format = r32g32b32a32_sfloat; - offset = 16; - }, - { - location = 4; - binding = 2; - format = r32g32_sfloat; - offset = 0; - }, - ); - }; - inputAssembly = { - topology = triangle_list; - primitiveRestartEnable = false; - }; - viewport = { - viewports = ( - { - x = 0; y = 0; - width = 640; height = 480; - minDepth = 0; maxDepth = 1; - } - ); - scissors = ( - { - offset = { x = 0; y = 0 }; - extent = { width = 640; height = 480; }; - }, - ); - }; - rasterization = { - depthClampEnable = false; - rasterizerDiscardEnable = false; - polygonMode = fill; - cullMode = back; - frontFace = clockwise; - depthBiasEnable = false; - lineWidth = 1; - }; - multisample = { - rasterizationSamples = $msaaSamples; - sampleShadingEnable = false; - minSampleShading = 0.5f; - alphaToCoverageEnable = false; - alphaToOneEnable = false; - }; - depthStencil = { - depthTestEnable = true; - depthWriteEnable = true; - depthCompareOp = less_or_equal; - depthBoundsTestEnable = false; - stencilTestEnable = false; - }; + vertexInput = $properties.vertexInput.alias; + inputAssembly = $properties.inputAssembly.alias; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_only; colorBlend = { logicOpEnable = false; attachments = ( - { - blendEnable = false; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }, - { - blendEnable = false; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }, - { - blendEnable = false; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }, - { - blendEnable = false; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }, + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, ); }; dynamic = { @@ -550,24 +585,18 @@ ); vertexInput = { bindings = ( - "$properties.pipelines.bsp_gbuf.vertexInput.bindings[0]", + "$properties.vertexInput.brush.bindings[0]", ); attributes = ( - "$properties.pipelines.bsp_gbuf.vertexInput.attributes[0]", + "$properties.vertexInput.brush.attributes[0]", ); }; - inputAssembly = $properties.pipelines.bsp_gbuf.inputAssembly; - viewport = $properties.pipelines.bsp_gbuf.viewport; - rasterization = $properties.pipelines.bsp_gbuf.rasterization; - multisample = $properties.pipelines.bsp_gbuf.multisample; - depthStencil = { - depthTestEnable = true; - depthWriteEnable = true; - depthCompareOp = less_or_equal; - depthBoundsTestEnable = false; - stencilTestEnable = false; - }; - colorBlend = $properties.pipelines.bsp_gbuf.colorBlend; + inputAssembly = $properties.inputAssembly.brush; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_and_write; + colorBlend = $properties.pipelines.bsp_gbuf.colorBlend; dynamic = { dynamicState = ( viewport, scissor ); }; @@ -596,120 +625,25 @@ { size = 4; offset = 0; constantID = 0; }, { size = 4; offset = 0; constantID = 1; }, { size = 4; offset = 0; constantID = 2; }, - { size = 4; offset = 4; constantID = 1; }, + { size = 4; offset = 0; constantID = 3; }, ); data = <00000000ffffffff>; }; }, ); - vertexInput = { - bindings = ( - { - binding = 0; - stride = "2 * 4 * 4"; - inputRate = vertex; - }, - ); - attributes = ( - { - location = 0; - binding = 0; - format = r32g32b32a32_sfloat; - offset = 0; - }, - { - location = 1; - binding = 0; - format = r32g32b32a32_sfloat; - offset = 16; - }, - ); - }; - inputAssembly = { - topology = triangle_fan; - primitiveRestartEnable = true; - }; - viewport = { - viewports = ( - { - x = 0; y = 0; - width = 640; height = 480; - minDepth = 0; maxDepth = 1; - } - ); - scissors = ( - { - offset = { x = 0; y = 0 }; - extent = { width = 640; height = 480; }; - }, - ); - }; - rasterization = { - depthClampEnable = false; - rasterizerDiscardEnable = false; - polygonMode = fill; - cullMode = back; - frontFace = clockwise; - depthBiasEnable = false; - lineWidth = 1; - }; - multisample = { - rasterizationSamples = $msaaSamples; - sampleShadingEnable = false; - minSampleShading = 0.5f; - alphaToCoverageEnable = false; - alphaToOneEnable = false; - }; - depthStencil = { - depthTestEnable = true; - depthWriteEnable = true; - depthCompareOp = less_or_equal; - depthBoundsTestEnable = false; - stencilTestEnable = false; - }; + vertexInput = $properties.vertexInput.brush; + inputAssembly = $properties.inputAssembly.brush; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_only; colorBlend = { logicOpEnable = false; attachments = ( - { - blendEnable = false; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }, - { - blendEnable = false; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }, - { - blendEnable = false; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }, - { - blendEnable = false; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - } + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, + $properties.attachmentBlendOp.disabled, ); }; dynamic = { @@ -739,26 +673,15 @@ }; }, ); - vertexInput = $properties.pipelines.bsp_gbuf.vertexInput; - inputAssembly = $properties.pipelines.bsp_gbuf.inputAssembly; - viewport = $properties.pipelines.bsp_gbuf.viewport; - rasterization = $properties.pipelines.bsp_gbuf.rasterization; - multisample = $properties.pipelines.bsp_gbuf.multisample; - depthStencil = $properties.pipelines.bsp_gbuf.depthStencil; + vertexInput = $properties.vertexInput.brush; + inputAssembly = $properties.inputAssembly.brush; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_only; colorBlend = { logicOpEnable = false; - attachments = ( - { - blendEnable = false; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }, - ); + attachments = ($properties.attachmentBlendOp.disabled); }; dynamic = { dynamicState = ( viewport, scissor ); @@ -780,89 +703,15 @@ module = $builtin/twod.frag; }, ); - vertexInput = { - bindings = ( - { - binding = 0; - stride = "2 * 4 * 4"; - inputRate = vertex; - }, - ); - attributes = ( - { - location = 0; - binding = 0; - format = r32g32_sfloat; - offset = 0; - }, - { - location = 1; - binding = 0; - format = r32g32_sfloat; - offset = 8; - }, - { - location = 2; - binding = 0; - format = r32g32b32a32_sfloat; - offset = 16; - }, - ); - }; - inputAssembly = { - topology = triangle_strip; - primitiveRestartEnable = true; - }; - viewport = { - viewports = ( - { - x = 0; y = 0; - width = 640; height = 480; - minDepth = 0; maxDepth = 1; - } - ); - scissors = ( - { - offset = { x = 0; y = 0 }; - extent = { width = 640; height = 480; }; - }, - ); - }; - rasterization = { - depthClampEnable = false; - rasterizerDiscardEnable = false; - polygonMode = fill; - cullMode = back; - frontFace = counter_clockwise; - depthBiasEnable = false; - lineWidth = 1; - }; - multisample = { - rasterizationSamples = $msaaSamples; - sampleShadingEnable = false; - minSampleShading = 0.5f; - alphaToCoverageEnable = false; - alphaToOneEnable = false; - }; - depthStencil = { - depthTestEnable = true; - depthWriteEnable = true; - depthCompareOp = less_or_equal; - depthBoundsTestEnable = false; - stencilTestEnable = false; - }; + vertexInput = $properties.vertexInput.twod; + inputAssembly = $properties.inputAssembly.twod; + viewport = $properties.viewport; + rasterization = $properties.rasterization.counter_cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_and_write; colorBlend = { logicOpEnable = false; - attachments = ({ - blendEnable = true; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }); + attachments = ($properties.attachmentBlendOp.alpha_blend); }; dynamic = { dynamicState = ( viewport, scissor ); @@ -890,80 +739,13 @@ }; }, ); - vertexInput = { - bindings = ( - { - binding = 0; - stride = "4 * 4"; - inputRate = vertex; - }, - ); - attributes = ( - { - location = 0; - binding = 0; - format = r32g32b32a32_sfloat; - offset = 0; - }, - ); - }; - inputAssembly = { - topology = triangle_strip; - primitiveRestartEnable = false; - }; - viewport = { - viewports = ( - { - x = 0; y = 0; - width = 640; height = 480; - minDepth = 0; maxDepth = 1; - } - ); - scissors = ( - { - offset = { x = 0; y = 0 }; - extent = { width = 640; height = 480; }; - }, - ); - }; - rasterization = { - depthClampEnable = false; - rasterizerDiscardEnable = false; - polygonMode = fill; - cullMode = back; - frontFace = counter_clockwise; - depthBiasEnable = false; - lineWidth = 1; - }; - multisample = { - rasterizationSamples = $msaaSamples; - sampleShadingEnable = false; - minSampleShading = 0.5f; - alphaToCoverageEnable = false; - alphaToOneEnable = false; - }; - depthStencil = { - depthTestEnable = false; - depthWriteEnable = false; - depthCompareOp = less_or_equal; - depthBoundsTestEnable = false; - stencilTestEnable = false; - }; - colorBlend = { - logicOpEnable = false; - attachments = ( - { - blendEnable = false; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }, - ); - }; + vertexInput = $properties.fsquad.vertexInput; + inputAssembly = $properties.fsquad.inputAssembly; + viewport = $properties.viewport; + rasterization = $properties.rasterization.counter_cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.disable; + colorBlend = $properties.fsquad.colorBlend; dynamic = { dynamicState = ( viewport, scissor ); }; @@ -984,80 +766,13 @@ module = $builtin/compose.frag; }, ); - vertexInput = { - bindings = ( - { - binding = 0; - stride = "4 * 4"; - inputRate = vertex; - }, - ); - attributes = ( - { - location = 0; - binding = 0; - format = r32g32b32a32_sfloat; - offset = 0; - }, - ); - }; - inputAssembly = { - topology = triangle_strip; - primitiveRestartEnable = false; - }; - viewport = { - viewports = ( - { - x = 0; y = 0; - width = 640; height = 480; - minDepth = 0; maxDepth = 1; - } - ); - scissors = ( - { - offset = { x = 0; y = 0 }; - extent = { width = 640; height = 480; }; - }, - ); - }; - rasterization = { - depthClampEnable = false; - rasterizerDiscardEnable = false; - polygonMode = fill; - cullMode = back; - frontFace = counter_clockwise; - depthBiasEnable = false; - lineWidth = 1; - }; - multisample = { - rasterizationSamples = $msaaSamples; - sampleShadingEnable = false; - minSampleShading = 0.5f; - alphaToCoverageEnable = false; - alphaToOneEnable = false; - }; - depthStencil = { - depthTestEnable = false; - depthWriteEnable = false; - depthCompareOp = less_or_equal; - depthBoundsTestEnable = false; - stencilTestEnable = false; - }; - colorBlend = { - logicOpEnable = false; - attachments = ( - { - blendEnable = false; - srcColorBlendFactor = src_alpha; - dstColorBlendFactor = one_minus_src_alpha; - colorBlendOp = add; - srcAlphaBlendFactor = src_alpha; - dstAlphaBlendFactor = one_minus_src_alpha; - alphaBlendOp = add; - colorWriteMask = r|g|b|a; - }, - ); - }; + vertexInput = $properties.fsquad.vertexInput; + inputAssembly = $properties.fsquad.inputAssembly; + viewport = $properties.viewport; + rasterization = $properties.rasterization.counter_cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.disable; + colorBlend = $properties.fsquad.colorBlend; dynamic = { dynamicState = ( viewport, scissor ); }; From 5ac807d4b2b9783dcfb4c78aaeafe12071909cfb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Mar 2021 10:12:26 +0900 Subject: [PATCH 433/435] [vulkan] Remove the old forward renderpass spec I doubt I'll go back to it, and it was in the wrong place anyway. --- libs/video/renderer/vulkan/qfpipeline.plist | 141 -------------------- 1 file changed, 141 deletions(-) diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 138d80855..54bc0f9af 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -780,145 +780,4 @@ //renderPass = renderpass; }; }; - renderpass = { - attachments = ( - { - flags = 0; - format = $swapchain.format; - samples = 1; - loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - storeOp = VK_ATTACHMENT_STORE_OP_STORE; - stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - }, - { - flags = 0; - format = VK_FORMAT_D32_SFLOAT; - samples = 1; - loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - }, - ); - subpasses = ( - { - pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - colorAttachments = ( - { - attachment = 0; - layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } - ); - depthStencilAttachment = { - attachment = 1; - layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - }; - preserveAttachments = (); - }, - ); - dependencies = ( - { - srcSubpass = VK_SUBPASS_EXTERNAL; - dstSubpass = 0; - srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - }, - { - srcSubpass = 0; - dstSubpass = VK_SUBPASS_EXTERNAL; - srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - }, - ); - }; - renderpass_msaa = { - attachments = ( - { - flags = 0; - format = $swapchain.format; - samples = VK_SAMPLE_COUNT_1_BIT; - loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - storeOp = VK_ATTACHMENT_STORE_OP_STORE; - stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - }, - { - flags = 0; - format = VK_FORMAT_D32_SFLOAT; - samples = $msaaSamples; - loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - }, - { - flags = 0; - format = $swapchain.format; - samples = $msaaSamples; - loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - storeOp = VK_ATTACHMENT_STORE_OP_STORE; - stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - }, - ); - subpasses = ( - { - pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - colorAttachments = ( - { - attachment = 2; - layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } - ); - resolveAttachments = ( - { - attachment = 0; - layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } - ); - depthStencilAttachment = { - attachment = 1; - layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - }; - preserveAttachments = (); - }, - ); - dependencies = ( - { - srcSubpass = VK_SUBPASS_EXTERNAL; - dstSubpass = 0; - srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - }, - { - srcSubpass = 0; - dstSubpass = VK_SUBPASS_EXTERNAL; - srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; - }, - ); - }; } From 6e0312658d259ecd0a534b679fdf0efcfbb1fcdd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Mar 2021 11:26:24 +0900 Subject: [PATCH 434/435] [vulkan] Fix sky depth issues There were actually several problems: translucency wasn't using or depending on the depth buffer, and the depth buffer wasn't marked as read-only in the g-buffer pass. Getting that correct seems to have given bigass1 a 0.5% boost (hard to say, could be the usual noise). --- include/QF/Vulkan/qf_vid.h | 2 +- libs/video/renderer/vulkan/deferred.plist | 49 +++++++++++++-------- libs/video/renderer/vulkan/qfpipeline.plist | 12 ++--- libs/video/renderer/vulkan/vulkan_alias.c | 8 +++- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index f2d9bf0ec..b01000d06 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -38,9 +38,9 @@ //FIXME location typedef enum { QFV_passDepth, // geometry + QFV_passTranslucent, // geometry QFV_passGBuffer, // geometry QFV_passLighting, // single quad - QFV_passTranslucent, // geometry QFV_passCompose, // single quad QFV_NumPasses diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index 229c24c10..d956a5792 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -329,7 +329,21 @@ layout = depth_stencil_attachment_optimal; }; }, - { // 1 g-buffer generation + { // 1 translucent + pipelineBindPoint = graphics; + colorAttachments = ( + { // translucent + attachment = 6; + layout = color_attachment_optimal; + }, + ); + depthStencilAttachment = { + attachment = 0; + layout = depth_stencil_read_only_optimal; + }; + preserveAttachments = (1, 2, 3, 4, 5); + }, + { // 2 g-buffer generation pipelineBindPoint = graphics; colorAttachments = ( { // color @@ -351,11 +365,11 @@ ); depthStencilAttachment = { attachment = 0; - layout = depth_stencil_attachment_optimal; + layout = depth_stencil_read_only_optimal; }; preserveAttachments = (6); }, - { // 2 lighting + { // 3 lighting pipelineBindPoint = graphics; inputAttachments = ( { // depth @@ -387,16 +401,6 @@ ); preserveAttachments = (6); }, - { // 3 translucent - pipelineBindPoint = graphics; - colorAttachments = ( - { // translucent - attachment = 6; - layout = color_attachment_optimal; - }, - ); - preserveAttachments = (0, 1, 2, 3, 4, 5); - }, { // 4 compose pipelineBindPoint = graphics; inputAttachments = ( @@ -421,7 +425,7 @@ dependencies = ( { srcSubpass = 0; // depth - dstSubpass = 1; // g-buffer + dstSubpass = 1; // translucent srcStageMask = color_attachment_output; dstStageMask = fragment_shader; srcAccessMask = color_attachment_write; @@ -429,8 +433,8 @@ dependencyFlags = by_region; }, { - srcSubpass = 1; // g-buffer - dstSubpass = 2; // lighting + srcSubpass = 0; // depth + dstSubpass = 2; // g-buffer srcStageMask = color_attachment_output; dstStageMask = fragment_shader; srcAccessMask = color_attachment_write; @@ -438,7 +442,16 @@ dependencyFlags = by_region; }, { - srcSubpass = 2; // lighting + srcSubpass = 2; // g-buffer + dstSubpass = 3; // lighting + srcStageMask = color_attachment_output; + dstStageMask = fragment_shader; + srcAccessMask = color_attachment_write; + dstAccessMask = shader_read; + dependencyFlags = by_region; + }, + { + srcSubpass = 3; // lighting dstSubpass = 4; // compose srcStageMask = color_attachment_output; dstStageMask = fragment_shader; @@ -447,7 +460,7 @@ dependencyFlags = by_region; }, { - srcSubpass = 3; // translucent + srcSubpass = 1; // translucent dstSubpass = 4; // compose srcStageMask = color_attachment_output; dstStageMask = fragment_shader; diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 54bc0f9af..97bcc9251 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -534,7 +534,7 @@ //renderPass = renderpass; }; alias_gbuf = { - subpass = 1; + subpass = 2; stages = ( { stage = vertex; @@ -604,7 +604,7 @@ //renderPass = renderpass; }; bsp_gbuf = { - subpass = 1; + subpass = 2; stages = ( { stage = vertex; @@ -653,7 +653,7 @@ //renderPass = renderpass; }; bsp_skysheet = { - subpass = 3; + subpass = 1; stages = ( { stage = vertex; @@ -690,7 +690,7 @@ //renderPass = renderpass; }; twod = { - subpass = 3; + subpass = 1; stages = ( { stage = vertex; @@ -708,7 +708,7 @@ viewport = $properties.viewport; rasterization = $properties.rasterization.counter_cw_cull_back; multisample = $properties.multisample; - depthStencil = $properties.depthStencil.test_and_write; + depthStencil = $properties.depthStencil.test_only; colorBlend = { logicOpEnable = false; attachments = ($properties.attachmentBlendOp.alpha_blend); @@ -720,7 +720,7 @@ //renderPass = renderpass; }; lighting = { - subpass = 2; + subpass = 3; stages = ( { stage = vertex; diff --git a/libs/video/renderer/vulkan/vulkan_alias.c b/libs/video/renderer/vulkan/vulkan_alias.c index 25a2d9d13..c2581e773 100644 --- a/libs/video/renderer/vulkan/vulkan_alias.c +++ b/libs/video/renderer/vulkan/vulkan_alias.c @@ -70,6 +70,12 @@ static const char *alias_pass_names[] = { "translucent", }; +static QFV_Subpass subpass_map[] = { + QFV_passDepth, // QFV_aliasDepth + QFV_passGBuffer, // QFV_aliasGBuffer + QFV_passTranslucent, // QFV_aliasTranslucent +}; + static void emit_commands (VkCommandBuffer cmd, int pose1, int pose2, qfv_alias_skin_t *skin, @@ -174,7 +180,7 @@ alias_begin_subpass (QFV_AliasSubpass subpass, VkPipeline pipeline, dfunc->vkResetCommandBuffer (cmd, 0); VkCommandBufferInheritanceInfo inherit = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0, - ctx->renderpass, subpass, + ctx->renderpass, subpass_map[subpass], cframe->framebuffer, 0, 0, 0, }; From 7e946a4de942e1b3865913ad1e2eff67c067bed7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Mar 2021 12:24:24 +0900 Subject: [PATCH 435/435] [vulkan] Implement water surface rendering They're unlit (fullbright, but that's nothing new for quake), but working nicely. As a bonus, sort out the sky pass (forced to due to the way command buffers are used). --- include/QF/Vulkan/qf_bsp.h | 4 +- libs/video/renderer/Makemodule.am | 5 + libs/video/renderer/vulkan/qfpipeline.plist | 37 +++++ libs/video/renderer/vulkan/shader.c | 3 + .../renderer/vulkan/shader/bsp_turb.frag | 52 ++++++ libs/video/renderer/vulkan/vulkan_bsp.c | 150 +++++++++--------- 6 files changed, 173 insertions(+), 78 deletions(-) create mode 100644 libs/video/renderer/vulkan/shader/bsp_turb.frag diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index ff3f6612a..7f279ffc2 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -73,7 +73,8 @@ typedef enum { typedef enum { QFV_bspDepth, QFV_bspGBuffer, - QFV_bspTranslucent, + QFV_bspSky, + QFV_bspTurb, QFV_bspNumPasses } QFV_BspSubpass; @@ -146,6 +147,7 @@ typedef struct bspctx_s { VkPipeline depth; VkPipeline gbuf; VkPipeline sky; + VkPipeline turb; VkPipelineLayout layout; size_t vertex_buffer_size; size_t index_buffer_size; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 8c459dd1c..d21a7952d 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -313,6 +313,8 @@ bsp_gbuff_src = $(vkshaderpath)/bsp_gbuf.frag bsp_gbuff_c = $(vkshaderpath)/bsp_gbuf.frag.spvc bsp_skyf_src = $(vkshaderpath)/bsp_sky.frag bsp_skyf_c = $(vkshaderpath)/bsp_sky.frag.spvc +bsp_turbf_src = $(vkshaderpath)/bsp_turb.frag +bsp_turbf_c = $(vkshaderpath)/bsp_turb.frag.spvc lightingf_src = $(vkshaderpath)/lighting.frag lightingf_c = $(vkshaderpath)/lighting.frag.spvc composef_src = $(vkshaderpath)/compose.frag @@ -348,6 +350,8 @@ $(bsp_gbuff_c): $(bsp_gbuff_src) $(bsp_skyf_c): $(bsp_skyf_src) +$(bsp_turbf_c): $(bsp_turbf_src) + $(lightingf_c): $(lightingf_src) $(composef_c): $(composef_src) @@ -374,6 +378,7 @@ vkshader_c = \ $(bsp_gbufg_c) \ $(bsp_gbuff_c) \ $(bsp_skyf_c) \ + $(bsp_turbf_c) \ $(lightingf_c) \ $(composef_c) \ $(aliasv_c) \ diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 97bcc9251..2d95f06b4 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -689,6 +689,43 @@ layout = quakebsp_layout; //renderPass = renderpass; }; + bsp_turb = { + subpass = 1; + stages = ( + { + stage = vertex; + name = main; + module = $builtin/quakebsp.vert; + }, + { + stage = fragment; + name = main; + module = $builtin/bsp_turb.frag; + specializationInfo = { + mapEntries = ( + { size = 4; offset = 0; constantID = 0; }, + { size = 4; offset = 4; constantID = 1; }, + ); + data = <00000000ffffffff>; + }; + }, + ); + vertexInput = $properties.vertexInput.brush; + inputAssembly = $properties.inputAssembly.brush; + viewport = $properties.viewport; + rasterization = $properties.rasterization.cw_cull_back; + multisample = $properties.multisample; + depthStencil = $properties.depthStencil.test_only; + colorBlend = { + logicOpEnable = false; + attachments = ($properties.attachmentBlendOp.disabled); + }; + dynamic = { + dynamicState = ( viewport, scissor ); + }; + layout = quakebsp_layout; + //renderPass = renderpass; + }; twod = { subpass = 1; stages = ( diff --git a/libs/video/renderer/vulkan/shader.c b/libs/video/renderer/vulkan/shader.c index d2921faca..c10d9a286 100644 --- a/libs/video/renderer/vulkan/shader.c +++ b/libs/video/renderer/vulkan/shader.c @@ -72,6 +72,8 @@ static static #include "libs/video/renderer/vulkan/shader/bsp_sky.frag.spvc" static +#include "libs/video/renderer/vulkan/shader/bsp_turb.frag.spvc" +static #include "libs/video/renderer/vulkan/shader/lighting.frag.spvc" static #include "libs/video/renderer/vulkan/shader/compose.frag.spvc" @@ -104,6 +106,7 @@ static shaderdata_t builtin_shaders[] = { { "bsp_gbuf.geom", bsp_gbuf_geom, sizeof (bsp_gbuf_geom) }, { "bsp_gbuf.frag", bsp_gbuf_frag, sizeof (bsp_gbuf_frag) }, { "bsp_sky.frag", bsp_sky_frag, sizeof (bsp_sky_frag) }, + { "bsp_turb.frag", bsp_turb_frag, sizeof (bsp_turb_frag) }, { "lighting.frag", lighting_frag, sizeof (lighting_frag) }, { "compose.frag", compose_frag, sizeof (compose_frag) }, { "alias.vert", alias_vert, sizeof (alias_vert) }, diff --git a/libs/video/renderer/vulkan/shader/bsp_turb.frag b/libs/video/renderer/vulkan/shader/bsp_turb.frag new file mode 100644 index 000000000..ab4b04c7d --- /dev/null +++ b/libs/video/renderer/vulkan/shader/bsp_turb.frag @@ -0,0 +1,52 @@ +#version 450 + +layout (set = 0, binding = 1) uniform sampler2D Texture; + +layout (push_constant) uniform PushConstants { + layout (offset = 64) + vec4 fog; + float time; +}; + +layout (location = 0) in vec4 tl_st; +layout (location = 1) in vec3 direction; + +layout (location = 0) out vec4 frag_color; + +const float PI = 3.14159265; +const float SPEED = 20.0; +const float CYCLE = 128.0; +const float FACTOR = PI * 2.0 / CYCLE; +const vec2 BIAS = vec2 (1.0, 1.0); +const float SCALE = 8.0; + +vec2 +warp_st (vec2 st, float time) +{ + vec2 angle = st.ts * CYCLE / 2.0; + vec2 phase = vec2 (time, time) * SPEED; + return st + (sin ((angle + phase) * FACTOR) + BIAS) / SCALE; +} + +vec4 +fogBlend (vec4 color) +{ + float az = fog.a * gl_FragCoord.z / gl_FragCoord.w; + vec3 fog_color = fog.rgb; + float fog_factor = exp (-az * az); + + return vec4 (mix (fog_color.rgb, color.rgb, fog_factor), color.a); +} + +void +main (void) +{ + vec4 c = vec4 (0); + vec4 e; + vec2 t_st = tl_st.xy; + vec2 l_st = tl_st.zw; + + t_st = warp_st (t_st, time); + c = texture (Texture, t_st); + frag_color = c;//fogBlend (c); +} diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index cd5b1e022..a85625440 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -72,13 +72,15 @@ static const char *bsp_pass_names[] = { "depth", "g-buffer", - "translucent", + "sky", + "turb", }; static QFV_Subpass subpass_map[] = { QFV_passDepth, // QFV_bspDepth QFV_passGBuffer, // QFV_bspGBuffer - QFV_passTranslucent, // QFV_bspTranslucent + QFV_passTranslucent, // QFV_bspSky + QFV_passTranslucent, // QFV_bspTurb }; static float identity[] = { @@ -968,58 +970,40 @@ bsp_end (vulkan_ctx_t *ctx) bsp_end_subpass (bframe->cmdSet.a[QFV_bspGBuffer], ctx); } -/*static void -turb_begin (bspctx_t *bctx) +static void +turb_begin (vulkan_ctx_t *ctx) { - quat_t fog; + bspctx_t *bctx = ctx->bsp_context; bctx->default_color[3] = bound (0, r_wateralpha->value, 1); + QuatCopy (bctx->default_color, bctx->last_color); - qfeglVertexAttrib4fv (quake_bsp.color.location, default_color); - Mat4Mult (glsl_projection, glsl_view, bsp_vp); + __auto_type cframe = &ctx->frames.a[ctx->curFrame]; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; - qfeglUseProgram (quake_turb.program); - qfeglEnableVertexAttribArray (quake_turb.vertex.location); - qfeglEnableVertexAttribArray (quake_turb.tlst.location); - qfeglDisableVertexAttribArray (quake_turb.color.location); + DARRAY_APPEND (&cframe->cmdSets[QFV_passTranslucent], + bframe->cmdSet.a[QFV_bspTurb]); - qfeglVertexAttrib4fv (quake_turb.color.location, default_color); + //FIXME need per frame matrices + bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; + bframe->imageInfo[0].imageView = ctx->default_magenta->view; + bframe->imageInfo[1].imageView = ctx->default_magenta->view; + bframe->imageInfo[2].imageView = QFV_ScrapImageView (bctx->light_scrap); + bframe->imageInfo[3].imageView = bctx->default_skysheet->view; + bframe->imageInfo[4].imageView = bctx->default_skybox->view; - glsl_Fog_GetColor (fog); - fog[3] = glsl_Fog_GetDensity () / 64.0; - fragconst_t frag_constants = { time: vr_data.realtime }; - dfunc->vkCmdPushConstants (cmd, bctx->layout, VK_SHADER_STAGE_FRAGMENT_BIT, - 64, sizeof (fragconst_t), &frag_constants); - qfeglUniform4fv (quake_turb.fog.location, 1, fog); + bsp_begin_subpass (QFV_bspTurb, bctx->turb, ctx); +} - qfeglUniform1i (quake_turb.palette.location, 1); - qfeglActiveTexture (GL_TEXTURE0 + 1); - qfeglEnable (GL_TEXTURE_2D); - qfeglBindTexture (GL_TEXTURE_2D, glsl_palette); - - qfeglUniform1f (quake_turb.time.location, vr_data.realtime); - - qfeglUniform1i (quake_turb.texture.location, 0); - qfeglActiveTexture (GL_TEXTURE0 + 0); - qfeglEnable (GL_TEXTURE_2D); - - qfeglBindBuffer (GL_ARRAY_BUFFER, bsp_vbo); -}*/ - -/*static void -turb_end (bspctx_t *bctx) +static void +turb_end (vulkan_ctx_t *ctx) { - qfeglDisableVertexAttribArray (quake_turb.vertex.location); - qfeglDisableVertexAttribArray (quake_turb.tlst.location); + bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; - qfeglActiveTexture (GL_TEXTURE0 + 0); - qfeglDisable (GL_TEXTURE_2D); - qfeglActiveTexture (GL_TEXTURE0 + 1); - qfeglDisable (GL_TEXTURE_2D); - - qfeglBindBuffer (GL_ARRAY_BUFFER, 0); -}*/ + bsp_end_subpass (bframe->cmdSet.a[QFV_bspTurb], ctx); +} static void spin (mat4_t mat, bspctx_t *bctx) @@ -1057,9 +1041,8 @@ sky_begin (vulkan_ctx_t *ctx) __auto_type cframe = &ctx->frames.a[ctx->curFrame]; bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; - //FIXME where should skys go? g-buffer is overkill. Translucent pre-pass? DARRAY_APPEND (&cframe->cmdSets[QFV_passTranslucent], - bframe->cmdSet.a[QFV_bspTranslucent]); + bframe->cmdSet.a[QFV_bspSky]); //FIXME need per frame matrices bframe->bufferInfo[0].buffer = ctx->matrices.buffer_3d; @@ -1071,8 +1054,7 @@ sky_begin (vulkan_ctx_t *ctx) bframe->imageInfo[4].imageView = get_view (bctx->skybox_tex, bctx->default_skybox); - //FIXME sky pass - bsp_begin_subpass (QFV_bspTranslucent, bctx->sky, ctx); + bsp_begin_subpass (QFV_bspSky, bctx->sky, ctx); } static void @@ -1081,8 +1063,7 @@ sky_end (vulkan_ctx_t *ctx) bspctx_t *bctx = ctx->bsp_context; bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; - //FIXME sky pass - bsp_end_subpass (bframe->cmdSet.a[QFV_bspTranslucent], ctx); + bsp_end_subpass (bframe->cmdSet.a[QFV_bspSky], ctx); } static inline void @@ -1217,7 +1198,10 @@ Vulkan_DrawWorld (vulkan_ctx_t *ctx) void Vulkan_DrawWaterSurfaces (vulkan_ctx_t *ctx) { -/* bspctx_t *bctx = ctx->bsp_context; + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; instsurf_t *is; msurface_t *surf; vulktex_t *tex = 0; @@ -1227,38 +1211,49 @@ Vulkan_DrawWaterSurfaces (vulkan_ctx_t *ctx) if (!bctx->waterchain) return; - turb_begin (bctx); + turb_begin (ctx); + push_transform (identity, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspTurb]); + fragconst_t frag_constants = { time: vr_data.realtime }; + push_fragconst (&frag_constants, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspTurb]); for (is = bctx->waterchain; is; is = is->tex_chain) { surf = is->surface; - if (tex != surf->texinfo->texture) { + if (tex != surf->texinfo->texture->render) { if (tex) { - //XXX qfeglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum); - //for (ec = tex->elechain; ec; ec = ec->next) - // draw_elechain (ec, quake_turb.mvp_matrix.location, - // quake_turb.vertex.location, - // quake_turb.tlst.location, - // quake_turb.color.location); + bind_view (qfv_bsp_texture, + get_view (tex->tex, ctx->default_black), + bframe, + bframe->cmdSet.a[QFV_bspTurb], + bctx->layout, dfunc); + for (ec = tex->elechain; ec; ec = ec->next) { + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspTurb]); + reset_elechain (ec); + } tex->elechain = 0; tex->elechain_tail = &tex->elechain; } - tex = surf->texinfo->texture; + tex = surf->texinfo->texture->render; } - add_surf_elements (tex, is, &ec, &el, bctx); + add_surf_elements (tex, is, &ec, &el, bctx, bframe); } if (tex) { - //XXX qfeglBindTexture (GL_TEXTURE_2D, tex->gl_texturenum); - //for (ec = tex->elechain; ec; ec = ec->next) - // draw_elechain (ec, quake_turb.mvp_matrix.location, - // quake_turb.vertex.location, - // quake_turb.tlst.location, - // quake_turb.color.location); + bind_view (qfv_bsp_texture, get_view (tex->tex, ctx->default_black), + bframe, bframe->cmdSet.a[QFV_bspTurb], + bctx->layout, dfunc); + for (ec = tex->elechain; ec; ec = ec->next) { + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspTurb]); + reset_elechain (ec); + } tex->elechain = 0; tex->elechain_tail = &tex->elechain; } - turb_end (bctx); + turb_end (ctx); bctx->waterchain = 0; - bctx->waterchain_tail = &bctx->waterchain;*/ + bctx->waterchain_tail = &bctx->waterchain; } void @@ -1278,12 +1273,11 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) return; sky_begin (ctx); - //FIXME sky pass push_transform (identity, bctx->layout, dfunc, - bframe->cmdSet.a[QFV_bspTranslucent]); + bframe->cmdSet.a[QFV_bspSky]); fragconst_t frag_constants = { time: vr_data.realtime }; push_fragconst (&frag_constants, bctx->layout, dfunc, - bframe->cmdSet.a[QFV_bspTranslucent]); + bframe->cmdSet.a[QFV_bspSky]); for (is = bctx->sky_chain; is; is = is->tex_chain) { surf = is->surface; if (tex != surf->texinfo->texture->render) { @@ -1291,11 +1285,11 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) bind_view (qfv_bsp_skysheet, get_view (tex->tex, ctx->default_black), bframe, - bframe->cmdSet.a[QFV_bspTranslucent],//FIXME + bframe->cmdSet.a[QFV_bspSky], bctx->layout, dfunc); for (ec = tex->elechain; ec; ec = ec->next) { - draw_elechain (ec, bctx->layout, dfunc,//FIXME - bframe->cmdSet.a[QFV_bspTranslucent]); + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspSky]); reset_elechain (ec); } tex->elechain = 0; @@ -1307,11 +1301,11 @@ Vulkan_DrawSky (vulkan_ctx_t *ctx) } if (tex) { bind_view (qfv_bsp_skysheet, get_view (tex->tex, ctx->default_black), - bframe, bframe->cmdSet.a[QFV_bspTranslucent],//FIXME + bframe, bframe->cmdSet.a[QFV_bspSky], bctx->layout, dfunc); for (ec = tex->elechain; ec; ec = ec->next) { - draw_elechain (ec, bctx->layout, dfunc,//FIXME - bframe->cmdSet.a[QFV_bspTranslucent]); + draw_elechain (ec, bctx->layout, dfunc, + bframe->cmdSet.a[QFV_bspSky]); reset_elechain (ec); } tex->elechain = 0; @@ -1488,6 +1482,7 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bctx->depth = Vulkan_CreatePipeline (ctx, "bsp_depth"); bctx->gbuf = Vulkan_CreatePipeline (ctx, "bsp_gbuf"); bctx->sky = Vulkan_CreatePipeline (ctx, "bsp_skysheet"); + bctx->turb = Vulkan_CreatePipeline (ctx, "bsp_turb"); bctx->layout = Vulkan_CreatePipelineLayout (ctx, "quakebsp_layout"); bctx->sampler = Vulkan_CreateSampler (ctx, "quakebsp_sampler"); @@ -1539,6 +1534,7 @@ Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx) dfunc->vkDestroyPipeline (device->dev, bctx->depth, 0); dfunc->vkDestroyPipeline (device->dev, bctx->gbuf, 0); dfunc->vkDestroyPipeline (device->dev, bctx->sky, 0); + dfunc->vkDestroyPipeline (device->dev, bctx->turb, 0); DARRAY_CLEAR (&bctx->texture_chains); DARRAY_CLEAR (&bctx->frames); QFV_DestroyStagingBuffer (bctx->light_stage);