Merge branch 'master' into wip-twod

This commit is contained in:
Bill Currie 2022-09-22 10:06:00 +09:00
commit 20ee47404f
83 changed files with 1976 additions and 1009 deletions

View file

@ -28,7 +28,7 @@ BUILT_SOURCES = $(top_srcdir)/.version
#AM_CFLAGS= @PREFER_NON_PIC@
AM_CPPFLAGS= -I$(top_srcdir)/include $(PTHREAD_CFLAGS) $(FNM_FLAGS) $(NCURSES_CFLAGS) $(FREETYPE_CFLAGS) $(HARFBUZZ_CFLAGS)
common_ldflags= -export-dynamic @PTHREAD_LDFLAGS@
common_ldflags= -export-dynamic @STATIC@ @PTHREAD_LDFLAGS@
SUFFICES =
TESTS =
@ -166,11 +166,11 @@ CLEANFILES += $(shader_DATA)
$(r_depfiles_remade):
$(MKDIR_P) $(@D)
echo '$@' | sed -e 's@\$(DEPDIR)/@@' -e 's@\(.*\)\.Qo$$@\1.o: $(top_srcdir)/\1.r qfcc@' >$@-t && $(am__mv) $@-t $@
echo '$@' | sed -e 's@\$(DEPDIR)/@@' -e 's@\(.*\)\.Qo$$@\1.o: $(top_srcdir)/\1.r $(QFCC)@' >$@-t && $(am__mv) $@-t $@
$(pas_depfiles_remade):
$(MKDIR_P) $(@D)
echo '$@' | sed -e 's@\$(DEPDIR)/@@' -e 's@\(.*\)\.Qo$$@\1.o: $(top_srcdir)/\1.pas qfcc@' >$@-t && $(am__mv) $@-t $@
echo '$@' | sed -e 's@\$(DEPDIR)/@@' -e 's@\(.*\)\.Qo$$@\1.o: $(top_srcdir)/\1.pas $(QFCC)@' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) $(pas_depfiles_remade)
echo findme $(ruamoko_gui_libgui_a_dep)

View file

@ -246,7 +246,7 @@ if test "x$ENABLE_tools_qfbsp" = xyes; then
QF_NEED(libs,[models image util])
fi
if test "x$ENABLE_tools_qfcc" = xyes; then
QFCC_TARGETS="qfcc qfprogs\$(EXEEXT)"
QFCC_TARGETS="qfcc\$(EXEEXT) qfprogs\$(EXEEXT)"
QF_NEED(tools,[qfcc])
QF_NEED(libs,[gamecode util])
fi

View file

@ -59,10 +59,12 @@ AC_SUBST(SGI_CD_LIBS)
AC_EGREP_CPP([QF_maGiC_VALUE],
[
#ifdef _WIN32
#include <windows.h>
#include <mmsystem.h>
#if defined(MCI_SET_DOOR_OPEN)
QF_maGiC_VALUE
#endif
#endif
],
CDTYPE="$CDTYPE WIN32"

View file

@ -238,26 +238,28 @@ QF_maGiC_VALUE
fi
dnl Win32
if test "x$ac_cv_header_windows_h" = "xyes"; then
SOUND_TYPES="$SOUND_TYPES Win32"
QF_NEED(snd_output, [win])
QF_NEED(snd_render, [default])
WINSND_LIBS="-lwinmm"
if test "x$ac_cv_header_dsound_h" = "xyes"; then
AC_EGREP_CPP([QF_maGiC_VALUE],
[
#include <windows.h>
#include <dsound.h>
#ifdef GMEM_MOVEABLE
# ifdef DirectSoundEnumerate
QF_maGiC_VALUE
# endif
#endif
],
SOUND_TYPES="$SOUND_TYPES DirectX"
QF_NEED(snd_output, [dx])
if test "x$SYSTYPE" = xWIN32; then
if test "x$ac_cv_header_windows_h" = "xyes"; then
SOUND_TYPES="$SOUND_TYPES Win32"
QF_NEED(snd_output, [win])
QF_NEED(snd_render, [default])
)
WINSND_LIBS="-lwinmm"
if test "x$ac_cv_header_dsound_h" = "xyes"; then
AC_EGREP_CPP([QF_maGiC_VALUE],
[
#include <windows.h>
#include <dsound.h>
#ifdef GMEM_MOVEABLE
# ifdef DirectSoundEnumerate
QF_maGiC_VALUE
# endif
#endif
],
SOUND_TYPES="$SOUND_TYPES DirectX"
QF_NEED(snd_output, [dx])
QF_NEED(snd_render, [default])
)
fi
fi
fi
AC_SUBST(WINSND_LIBS)

View file

@ -8,7 +8,7 @@ case "$host_os" in
if test "x$host" != "x$build"; then
case "$build_os" in
cygwin*)
CFLAGS="$CFLAGS -mno-cygwin -mconsole -D__USE_MINGW_ANSI_STDIO"
CFLAGS="$CFLAGS -mconsole -D__USE_MINGW_ANSI_STDIO"
CPPFLAGS="$CPPFLAGS $CFLAGS"
;;
esac
@ -19,6 +19,7 @@ case "$host_os" in
;;
cygwin*)
cygwin=yes
AC_DEFINE(NEED_GNUPRINTF)
if test "x$host" != "x$build"; then
CC="$host_cpu-$host_os-gcc"
AS="$CC"

View file

@ -91,8 +91,8 @@ case "${host}" in
fi
;;
i?86-*-cygwin*)
SYSTYPE=WIN32
i?86-*-cygwin*|x86_64-*-cygwin*)
#SYSTYPE=WIN32
AC_MSG_RESULT([Win32 driver])
WIN32_LIBS=' $(NET_LIBS)'
;;

View file

@ -197,11 +197,11 @@ include_qf_vulkan = \
include/QF/Vulkan/qf_matrices.h \
include/QF/Vulkan/qf_model.h \
include/QF/Vulkan/qf_particles.h \
include/QF/Vulkan/qf_renderpass.h \
include/QF/Vulkan/qf_scene.h \
include/QF/Vulkan/qf_sprite.h \
include/QF/Vulkan/qf_texture.h \
include/QF/Vulkan/qf_vid.h \
include/QF/Vulkan/renderpass.h \
include/QF/Vulkan/scrap.h \
include/QF/Vulkan/shader.h \
include/QF/Vulkan/staging.h \

View file

@ -22,7 +22,7 @@ GLOBAL_LEVEL_VULKAN_FUNCTION (vkCreateInstance)
#endif
INSTANCE_LEVEL_VULKAN_FUNCTION (vkEnumeratePhysicalDevices)
INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceProperties)
INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceProperties2)
INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceFeatures)
INSTANCE_LEVEL_VULKAN_FUNCTION (vkGetPhysicalDeviceQueueFamilyProperties)
INSTANCE_LEVEL_VULKAN_FUNCTION (vkCreateDevice)

View file

@ -42,7 +42,9 @@ typedef struct DARRAY_TYPE(const char *) qfv_debugstack_t;
typedef struct qfv_physdev_s {
struct qfv_instance_s *instance;
VkPhysicalDevice dev;
VkPhysicalDeviceProperties properties;
VkPhysicalDeviceProperties2 properties2;
VkPhysicalDeviceProperties *properties;
VkPhysicalDeviceMultiviewProperties multiViewProperties;
VkPhysicalDeviceMemoryProperties memory_properties;
} qfv_physdev_t;

View file

@ -39,31 +39,33 @@
#include "QF/simd/types.h"
/** \defgroup vulkan_bsp Brush model rendering
\ingroup vulkan
*/
/** Represent a single face (polygon) of a brush model.
*
* There is one of these for each face in the bsp (brush) model, built at run
* time when the model is loaded (actually, after all models are loaded but
* before rendering begins).
*/
typedef struct bsp_face_s {
uint32_t first_index;
uint32_t index_count;
uint32_t tex_id;
uint32_t flags;
uint32_t first_index; ///< index of first index in poly_indices
uint32_t index_count; ///< includes primitive restart
uint32_t tex_id; ///< texture bound to this face (maybe animated)
uint32_t flags; ///< face drawing (alpha, side, sky, turb)
} bsp_face_t;
/** Represent a brush model, both main and sub-model.
*
* Used for rendering non-world models.
*/
typedef struct bsp_model_s {
uint32_t first_face;
uint32_t face_count;
} bsp_model_t;
typedef struct bsp_packet_s {
int first_index;
int index_count;
int transform_id;
int color_id;
} bsp_packet_t;
typedef struct bsp_packetset_s
DARRAY_TYPE (bsp_packet_t) bsp_packetset_t;
typedef struct bsp_indexset_s
DARRAY_TYPE (uint32_t) bsp_indexset_t;
#if 0
typedef struct texname_s {
char name[MIPTEXNAME];
} texname_t;
@ -73,22 +75,58 @@ typedef struct texmip_s {
uint32_t height;
uint32_t offsets[MIPLEVELS];
} texmip_t;
#endif
/** \defgroup vulkan_bsp_texanim Animated Textures
* \ingroup vulkan_bsp
*
* Brush models support texture animations. For general details, see
* \ref bsp_texture_animation. These structures allow for quick lookup
* of the correct texture to use in an animation cycle, or even whether there
* is an animation cycle.
*/
///@{
/** Represent a texture's animation group.
*
* Every texture is in an animation group, even when not animated. When the
* texture is not animated, `count` is 1, otherwise `count` is the number of
* frames in the group, thus every texture has at least one frame.
*
* Each texture in a particular groupp shares the same `base` frame, with
* `offset` giving the texture's relative frame number within the group.
* The current frame is given by `base + (anim_index + offset) % count` where
* `anim_index` is the global time-based texture animation frame.
*/
typedef struct texanim_s {
uint16_t base;
byte offset;
byte count;
uint16_t base; ///< first frame in group
byte offset; ///< relative frame in group
byte count; ///< number of frames in group
} texanim_t;
/** Holds texture animation data for brush models.
*
* Brush models support one or two texture animation groups, based on the
* entity's frame (0 or non-0). When the entity's frame is 0, group 0 is used,
* otherwise group 1 is used. If there is no alternate (group 1) animation
* data for the texture, then the texture's group 0 data is copied to group 1
* in order to avoid coplications in selecting which texture a face is to use.
*
* As all of a group's frames are together, `frame_map` is used to get the
* actual texture id for the frame.
*/
typedef struct texdata_s {
// texname_t *names;
// texmip_t **mips;
texanim_t *anim_main;
texanim_t *anim_alt;
uint16_t *anim_map;
texanim_t *anim_main; ///< group 0 animations
texanim_t *anim_alt; ///< group 1 animations
uint16_t *frame_map; ///< map from texture frame to texture id
// int num_tex;
} texdata_t;
///@}
/** \defgroup vulkan_bsp_draw Brush model drawing
* \ingroup vulkan_bsp
*/
///@{
typedef struct vulktex_s {
struct qfv_tex_s *tex;
VkDescriptorSet descriptor;
@ -98,65 +136,186 @@ typedef struct vulktex_s {
typedef struct regtexset_s
DARRAY_TYPE (vulktex_t *) regtexset_t;
/** Represent a single draw call.
*
* For each texture that has faces to be rendered, one or more draw calls is
* made. Normally, only one call per texture is made, but if different models
* use the same texture, then a separate draw call is made for each model.
* When multiple entities use the same model, instanced rendering is used to
* draw all the faces sharing a texture for all the entities using that model.
* Thus when there are multiple draw calls for a single texture, they are
* grouped together so there is only one bind per texture.
*
* The index buffer is populated every frame with the vertex indices of the
* faces to be rendered for the current frame, grouped by texture and instance
* id (model render id).
*
* The model render id is assigned after models are loaded but before rendering
* begins and remains constant until the next time models are loaded (level
* change).
*
* The entid buffer is also populated every frame with the render id of the
* entities to be drawn that frame, It is used to map gl_InstanceIndex to
* entity id so as to look up the entity's transform and color (and any other
* data in the future).
*
* \dot
* digraph vulkan_bsp_draw_call {
* layout=dot; rankdir=LR; compound=true; nodesep=1.0;
* vertices [shape=none,label=< <table border="1" cellborder="1">
* <tr><td>vertex</td></tr>
* <tr><td>vertex</td></tr>
* <tr><td>...</td></tr>
* <tr><td port="p">vertex</td></tr>
* <tr><td>vertex</td></tr>
* </table> >];
* indices [shape=none,label=< <table border="1" cellborder="1">
* <tr><td>index</td></tr>
* <tr><td>index</td></tr>
* <tr><td>...</td></tr>
* <tr><td port="p">index</td></tr>
* <tr><td>index</td></tr>
* </table> >];
* entids [shape=none,label=< <table border="1" cellborder="1">
* <tr><td>entid</td></tr>
* <tr><td>...</td></tr>
* <tr><td port="p">entid</td></tr>
* <tr><td>entid</td></tr>
* <tr><td>...</td></tr>
* <tr><td>entid</td></tr>
* </table> >];
* entdata [shape=none,label=< <table border="1" cellborder="1">
* <tr><td>transform</td><td>color</td></tr>
* <tr><td>transform</td><td>color</td></tr>
* <tr><td colspan="2">...</td></tr>
* <tr><td port="p">transform</td><td>color</td></tr>
* <tr><td colspan="2">...</td></tr>
* <tr><td>transform</td><td>color</td></tr>
* </table> >];
* drawcall [shape=none,label=< <table border="1" cellborder="1">
* <tr><td port="tex" >tex_id</td></tr>
* <tr><td >inst_id</td></tr>
* <tr><td port="ind" >first_index</td></tr>
* <tr><td >index_count</td></tr>
* <tr><td port="inst">first_instance</td></tr>
* <tr><td >instance_count</td></tr>
* </table> >];
* textures [shape=none,label=< <table border="1" cellborder="1">
* <tr><td>texture</td></tr>
* <tr><td>texture</td></tr>
* <tr><td port="p">texture</td></tr>
* <tr><td>...</td></tr>
* <tr><td>texture</td></tr>
* </table> >];
* vertex [label="vertex shader"];
* fragment [label="fragment shader"];
* drawcall:tex -> textures:p;
* drawcall:ind -> indices:p;
* drawcall:inst -> entids:p;
* entids:p -> entdata:p;
* indices:p -> vertices:p;
* vertex -> entdata [label="storage buffer"];
* vertex -> entids [label="per instance"];
* vertex -> indices [label="index buffer"];
* vertex -> vertices [label="per vertex"];
* fragment -> textures [label="per call"];
* }
* \enddot
*/
///@{
typedef struct bsp_draw_s {
uint32_t tex_id;
uint32_t inst_id;
uint32_t index_count;
uint32_t instance_count;
uint32_t first_index;
uint32_t first_instance;
uint32_t tex_id; ///< texture to bind for this draw call
uint32_t inst_id; ///< model render id owning this draw call
uint32_t index_count; ///< number of indices for this draw call
uint32_t instance_count; ///< number of instances to draw
uint32_t first_index; ///< index into index buffer
uint32_t first_instance; ///< index into entid buffer
} bsp_draw_t;
typedef struct bsp_drawset_s
DARRAY_TYPE (bsp_draw_t) bsp_drawset_t;
///@}
/** Tag models that are to be queued for translucent drawing.
*/
#define INST_ALPHA (1u<<31)
/** Representation of a single face queued for drawing.
*/
///@{
typedef struct instface_s {
uint32_t inst_id;
uint32_t face;
uint32_t inst_id; ///< model render id owning this face
uint32_t face; ///< index of face in context array
} instface_t;
typedef struct bsp_instfaceset_s
DARRAY_TYPE (instface_t) bsp_instfaceset_t;
///@}
/** Track entities using a model.
*/
///@{
typedef struct bsp_modelentset_s
DARRAY_TYPE (uint32_t) bsp_modelentset_t;
/** Represent a single model and the entities using it.
*/
typedef struct bsp_instance_s {
int first_instance;
bsp_modelentset_t entities;
int first_instance; ///< index into entid buffer
bsp_modelentset_t entities; ///< list of entity render ids using this model
} bsp_instance_t;
///@}
typedef struct bsp_pass_s {
uint32_t *indices; // points into index buffer
uint32_t index_count; // number of indices written to buffer
uint32_t *entid_data;
uint32_t entid_count;
int vis_frame;
int *face_frames;
int *leaf_frames;
int *node_frames;
bsp_instfaceset_t *face_queue;
regtexset_t *textures;
int num_queues;
bsp_drawset_t *draw_queues;
uint32_t inst_id;
bsp_instance_t *instances;
int ent_frame;
vec4f_t position; ///< view position
plane_t *frustum; ///< view frustum for culling
const struct mod_brush_s *brush;///< data for current model
struct bspctx_s *bsp_context; ///< owning bsp context
/** \name GPU data
*
* The indices to be drawn and the entity ids associated with each draw
* instance are updated each frame. The pointers are to the per-frame
* mapped buffers for the respective data.
*/
///@{
uint32_t *indices; ///< polygon vertex indices
uint32_t index_count; ///< number of indices written to buffer
uint32_t *entid_data; ///< instance id to entity id map
uint32_t entid_count; ///< numer of entids written to buffer
///@}
/** \name Potentially Visible Sets
*
* For an object to be in the PVS, its frame id must match the current
* visibility frame id, thus clearing all sets is done by incrementing
* `vis_frame`, and adding an object to the PVS is done by setting its
* current frame id to the current visibility frame id.
*/
///@{
int vis_frame; ///< current visibility frame id
int *face_frames; ///< per-face visibility frame ids
int *leaf_frames; ///< per-leaf visibility frame ids
int *node_frames; ///< per-node visibility frame ids
///@}
bsp_instfaceset_t *face_queue; ///< per-texture face queues
regtexset_t *textures; ///< textures to bind when emitting calls
int num_queues; ///< number of pipeline queues
bsp_drawset_t *draw_queues; ///< per-pipeline draw queues
uint32_t inst_id; ///< render id of current model
bsp_instance_t *instances; ///< per-model entid lists
// FIXME There are several potential optimizations here:
// 1) ent_frame could be forced to be 0 or 1 and then used to index a
// two-element array of texanim pointers
// 2) ent_frame could be a pointer to the correct texanim array
// 3) could update a tex_id map each frame and unconditionally index that
//
// As the texture id is used for selecting the face queue, 3 could be used
// for mapping all textures to 1 or two queues for shadow rendering
int ent_frame; ///< animation frame of current entity
} bsp_pass_t;
///@}
typedef struct bspvert_s {
quat_t vertex;
quat_t tlst;
} bspvert_t;
typedef enum {
qfv_bsp_texture,
qfv_bsp_glowmap,
qfv_bsp_lightmap,
qfv_bsp_skysheet,
qfv_bsp_skycube,
} qfv_bsp_tex;
/// \ingroup vulkan_bsp
///@{
typedef enum {
QFV_bspDepth,
QFV_bspGBuffer,
@ -179,34 +338,33 @@ typedef struct bspframe_s {
typedef struct bspframeset_s
DARRAY_TYPE (bspframe_t) bspframeset_t;
/** Main BSP context structure
*
* This holds all the state and resources needed for rendering brush models.
*/
typedef struct bspctx_s {
regtexset_t registered_textures;
struct qfv_tex_s *default_skysheet;
struct qfv_tex_s *skysheet_tex;
struct qfv_tex_s *default_skybox;
struct qfv_tex_s *skybox_tex;
VkDescriptorSet skybox_descriptor;
vulktex_t notexture;
quat_t default_color;
quat_t last_color;
vulktex_t notexture; ///< replacement for invalid textures
struct scrap_s *light_scrap;
struct qfv_stagebuf_s *light_stage;
bsp_model_t *models;
bsp_face_t *faces;
uint32_t *poly_indices;
int num_models; ///< number of loaded brush models
bsp_model_t *models; ///< all loaded brush models
bsp_face_t *faces; ///< all faces from all loaded brush models
uint32_t *poly_indices; ///< face indices from all loaded brush models
texdata_t texdata;
int anim_index;
regtexset_t registered_textures;///< textures for all loaded brush models
texdata_t texdata; ///< texture animation data
int anim_index; ///< texture animation frame (5fps)
struct qfv_tex_s *default_skysheet;
struct qfv_tex_s *skysheet_tex; ///< scrolling sky texture for current map
int model_id;
struct qfv_tex_s *default_skybox;
struct qfv_tex_s *skybox_tex; ///< sky box texture for current map
VkDescriptorSet skybox_descriptor;
bsp_pass_t main_pass; // camera view depth, gbuffer, etc
bsp_pass_t main_pass; ///< camera view depth, gbuffer, etc
VkSampler sampler;
VkPipelineLayout layout;
@ -230,7 +388,6 @@ typedef struct bspctx_s {
struct vulkan_ctx_s;
struct qfv_renderframe_s;
void Vulkan_ClearElements (struct vulkan_ctx_s *ctx);
void Vulkan_DrawWorld (struct qfv_renderframe_s *rFrame);
void Vulkan_DrawSky (struct qfv_renderframe_s *rFrame);
void Vulkan_DrawWaterSurfaces (struct qfv_renderframe_s *rFrame);
@ -242,5 +399,6 @@ 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);
///@}
#endif//__QF_Vulkan_qf_bsp_h

View file

@ -35,6 +35,7 @@
#include "QF/modelgen.h"
#include "QF/scene/light.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/command.h"
#include "QF/Vulkan/image.h"
#include "QF/simd/types.h"
@ -79,6 +80,20 @@ typedef struct lightingframe_s {
typedef struct lightingframeset_s
DARRAY_TYPE (lightingframe_t) lightingframeset_t;
typedef struct light_renderer_s {
VkRenderPass renderPass; // shared
VkFramebuffer framebuffer;
VkImage image; // shared
VkImageView view;
uint32_t size;
uint32_t layer;
uint32_t numLayers;
int mode;
} light_renderer_t;
typedef struct light_renderer_set_s
DARRAY_TYPE (light_renderer_t) light_renderer_set_t;
typedef struct lightingctx_s {
lightingframeset_t frames;
VkPipeline pipeline;
@ -86,10 +101,16 @@ typedef struct lightingctx_s {
VkSampler sampler;
VkDeviceMemory light_memory;
VkDeviceMemory shadow_memory;
qfv_lightmatset_t lightmats;
qfv_imageset_t lightimages;
lightintset_t lightlayers;
qfv_imageviewset_t lightviews;
qfv_lightmatset_t light_mats;
qfv_imageset_t light_images;
light_renderer_set_t light_renderers;
qfv_renderpass_t *qfv_renderpass;
VkRenderPass renderpass_6;
VkRenderPass renderpass_4;
VkRenderPass renderpass_1;
VkCommandPool cmdpool;
struct lightingdata_s *ldata;
struct scene_s *scene;
@ -98,6 +119,7 @@ typedef struct lightingctx_s {
struct vulkan_ctx_s;
struct qfv_renderframe_s;
void Vulkan_Lighting_CreateRenderPasses (struct vulkan_ctx_s *ctx);
void Vulkan_Lighting_Init (struct vulkan_ctx_s *ctx);
void Vulkan_Lighting_Shutdown (struct vulkan_ctx_s *ctx);
void Vulkan_Lighting_Draw (struct qfv_renderframe_s *rFrame);

View file

@ -33,6 +33,7 @@ struct qfv_renderframe_s;
struct entqueue_s;
struct scene_s;
void Vulkan_Main_CreateRenderPasses (struct vulkan_ctx_s *ctx);
void Vulkan_NewScene (struct scene_s *scene, struct vulkan_ctx_s *ctx);
void Vulkan_RenderView (struct qfv_renderframe_s *rFrame);
void Vulkan_RenderEntities (struct entqueue_s *queue,

View file

@ -0,0 +1,68 @@
#ifndef __QF_Vulkan_renderpass_h
#define __QF_Vulkan_renderpass_h
#include "QF/darray.h"
#include "QF/simd/types.h"
typedef struct qfv_framebufferset_s
DARRAY_TYPE (VkFramebuffer) qfv_framebufferset_t;
#define QFV_AllocFrameBuffers(num, allocator) \
DARRAY_ALLOCFIXED (qfv_framebufferset_t, num, allocator)
typedef struct qfv_subpass_s {
vec4f_t color;
const char *name;
} qfv_subpass_t;
typedef struct qfv_subpassset_s
DARRAY_TYPE (qfv_subpass_t) qfv_subpassset_t;
typedef struct qfv_renderframe_s {
struct vulkan_ctx_s *vulkan_ctx;
struct qfv_renderpass_s *renderpass;
VkSubpassContents subpassContents;
int subpassCount;
qfv_subpass_t *subpassInfo;
struct qfv_cmdbufferset_s *subpassCmdSets;
} qfv_renderframe_t;
typedef struct qfv_renderframeset_s
DARRAY_TYPE (qfv_renderframe_t) qfv_renderframeset_t;
typedef struct clearvalueset_s
DARRAY_TYPE (VkClearValue) clearvalueset_t;
typedef void (*qfv_draw_t) (qfv_renderframe_t *rFrame);
typedef struct qfv_renderpass_s {
vec4f_t color; // for debugging
const char *name; // for debugging
struct plitem_s *renderpassDef;
VkRenderPass renderpass;
clearvalueset_t *clearValues;
struct qfv_imageset_s *attachment_images;
struct qfv_imageviewset_s *attachment_views;
VkDeviceMemory attachmentMemory;
qfv_framebufferset_t *framebuffers;
VkViewport viewport;
VkRect2D scissor;
int order;
int primary_commands;
size_t subpassCount;
qfv_subpassset_t *subpass_info;
qfv_renderframeset_t frames;
qfv_draw_t draw;
} qfv_renderpass_t;
struct qfv_output_s;
qfv_renderpass_t *Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx,
const char *name,
struct qfv_output_s *output,
qfv_draw_t draw);
void Vulkan_DestroyRenderPass (struct vulkan_ctx_s *ctx,
qfv_renderpass_t *renderpass);
#endif//__QF_Vulkan_renderpass_h

View file

@ -35,6 +35,14 @@
#endif
#include <vulkan/vulkan.h>
/** \defgroup vulkan Vulkan Renderer
*/
enum {
QFV_rp_shadowmap,
QFV_rp_main,
};
//FIXME location
typedef enum {
QFV_passDepth, // geometry
@ -61,7 +69,7 @@ struct vulkan_ctx_s;
void Vulkan_DestroyFrames (struct vulkan_ctx_s *ctx);
void Vulkan_CreateFrames (struct vulkan_ctx_s *ctx);
void Vulkan_CreateCapture (struct vulkan_ctx_s *ctx);
void Vulkan_CreateRenderPass (struct vulkan_ctx_s *ctx);
void Vulkan_CreateRenderPasses (struct vulkan_ctx_s *ctx);
void Vulkan_DestroyRenderPasses (struct vulkan_ctx_s *ctx);
void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx);
void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx);
@ -85,4 +93,6 @@ struct entity_s;
void Vulkan_BeginEntityLabel (struct vulkan_ctx_s *ctx, VkCommandBuffer cmd,
struct entity_s *ent);
struct plitem_s *Vulkan_GetConfig (struct vulkan_ctx_s *ctx, const char *name);
#endif // __QF_Vulkan_vid_h

View file

@ -1,90 +0,0 @@
#ifndef __QF_Vulkan_renderpass_h
#define __QF_Vulkan_renderpass_h
#include "QF/darray.h"
#include "QF/simd/types.h"
typedef struct qfv_attachmentdescription_s
DARRAY_TYPE (VkAttachmentDescription) qfv_attachmentdescription_t;
#define QFV_AllocAttachmentDescription(num, allocator) \
DARRAY_ALLOCFIXED (qfv_attachmentdescription_t, num, allocator)
typedef struct qfv_attachmentreference_s
DARRAY_TYPE (VkAttachmentReference) qfv_attachmentreference_t;
#define QFV_AllocAttachmentReference(num, allocator) \
DARRAY_ALLOCFIXED (qfv_attachmentreference_t, num, allocator)
typedef struct qfv_subpassparametersset_s
DARRAY_TYPE (VkSubpassDescription) qfv_subpassparametersset_t;
#define QFV_AllocSubpassParametersSet(num, allocator) \
DARRAY_ALLOCFIXED (qfv_subpassparametersset_t, num, allocator)
typedef struct qfv_subpassdependency_s
DARRAY_TYPE (VkSubpassDependency) qfv_subpassdependency_t;
#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
QFV_CreateRenderPass (struct qfv_device_s *device,
qfv_attachmentdescription_t *attachments,
qfv_subpassparametersset_t *subpasses,
qfv_subpassdependency_t *dependencies);
VkFramebuffer
QFV_CreateFramebuffer (struct qfv_device_s *device,
VkRenderPass renderPass,
struct qfv_imageviewset_s *attachments,
VkExtent2D, uint32_t layers);
typedef struct qfv_subpass_s {
vec4f_t color;
const char *name;
} qfv_subpass_t;
typedef struct qfv_renderframe_s {
struct vulkan_ctx_s *vulkan_ctx;
struct qfv_renderpass_s *renderpass;
VkSubpassContents subpassContents;
int subpassCount;
qfv_subpass_t *subpassInfo;
struct qfv_cmdbufferset_s *subpassCmdSets;
} qfv_renderframe_t;
typedef struct qfv_renderframeset_s
DARRAY_TYPE (qfv_renderframe_t) qfv_renderframeset_t;
typedef struct clearvalueset_s
DARRAY_TYPE (VkClearValue) clearvalueset_t;
typedef struct qfv_renderpass_s {
vec4f_t color; // for debugging
const char *name; // for debugging
struct plitem_s *renderpassDef;
VkRenderPass renderpass;
clearvalueset_t *clearValues;
struct qfv_imageset_s *attachment_images;
struct qfv_imageviewset_s *attachment_views;
VkDeviceMemory attachmentMemory;
qfv_framebufferset_t *framebuffers;
VkViewport viewport;
VkRect2D scissor;
qfv_renderframeset_t frames;
void (*draw) (qfv_renderframe_t *rFrame);
} qfv_renderpass_t;
#endif//__QF_Vulkan_renderpass_h

View file

@ -103,13 +103,13 @@ typedef struct texture_s {
} texture_t;
#define SURF_PLANEBACK 0x02
#define SURF_DRAWSKY 0x04
#define SURF_DRAWTURB 0x08
#define SURF_DRAWSKY 0x01
#define SURF_DRAWALPHA 0x02
#define SURF_DRAWTURB 0x04
#define SURF_PLANEBACK 0x08
#define SURF_DRAWTILED 0x10
#define SURF_DRAWBACKGROUND 0x20
#define SURF_DRAWNOALPHA 0x40
#define SURF_LIGHTBOTHSIDES 0x80
#define SURF_LIGHTBOTHSIDES 0x40
// !!! if this is changed, it must be changed in asm_draw.h too !!!
typedef struct {

View file

@ -120,7 +120,6 @@ typedef struct vid_render_funcs_s {
void (*begin_frame) (void);
void (*render_view) (void);
void (*draw_entities) (struct entqueue_s *queue);
void (*draw_particles) (struct psystem_s *psystem);
void (*draw_transparent) (void);
void (*post_process) (struct framebuffer_s *src);

View file

@ -84,6 +84,7 @@ extern gamedir_t *qfs_gamedir;
/** Function type of callback called on gamedir change.
\param phase 0 = before Cache_Flush(), 1 = after Cache_Flush()
\param data data pointer passed on to the callback
*/
typedef void gamedir_callback_t (int phase, void *data);

View file

@ -37,6 +37,8 @@
* \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.
*
* \note On its own, this is not thread-safe. Suitable locking is required.
*/
#define RING_BUFFER(type, size) \
struct { \
@ -45,6 +47,26 @@
unsigned tail; \
}
/** Type declaration for a type-safe ring buffer with atomic head and tail.
*
* \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.
*
* \note This is suitable only for single-reader/single-writer unless
* additional locking is provided for multi-user side. This means `head` must
* have an associated lock for multiple writers, and `tail` must have an
* associated lock for multiple readers. For multi-reader + multi-writer, it
* may be better to use RING_BUFFER with suitable locking.
*/
#define RING_BUFFER_ATOMIC(type, size) \
struct { \
type buffer[size]; \
_Atomic unsigned head; \
_Atomic unsigned tail; \
}
#define RB_buffer_size(ring_buffer) \
({ __auto_type rb_s = (ring_buffer); \
sizeof (rb_s->buffer) / sizeof (rb_s->buffer[0]); \
@ -95,7 +117,7 @@
const typeof (rb->buffer[0]) *d = (data); \
unsigned c = (count); \
unsigned h = rb->head; \
rb->head = (h + c) % RB_buffer_size (rb); \
unsigned new_head = (h + c) % RB_buffer_size (rb); \
if (c > RB_buffer_size (rb) - h) { \
memcpy (rb->buffer + h, d, \
(RB_buffer_size (rb) - h) * sizeof (rb->buffer[0])); \
@ -104,6 +126,7 @@
h = 0; \
} \
memcpy (rb->buffer + h, d, c * sizeof (rb->buffer[0])); \
rb->head = new_head; \
})
/** Acquire \a count objects from the buffer, wrapping if necessary.
@ -122,8 +145,10 @@
({ __auto_type rb = &(ring_buffer); \
unsigned c = (count); \
unsigned h = rb->head; \
rb->head = (h + c) % RB_buffer_size (rb); \
&rb->buffer[h]; \
unsigned new_head = (h + c) % RB_buffer_size (rb); \
__auto_type head_addr = &rb->buffer[h]; \
rb->head = new_head; \
head_addr; \
})
/** Read \a count objects from the buffer to \a data, wrapping if necessary.
@ -145,6 +170,7 @@
unsigned c = (count); \
unsigned oc = c; \
unsigned t = rb->tail; \
unsigned new_tail = (t + oc) % RB_buffer_size (rb); \
if (c > RB_buffer_size (rb) - t) { \
memcpy (d, rb->buffer + t, \
(RB_buffer_size (rb) - t) * sizeof (rb->buffer[0])); \
@ -153,7 +179,7 @@
t = 0; \
} \
memcpy (d, rb->buffer + t, c * sizeof (rb->buffer[0])); \
rb->tail = (t + oc) % RB_buffer_size (rb); \
rb->tail = new_tail; \
})
/** Discard \a count objects from the ring buffer.

View file

@ -279,7 +279,7 @@ int SND_Memory_GetRetainCount (void *ptr) __attribute__((pure));
\param sfx
\param realname
\param info
\param loader
\param load
*/
void SND_SFX_Block (sfx_t *sfx, char *realname, wavinfo_t info,
sfxbuffer_t *(*load) (sfxblock_t *block));
@ -306,7 +306,7 @@ sfxbuffer_t *SND_SFX_StreamOpen (sfx_t *sfx, void *file,
void (*close) (sfxbuffer_t *));
/** Close a stream.
\param sfx
\param stream
*/
void SND_SFX_StreamClose (sfxstream_t *stream);

View file

@ -14,6 +14,7 @@ typedef struct qfv_output_s {
VkExtent2D extent;
VkImageView view;
VkFormat format;
VkImageView *view_list; // per frame
} qfv_output_t;
typedef struct vulkan_frame_s {
@ -76,8 +77,6 @@ typedef struct vulkan_ctx_s {
struct composectx_s *compose_context;
VkCommandPool cmdpool;
VkCommandBuffer cmdbuffer;
VkFence fence; // for ctx->cmdbuffer only
struct qfv_stagebuf_s *staging;
size_t curFrame;
vulkan_frameset_t frames;
@ -98,7 +97,7 @@ typedef struct vulkan_ctx_s {
int window_width;
int window_height;
//FIXME not sure I like it being here (also, type name)
//FIXME this is for the parser
qfv_output_t output;
#define EXPORTED_VULKAN_FUNCTION(fname) PFN_##fname fname;

View file

@ -287,6 +287,42 @@ static cvar_t cl_yawspeed_cvar = {
.flags = CVAR_NONE,
.value = { .type = &cexpr_float, .value = &cl_yawspeed },
};
float cl_maxpitch;
static cvar_t cl_maxpitch_cvar = {
.name = "cl_maxpitch",
.description =
"turning speed",
.default_value = "90",
.flags = CVAR_ARCHIVE,
.value = { .type = &cexpr_float, .value = &cl_maxpitch },
};
float cl_minpitch;
static cvar_t cl_minpitch_cvar = {
.name = "cl_minpitch",
.description =
"turning speed",
.default_value = "-90",
.flags = CVAR_ARCHIVE,
.value = { .type = &cexpr_float, .value = &cl_minpitch },
};
float cl_maxroll;
static cvar_t cl_maxroll_cvar = {
.name = "cl_maxroll",
.description =
"turning speed",
.default_value = "50",
.flags = CVAR_ARCHIVE,
.value = { .type = &cexpr_float, .value = &cl_maxroll },
};
float cl_minroll;
static cvar_t cl_minroll_cvar = {
.name = "cl_minroll",
.description =
"turning speed",
.default_value = "-50",
.flags = CVAR_ARCHIVE,
.value = { .type = &cexpr_float, .value = &cl_minroll },
};
int lookspring;
static cvar_t lookspring_cvar = {
@ -376,10 +412,10 @@ CL_AdjustAngles (float frametime, movestate_t *ms, viewstate_t *vs)
if (delta[PITCH]) {
V_StopPitchDrift (vs);
ms->angles[PITCH] = bound (-70, ms->angles[PITCH], 80);
ms->angles[PITCH] = bound (cl_minpitch, ms->angles[PITCH], cl_maxpitch);
}
if (delta[ROLL]) {
ms->angles[ROLL] = bound (-50, ms->angles[ROLL], 50);
ms->angles[ROLL] = bound (cl_minroll, ms->angles[ROLL], cl_maxroll);
}
if (delta[YAW]) {
ms->angles[YAW] = anglemod (ms->angles[YAW]);
@ -600,6 +636,10 @@ CL_Input_Init_Cvars (void)
Cvar_Register (&cl_sidespeed_cvar, 0, 0);
Cvar_Register (&cl_upspeed_cvar, 0, 0);
Cvar_Register (&cl_yawspeed_cvar, 0, 0);
Cvar_Register (&cl_maxpitch_cvar, 0, 0);
Cvar_Register (&cl_minpitch_cvar, 0, 0);
Cvar_Register (&cl_maxroll_cvar, 0, 0);
Cvar_Register (&cl_minroll_cvar, 0, 0);
}
void

View file

@ -204,7 +204,9 @@ parse_light (light_t *light, int *style, const plitem_t *entity,
} color = { .v = light->color };
sscanf (str, "%f %f %f", VectorExpandAddr (color.a));
light->color = color.v;
VectorScale (light->color, 1/255.0, light->color);
if (light->color[0] > 1 || light->color[1] > 1 || light->color[2] > 1) {
VectorScale (light->color, 1/255.0, light->color);
}
}
if ((str = PL_String (PL_ObjectForKey (entity, "wait")))) {

View file

@ -1629,7 +1629,7 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents)
goto err;
}
if (mode == 'M' || mode == 'm') {
if (!isxdigit (fmt[3])) {
if (!isxdigit ((byte) fmt[3])) {
goto err;
}
shift = fmt[3];

View file

@ -240,7 +240,7 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s)
*v = ' ';
}
}
if (sscanf (s, "%f %f %f", VectorExpandAddr (vec)) != 3) {
if (sscanf (str, "%f %f %f", VectorExpandAddr (vec)) != 3) {
Sys_Printf ("Malformed vector %s\n", s);
}
VectorCopy (vec, PR_PTR (vector, d));

View file

@ -206,7 +206,7 @@ LoadPNG (QFile *infile, int load)
#define WRITEPNG_BIT_DEPTH 8
int
VISIBLE int
WritePNG (QFile *outfile, const tex_t *tex)
{
int i;
@ -299,9 +299,10 @@ LoadPNG (QFile *infile, int load)
return 0;
}
VISIBLE void
WritePNG (QFile *outfile, const byte *data, int width, int height)
VISIBLE int
WritePNG (QFile *outfile, const tex_t *tex)
{
return 0;
}
#endif

View file

@ -218,6 +218,11 @@ check_device (const char *path)
dev->event_count = 0;
dev->data = 0;
dev->axis_event = 0;
dev->button_event = 0;
//Sys_Printf ("%s:\n", path);
//Sys_Printf ("\tname: %s\n", dev->name);
//Sys_Printf ("\tbuttons: %d\n", dev->num_buttons);

View file

@ -652,19 +652,23 @@ Mod_LoadFaces (model_t *mod, bsp_t *bsp)
continue;
}
if (out->texinfo->texture->name[0] == '*') { // turbulent
out->flags |= (SURF_DRAWTURB
| SURF_DRAWTILED
| SURF_LIGHTBOTHSIDES);
for (i = 0; i < 2; i++) {
out->extents[i] = 16384;
out->texturemins[i] = -8192;
}
if (mod_funcs && mod_funcs->Mod_SubdivideSurface) {
// cut up polygon for warps
mod_funcs->Mod_SubdivideSurface (mod, out);
}
continue;
switch (out->texinfo->texture->name[0]) {
case '*': // turbulent
out->flags |= (SURF_DRAWTURB
| SURF_DRAWTILED
| SURF_LIGHTBOTHSIDES);
for (i = 0; i < 2; i++) {
out->extents[i] = 16384;
out->texturemins[i] = -8192;
}
if (mod_funcs && mod_funcs->Mod_SubdivideSurface) {
// cut up polygon for warps
mod_funcs->Mod_SubdivideSurface (mod, out);
}
break;
case '{':
out->flags |= SURF_DRAWALPHA;
break;
}
}
}

View file

@ -58,12 +58,6 @@
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#ifdef HAVE_WINDOWS_H
# include <windows.h>
#endif
#ifdef HAVE_WINSOCK_H
# include <winsock.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
@ -537,7 +531,7 @@ UDP_Read (int socket, byte *buf, int len, netadr_t *from)
}
SockadrToNetadr (&addr, from);
Sys_MaskPrintf (SYS_net, "got %d bytes from %s on iface %d (%s)\n", ret,
UDP_AddrToString (from), info ? info->ipi_ifindex - 1 : -1,
UDP_AddrToString (from), info ? (int) info->ipi_ifindex - 1 : -1,
last_iface ? inet_ntoa (info->ipi_addr) : "?");
#else
socklen_t addrlen = sizeof (AF_address_t);

View file

@ -940,7 +940,11 @@ Sys_ConsoleInput (void)
#endif
}
#ifdef _WIN32
static jmp_buf aiee_abort;
#else
static sigjmp_buf aiee_abort;
#endif
typedef struct sh_stack_s {
struct sh_stack_s *next;

View file

@ -18,6 +18,7 @@ libs_util_tests = \
libs/util/test/test-pqueue \
libs/util/test/test-qfs \
libs/util/test/test-quat \
libs/util/test/test-ringbuffer \
libs/util/test/test-seb \
libs/util/test/test-sebvf \
libs/util/test/test-seg \
@ -106,6 +107,11 @@ libs_util_test_test_quat_SOURCES=libs/util/test/test-quat.c
libs_util_test_test_quat_LDADD=libs/util/libQFutil.la
libs_util_test_test_quat_DEPENDENCIES=libs/util/libQFutil.la
libs_util_test_test_ringbuffer_SOURCES=libs/util/test/test-ringbuffer.c
libs_util_test_test_ringbuffer_LDADD=libs/util/libQFutil.la
libs_util_test_test_ringbuffer_LDFLAGS=-pthread
libs_util_test_test_ringbuffer_DEPENDENCIES=libs/util/libQFutil.la
libs_util_test_test_seb_SOURCES=libs/util/test/test-seb.c
libs_util_test_test_seb_LDADD=libs/util/libQFutil.la
libs_util_test_test_seb_DEPENDENCIES=libs/util/libQFutil.la

View file

@ -1,6 +1,7 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
// because libc has its own remove
#define remove remove_renamed
#include <stdio.h>
#include <string.h>

View file

@ -0,0 +1,313 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <threads.h>
#include "QF/dstring.h"
#include "QF/mathlib.h"
#include "QF/ringbuffer.h"
#include "QF/sys.h"
typedef int (*test_func) (int a, int b);
typedef RING_BUFFER (int, 8) ringbuffer_t;
typedef RING_BUFFER (char, 8) ringbuffer_char_t;
typedef RING_BUFFER_ATOMIC (char, 8) ringbuffer_atomic_t;
static ringbuffer_t int_ringbuffer = { .buffer = { [0 ... 7] = 0xdeadbeef } };
static ringbuffer_char_t ringbuffer_char;
static ringbuffer_atomic_t ringbuffer_atomic;
mtx_t rb_mtx;
cnd_t rb_write_cnd;
cnd_t rb_read_cnd;
ringbuffer_atomic_t int_ringbuffer_atomic;
static int
get_size (int a, int b)
{
return RB_buffer_size (&int_ringbuffer);
}
static int
space_available (int a, int b)
{
return RB_SPACE_AVAILABLE (int_ringbuffer);
}
static int
data_available (int a, int b)
{
return RB_DATA_AVAILABLE (int_ringbuffer);
}
static int
write_data (int value, int b)
{
return RB_WRITE_DATA (int_ringbuffer, &value, 1);
}
static int
acquire (int count, int b)
{
return *RB_ACQUIRE (int_ringbuffer, count);
}
static int
read_data (int a, int b)
{
int ret;
RB_READ_DATA (int_ringbuffer, &ret, 1);
return ret;
}
static int
release (int count, int b)
{
return RB_RELEASE (int_ringbuffer, count);
}
static int
peek_data (int offset, int b)
{
return *RB_PEEK_DATA (int_ringbuffer, offset);
}
static int
poke_data (int offset, int value)
{
return RB_POKE_DATA (int_ringbuffer, offset, value);
}
static int
init_threading (int a, int b)
{
if (mtx_init (&rb_mtx, mtx_plain) != thrd_success) {
return -1;
}
if (cnd_init (&rb_write_cnd) != thrd_success) {
return -1;
}
if (cnd_init (&rb_read_cnd) != thrd_success) {
return -1;
}
return 0;
}
static const char *text = "Sometimes, it is necessary to write long gibberish "
"in order to test things. Hopefully, this may be an exception, though it's "
"not exactly the most useful or intersting text around.";
static dstring_t *out_text;
static int
compare_strings (int a, int b)
{
int ret = strcmp (out_text->str, text);
dstring_delete (out_text);
out_text = 0;
return ret;
}
static int
locked_reader (void *data)
{
if (!out_text) {
out_text = dstring_new ();
}
dstring_clear (out_text);
do {
mtx_lock (&rb_mtx);
while (RB_DATA_AVAILABLE (ringbuffer_char) < 1) {
cnd_wait (&rb_read_cnd, &rb_mtx);
}
unsigned len = RB_DATA_AVAILABLE (ringbuffer_char);
RB_READ_DATA (ringbuffer_char, dstring_reserve (out_text, len), len);
cnd_signal (&rb_write_cnd);
mtx_unlock (&rb_mtx);
} while (out_text->str[out_text->size - 1]);
return 0;
}
static int
locked_writer (void *data)
{
size_t data_len = strlen (text) + 1; // send nul terminator too
const char *str = text;
while (data_len > 0) {
mtx_lock (&rb_mtx);
while (RB_SPACE_AVAILABLE (ringbuffer_char) < 1) {
cnd_wait (&rb_write_cnd, &rb_mtx);
}
unsigned len = RB_SPACE_AVAILABLE (ringbuffer_char);
len = min (len, data_len);
RB_WRITE_DATA (ringbuffer_char, str, len);
str += len;
data_len -= len;
cnd_signal (&rb_read_cnd);
mtx_unlock (&rb_mtx);
}
return 0;
}
static int
run_locked (int a, int b)
{
thrd_t writer;
thrd_t reader;
if (thrd_create (&writer, locked_writer, 0) != thrd_success) {
return -1;
}
if (thrd_create (&reader, locked_reader, 0) != thrd_success) {
return -1;
}
int res;
if (thrd_join (writer, &res) != thrd_success) {
return -1;
}
if (thrd_join (reader, &res) != thrd_success) {
return -1;
}
return 0;
}
static int
free_reader (void *data)
{
if (!out_text) {
out_text = dstring_new ();
}
dstring_clear (out_text);
do {
while (RB_DATA_AVAILABLE (ringbuffer_atomic) < 1) {
}
unsigned len = RB_DATA_AVAILABLE (ringbuffer_atomic);
RB_READ_DATA (ringbuffer_atomic, dstring_reserve (out_text, len), len);
} while (out_text->str[out_text->size - 1]);
return 0;
}
static int
free_writer (void *data)
{
size_t data_len = strlen (text) + 1; // send nul terminator too
const char *str = text;
while (data_len > 0) {
while (RB_SPACE_AVAILABLE (ringbuffer_atomic) < 1) {
}
unsigned len = RB_SPACE_AVAILABLE (ringbuffer_atomic);
len = min (len, data_len);
RB_WRITE_DATA (ringbuffer_atomic, str, len);
str += len;
data_len -= len;
}
return 0;
}
static int
run_free (int a, int b)
{
thrd_t writer;
thrd_t reader;
if (thrd_create (&writer, free_writer, 0) != thrd_success) {
return -1;
}
if (thrd_create (&reader, free_reader, 0) != thrd_success) {
return -1;
}
int res;
if (thrd_join (writer, &res) != thrd_success) {
return -1;
}
if (thrd_join (reader, &res) != thrd_success) {
return -1;
}
return 0;
}
#define _ 0 // unused parameter
struct {
test_func test;
int param1, param2;
int test_expect;
} tests[] = {
{ get_size, _, _, 8 },
{ space_available, _, _, 7 },
{ data_available, _, _, 0 },
{ write_data, 0x600dc0de, _, 1 },
{ space_available, _, _, 6 },
{ data_available, _, _, 1 },
{ acquire, 0, _, 0xdeadbeef }, // iffy test: 0 count
{ space_available, _, _, 6 },
{ data_available, _, _, 1 },
{ read_data, 1, _, 0x600dc0de },
{ space_available, _, _, 7 },
{ data_available, _, _, 0 },
{ release, 0, _, 1 },
{ space_available, _, _, 7 },
{ data_available, _, _, 0 },
{ poke_data, 0, 1, 1 },
{ poke_data, 1, 2, 2 },
{ poke_data, 2, 3, 3 },
{ poke_data, 3, 4, 4 },
{ poke_data, 4, 5, 5 },
{ poke_data, 5, 6, 6 },
{ acquire, 6, _, 1 },
{ space_available, _, _, 1 },
{ data_available, _, _, 6 },
{ write_data, 7, _, 0 }, // head wrapped to 0
{ space_available, _, _, 0 },
{ data_available, _, _, 7 },
{ peek_data, 0, _, 1 },
{ peek_data, 1, _, 2 },
{ peek_data, 2, _, 3 },
{ peek_data, 3, _, 4 },
{ peek_data, 4, _, 5 },
{ peek_data, 5, _, 6 },
{ peek_data, 6, _, 7 },
{ space_available, _, _, 0 },
{ data_available, _, _, 7 },
{ init_threading, _, _, 0 },
{ run_locked, _, _, 0 },
{ compare_strings, _, _, 0 },
{ run_free, _, _, 0 },
{ compare_strings, _, _, 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;
for (size_t i = 0; i < num_tests; i++) {
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 %zd (line %zd) failed\n", i, i + test_start_line);
printf ("expect: %d\n", tests[i].test_expect);
printf ("got : %d\n", test_res);
}
}
return res;
}

View file

@ -191,6 +191,8 @@ pipeline_src = libs/video/renderer/vulkan/qfpipeline.plist
pipeline_gen = libs/video/renderer/vulkan/qfpipeline.plc
deferred_src = libs/video/renderer/vulkan/deferred.plist
deferred_gen = libs/video/renderer/vulkan/deferred.plc
shadow_src = libs/video/renderer/vulkan/shadow.plist
shadow_gen = libs/video/renderer/vulkan/shadow.plc
forward_src = libs/video/renderer/vulkan/forward.plist
forward_gen = libs/video/renderer/vulkan/forward.plc
@ -217,7 +219,6 @@ libs_video_renderer_librender_vulkan_la_SOURCES = \
libs/video/renderer/vulkan/memory.c \
libs/video/renderer/vulkan/pipeline.c \
libs/video/renderer/vulkan/projection.c \
libs/video/renderer/vulkan/renderpass.c \
libs/video/renderer/vulkan/resource.c \
libs/video/renderer/vulkan/scrap.c \
libs/video/renderer/vulkan/shader.c \
@ -235,6 +236,7 @@ libs_video_renderer_librender_vulkan_la_SOURCES = \
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_renderpass.c \
libs/video/renderer/vulkan/vulkan_scene.c \
libs/video/renderer/vulkan/vulkan_sprite.c \
libs/video/renderer/vulkan/vulkan_texture.c \
@ -244,7 +246,13 @@ 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) ${deferred_gen} $(forward_gen)
libs/video/renderer/vulkan/vulkan_vid_common.lo: \
libs/video/renderer/vulkan/vulkan_vid_common.c \
$(vkparse_src) \
$(pipeline_gen) \
${deferred_gen} \
${shadow_gen} \
$(forward_gen)
qwaq_cmd = $(top_builddir)/ruamoko/qwaq/qwaq-cmd$(EXEEXT)
@ -325,8 +333,6 @@ fstriangle_src = $(vkshaderpath)/fstriangle.vert
fstriangle_c = $(vkshaderpath)/fstriangle.vert.spvc
pushcolor_src = $(vkshaderpath)/pushcolor.frag
pushcolor_c = $(vkshaderpath)/pushcolor.frag.spvc
shadow_src = $(vkshaderpath)/shadow.geom
shadow_c = $(vkshaderpath)/shadow.geom.spvc
$(partphysicsc_c): $(partphysicsc_src)
$(partupdatec_c): $(partupdatec_src)
@ -390,8 +396,6 @@ $(fstriangle_c): $(fstriangle_src)
$(pushcolor_c): $(pushcolor_src)
$(shadow_c): $(shadow_src)
vkshader_c = \
$(partphysicsc_c) \
$(partupdatec_c) \
@ -459,6 +463,7 @@ BUILT_SOURCES += $(shader_gen)
EXTRA_DIST += \
$(deferred_src) \
$(shadow_src) \
$(forward_src) \
$(pipeline_src) \
libs/video/renderer/vulkan/vkparse.plist \

View file

@ -192,7 +192,6 @@ render_scene (void)
r_framecount++;
EntQueue_Clear (r_ent_queue);
r_funcs->render_view ();
r_funcs->draw_entities (r_ent_queue);
r_funcs->draw_particles (&r_psystem);
r_funcs->draw_transparent ();
}

View file

@ -264,6 +264,7 @@ gl_render_view (void)
// do 3D refresh drawing, and then update the screen
qfglClear (GL_DEPTH_BUFFER_BIT);
gl_R_RenderView ();
gl_R_RenderEntities (r_ent_queue);
}
static void
@ -531,7 +532,6 @@ vid_render_funcs_t gl_vid_render_funcs = {
gl_R_LineGraph,
gl_begin_frame,
gl_render_view,
gl_R_RenderEntities,
gl_R_DrawParticles,
gl_draw_transparent,
gl_post_process,

View file

@ -225,6 +225,7 @@ glsl_render_view (void)
{
qfeglClear (GL_DEPTH_BUFFER_BIT);
glsl_R_RenderView ();
glsl_R_RenderEntities (r_ent_queue);
}
static void
@ -475,7 +476,6 @@ vid_render_funcs_t glsl_vid_render_funcs = {
glsl_R_LineGraph,
glsl_begin_frame,
glsl_render_view,
glsl_R_RenderEntities,
glsl_R_DrawParticles,
glsl_draw_transparent,
glsl_post_process,

View file

@ -160,6 +160,7 @@ static void
sw_render_view (void)
{
R_RenderView ();
R_DrawEntitiesOnList (r_ent_queue);
}
static void
@ -489,7 +490,6 @@ vid_render_funcs_t sw_vid_render_funcs = {
R_LineGraph,
sw_begin_frame,
sw_render_view,
R_DrawEntitiesOnList,
R_DrawParticles,
sw_draw_transparent,
sw_post_process,

View file

@ -29,6 +29,7 @@
#endif
#include <stdlib.h>
#include <string.h>
#include "QF/cvar.h"
#include "QF/darray.h"
@ -50,6 +51,7 @@
#include "QF/Vulkan/qf_main.h"
#include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_particles.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_scene.h"
#include "QF/Vulkan/qf_sprite.h"
#include "QF/Vulkan/qf_texture.h"
@ -62,7 +64,6 @@
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/projection.h"
#include "QF/Vulkan/staging.h"
#include "QF/Vulkan/renderpass.h"
#include "QF/Vulkan/swapchain.h"
#include "QF/ui/view.h"
@ -89,7 +90,7 @@ vulkan_R_Init (void)
Vulkan_CreateSwapchain (vulkan_ctx);
Vulkan_CreateFrames (vulkan_ctx);
Vulkan_CreateCapture (vulkan_ctx);
Vulkan_CreateRenderPass (vulkan_ctx);
Vulkan_CreateRenderPasses (vulkan_ctx);
Vulkan_Texture_Init (vulkan_ctx);
Vulkan_Matrix_Init (vulkan_ctx);
@ -111,6 +112,7 @@ vulkan_R_Init (void)
static void
vulkan_R_ClearState (void)
{
QFV_DeviceWaitIdle (vulkan_ctx->device);
r_refdef.worldmodel = 0;
R_ClearEfrags ();
R_ClearDlights ();
@ -305,25 +307,13 @@ vulkan_render_view (void)
for (size_t i = 0; i < vulkan_ctx->renderPasses.size; i++) {
__auto_type rp = vulkan_ctx->renderPasses.a[i];
__auto_type rpFrame = &rp->frames.a[vulkan_ctx->curFrame];
frame->framebuffer = rp->framebuffers->a[imageIndex];
if (rp->framebuffers) {
frame->framebuffer = rp->framebuffers->a[imageIndex];
}
rp->draw (rpFrame);
}
}
static void
vulkan_draw_entities (entqueue_t *queue)
{
__auto_type frame = &vulkan_ctx->frames.a[vulkan_ctx->curFrame];
uint32_t imageIndex = vulkan_ctx->swapImageIndex;
for (size_t i = 0; i < vulkan_ctx->renderPasses.size; i++) {
__auto_type rp = vulkan_ctx->renderPasses.a[i];
__auto_type rpFrame = &rp->frames.a[vulkan_ctx->curFrame];
frame->framebuffer = rp->framebuffers->a[imageIndex];
Vulkan_RenderEntities (queue, rpFrame);
}
}
static void
vulkan_draw_particles (struct psystem_s *psystem)
{
@ -371,13 +361,27 @@ vulkan_end_frame (void)
.renderArea = { {0, 0}, vulkan_ctx->swapchain->extent },
};
__auto_type cmdBufs = (qfv_cmdbufferset_t) DARRAY_STATIC_INIT (4);
DARRAY_APPEND (&cmdBufs, frame->cmdBuffer);
dfunc->vkBeginCommandBuffer (frame->cmdBuffer, &beginInfo);
for (size_t i = 0; i < vulkan_ctx->renderPasses.size; i++) {
__auto_type rp = vulkan_ctx->renderPasses.a[i];
__auto_type rpFrame = &rp->frames.a[vulkan_ctx->curFrame];
if (rp->primary_commands) {
for (int j = 0; j < rpFrame->subpassCount; j++) {
__auto_type cmdSet = &rpFrame->subpassCmdSets[j];
size_t base = cmdBufs.size;
DARRAY_RESIZE (&cmdBufs, base + cmdSet->size);
memcpy (&cmdBufs.a[base], cmdSet->a,
cmdSet->size * sizeof (VkCommandBuffer));
}
continue;
}
QFV_CmdBeginLabel (device, frame->cmdBuffer, rp->name, rp->color);
if (rpFrame->renderpass) {
if (rpFrame->renderpass && rp->renderpass) {
renderPassInfo.framebuffer = frame->framebuffer,
renderPassInfo.renderPass = rp->renderpass;
renderPassInfo.clearValueCount = rp->clearValues->size;
@ -435,12 +439,14 @@ vulkan_end_frame (void)
VkSubmitInfo submitInfo = {
VK_STRUCTURE_TYPE_SUBMIT_INFO, 0,
1, &frame->imageAvailableSemaphore, &waitStage,
1, &frame->cmdBuffer,
cmdBufs.size, cmdBufs.a,
1, &frame->renderDoneSemaphore,
};
dfunc->vkResetFences (dev, 1, &frame->fence);
dfunc->vkQueueSubmit (queue->queue, 1, &submitInfo, frame->fence);
DARRAY_CLEAR (&cmdBufs);
if (vulkan_ctx->capture_callback) {
//FIXME look into "threading" this rather than waiting here
dfunc->vkWaitForFences (device->dev, 1, &frame->fence, VK_TRUE,
@ -648,11 +654,6 @@ vulkan_vid_render_choose_visual (void *data)
vulkan_ctx->cmdpool = QFV_CreateCommandPool (vulkan_ctx->device,
vulkan_ctx->device->queue.queueFamily,
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];
vulkan_ctx->fence = QFV_CreateFence (vulkan_ctx->device, 1);
Sys_MaskPrintf (SYS_vulkan, "vk choose visual %p %p %d %#zx\n",
vulkan_ctx->device->dev, vulkan_ctx->device->queue.queue,
vulkan_ctx->device->queue.queueFamily,
@ -664,7 +665,7 @@ vulkan_vid_render_create_context (void *data)
{
vulkan_ctx->create_window (vulkan_ctx);
vulkan_ctx->surface = vulkan_ctx->create_surface (vulkan_ctx);
Sys_MaskPrintf (SYS_vulkan, "vk create context %#zx\n",
Sys_MaskPrintf (SYS_vulkan, "vk create context: surface:%#zx\n",
(size_t) vulkan_ctx->surface);
}
@ -743,7 +744,6 @@ vulkan_vid_render_shutdown (void)
Vulkan_DestroyRenderPasses (vulkan_ctx);
QFV_DestroyStagingBuffer (vulkan_ctx->staging);
df->vkDestroyFence (dev, vulkan_ctx->fence, 0);
df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0);
Vulkan_Shutdown_Common (vulkan_ctx);
@ -784,7 +784,6 @@ vid_render_funcs_t vulkan_vid_render_funcs = {
vulkan_R_LineGraph,
vulkan_begin_frame,
vulkan_render_view,
vulkan_draw_entities,
vulkan_draw_particles,
vulkan_draw_transparent,
vulkan_post_process,

View file

@ -99,7 +99,7 @@
};
};
framebuffer = {
renderPass = $properties.renderpass;
renderPass = deferred;
attachments = (depth, color, emission, normal, position, opaque,
translucent, $output.view);
width = $output.extent.width;
@ -125,6 +125,16 @@
initialLayout = undefined;
finalLayout = color_attachment_optimal;
};
info = {
color = "[0, 1, 0, 1]";
subpass_info = (
{ name = depth; color = "[ 0.5, 0.5, 0.5, 1]" },
{ name = translucent; color = "[ 0.25, 0.25, 0.6, 1]" },
{ name = g-buffef; color = "[ 0.3, 0.7, 0.3, 1]" },
{ name = lighting; color = "[ 0.8, 0.8, 0.8, 1]" },
{ name = compose; color = "[ 0.7, 0.3, 0.3, 1]" },
);
};
renderpass = {
attachments = (
{

View file

@ -149,11 +149,16 @@ QFV_CreateDevice (vulkan_ctx_t *ctx, const char **extensions)
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0,
family, 1, &priority
};
VkPhysicalDeviceMultiviewFeatures multiview_features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
.multiview = 1,
};
VkPhysicalDeviceFeatures features = {
.geometryShader = 1,
.multiViewport = 1,
};
VkDeviceCreateInfo dCreateInfo = {
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0,
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, &multiview_features, 0,
1, &qCreateInfo,
nlay, lay,
next, ext,

View file

@ -279,7 +279,15 @@ QFV_CreateInstance (vulkan_ctx_t *ctx,
qfv_physdev_t *dev = &inst->devices[i];
dev->instance = inst;
dev->dev = physDev;
ifunc->vkGetPhysicalDeviceProperties (physDev, &dev->properties);
dev->properties2 = (VkPhysicalDeviceProperties2) {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
.pNext = &dev->multiViewProperties,
};
dev->multiViewProperties = (VkPhysicalDeviceMultiviewProperties) {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES,
};
ifunc->vkGetPhysicalDeviceProperties2 (physDev, &dev->properties2);
dev->properties = &dev->properties2.properties;
ifunc->vkGetPhysicalDeviceMemoryProperties (physDev,
&dev->memory_properties);
}
@ -306,8 +314,8 @@ 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);
counts = min (physdev->properties->limits.framebufferColorSampleCounts,
physdev->properties->limits.framebufferDepthSampleCounts);
while (maxSamples && maxSamples > counts) {
maxSamples >>= 1;
}

View file

@ -365,7 +365,7 @@
{
stageFlags = fragment;
offset = 0;
size = "4 * 4 + 4 + 4";
size = "4 * 4 + 4 + 4 + 4";
},
);
};
@ -672,7 +672,7 @@
dynamic = {
dynamicState = ( viewport, scissor );
};
renderPass = renderpass;
renderPass = deferred;
};
depth_base = {
@inherit = $properties.pipelines.base;

View file

@ -1,141 +0,0 @@
/*
renderpass.c
Vulkan render pass and frame buffer functions
Copyright (C) 2020 Bill Currie <bill@taniwha.org>
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/cvar.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/image.h"
#include "QF/Vulkan/renderpass.h"
VkRenderPass
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;
if (developer & SYS_vulkan) {
Sys_Printf ("attachments: %zd\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);
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: %zd\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);
}
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);
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: %zd\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,
subpassparams->size, subpassparams->a,
dependencies->size, dependencies->a,
};
VkRenderPass renderpass;
dfunc->vkCreateRenderPass (dev, &createInfo, 0, &renderpass);
return renderpass;
}
VkFramebuffer
QFV_CreateFramebuffer (qfv_device_t *device, VkRenderPass renderPass,
qfv_imageviewset_t *attachments,
VkExtent2D extent, uint32_t layers)
{
VkDevice dev = device->dev;
qfv_devfuncs_t *dfunc = device->funcs;
VkFramebufferCreateInfo createInfo = {
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 0, 0,
renderPass, attachments->size, attachments->a,
extent.width, extent.height, layers,
};
VkFramebuffer framebuffer;
dfunc->vkCreateFramebuffer (dev, &createInfo, 0, &framebuffer);
return framebuffer;
}

View file

@ -104,8 +104,6 @@ static
#include "libs/video/renderer/vulkan/shader/fstriangle.vert.spvc"
static
#include "libs/video/renderer/vulkan/shader/pushcolor.frag.spvc"
static
#include "libs/video/renderer/vulkan/shader/shadow.geom.spvc"
typedef struct shaderdata_s {
const char *name;
@ -147,7 +145,6 @@ static shaderdata_t builtin_shaders[] = {
{ "passthrough.vert", passthrough_vert, sizeof (passthrough_vert) },
{ "fstriangle.vert", fstriangle_vert, sizeof (fstriangle_vert) },
{ "pushcolor.frag", pushcolor_frag, sizeof (pushcolor_frag) },
{ "shadow.geom", shadow_geom, sizeof (shadow_geom) },
{}
};

View file

@ -12,6 +12,7 @@ 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 = 4) in vec4 color;
layout (location = 0) out vec4 frag_color;
layout (location = 1) out vec4 frag_emission;
@ -37,7 +38,7 @@ main (void)
vec3 e_st = vec3 (tl_st.xy, 1);
vec2 l_st = vec2 (tl_st.zw);
c = texture (Texture, t_st);
c = texture (Texture, t_st) * color;
e = texture (Texture, e_st);
frag_color = c;//fogBlend (c);
frag_emission = e;

View file

@ -11,11 +11,13 @@ 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 = 2) in vec4 v_color[];
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;
layout (location = 4) out vec4 color;
void
main()
@ -31,6 +33,7 @@ main()
gl_Position = Projection3d * (View * (p));
tl_st = v_tl_st[vert];
direction = v_direction[vert];
color = v_color[vert];
normal = n;
position = p;
EmitVertex ();

View file

@ -20,6 +20,7 @@ layout (location = 2) in uint entid;
layout (location = 0) out vec4 tl_st;
layout (location = 1) out vec3 direction;
layout (location = 2) out vec4 color;
void
main (void)
@ -29,4 +30,5 @@ main (void)
gl_Position = vec4 (vert, 1);
direction = (Sky * vertex).xyz;
tl_st = tl_uv;
color = entities[entid].color;
}

View file

@ -10,10 +10,12 @@ layout (push_constant) uniform PushConstants {
vec4 fog;
float time;
float alpha;
float turb_scale;
};
layout (location = 0) in vec4 tl_st;
layout (location = 1) in vec3 direction;
layout (location = 2) in vec4 color;
layout (location = 0) out vec4 frag_color;

View file

@ -6,10 +6,12 @@ layout (push_constant) uniform PushConstants {
vec4 fog;
float time;
float alpha;
float turb_scale;
};
layout (location = 0) in vec4 tl_st;
layout (location = 1) in vec3 direction;
layout (location = 2) in vec4 color;
layout (location = 0) out vec4 frag_color;
@ -25,7 +27,7 @@ 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;
return st + turb_scale * (sin ((angle + phase) * FACTOR) + BIAS) / SCALE;
}
vec4
@ -48,7 +50,8 @@ main (void)
c = texture (Texture, t_st);
e = texture (Texture, e_st);
float a = c.a * e.a * alpha;
c += e;
c.a = alpha;
frag_color = c;//fogBlend (c);
c.a = a;
frag_color = c * color;//fogBlend (c);
}

View file

@ -20,6 +20,7 @@ layout (location = 2) in uint entid;
layout (location = 0) out vec4 tl_st;
layout (location = 1) out vec3 direction;
layout (location = 2) out vec4 color;
void
main (void)
@ -28,4 +29,5 @@ main (void)
gl_Position = Projection3d * (View * vec4 (vert, 1));
direction = (Sky * vertex).xyz;
tl_st = tl_uv;
color = entities[entid].color;
}

View file

@ -1,54 +1,17 @@
{
images = {
shadow = {
flags = cube_compatible;
imageType = `2d;
format = x8_d24_unorm_pack32;
samples = 1;
extent = {
width = 256; // FIXME config
height = 256; // FIXME config
depth = 1;
};
mipLevels = 1;
arrayLayers = 2048; // FIXME config
tiling = optimal;
usage = depth_stencil_attachment|sampled;
initialLayout = undefined;
};
};
imageViews = {
shadow = {
image = depth;
viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
format = $properties.images.shadow.format;
components = {
r = identity;
g = identity;
b = identity;
a = identity;
};
subresourceRange = {
aspectMask = depth;
levelCount = 1;
layerCount = $properties.images.shadow.arrayLayers;
};
};
};
framebuffer = {
renderPass = $properties.renderpass;
attachments = (shadown);
width = $properties.images.shadow.extent.width;
height = $properties.images.shadow.extent.height;
layers = $properties.images.shadow.arrayLayers;
};
clearValues = (
{ depthStencil = { depth = 1; stencil = 0; }; },
);
renderpass = {
info = {
color = "[0.2, 0.2, 0.2, 1]";
subpass_info = (
{ name = depth; color = "[ 0.5, 0.5, 0.5, 1]" },
);
};
renderpass_base = {
attachments = (
{
format = $properties.images.depth.format;
format = $output.format;
samples = 1;
loadOp = dont_care;
storeOp = store;
@ -68,4 +31,22 @@
}
);
};
renderpass_6 = {
@inherit = $properties.renderpass_base;
@next = (VkRenderPassMultiviewCreateInfo, {
viewMasks = (0x0000003fu);
});
};
renderpass_4 = {
@inherit = $properties.renderpass_base;
@next = (VkRenderPassMultiviewCreateInfo, {
viewMasks = (0x0000000fu);
});
};
renderpass_1 = {
@inherit = $properties.renderpass_base;
@next = (VkRenderPassMultiviewCreateInfo, {
viewMasks = (0x00000001u);
});
};
}

View file

@ -41,7 +41,7 @@ qfv_stagebuf_t *
QFV_CreateStagingBuffer (qfv_device_t *device, const char *name, size_t size,
VkCommandPool cmdPool)
{
size_t atom = device->physDev->properties.limits.nonCoherentAtomSize;
size_t atom = device->physDev->properties->limits.nonCoherentAtomSize;
qfv_devfuncs_t *dfunc = device->funcs;
dstring_t *str = dstring_new ();

View file

@ -155,11 +155,14 @@ qfv_devfuncs_t dfuncs = {
.vkQueueSubmit = vkQueueSubmit,
};
qfv_physdev_t physDev = {
.properties = {
.limits = {
.nonCoherentAtomSize = 256,
.properties2 = {
.properties = {
.limits = {
.nonCoherentAtomSize = 256,
},
},
},
.properties = &physDev.properties2.properties,
};
qfv_device_t device = {
.physDev = &physDev,

View file

@ -11,6 +11,7 @@
@interface Struct: Type
{
string outname;
int write_symtab;
}
-(void) queueFieldTypes;
-(qfot_var_t *)findField:(string) fieldName;

View file

@ -84,6 +84,7 @@
PLItem *new_name = [field_dict getObjectForKey:".name"];
Array *field_defs = [Array array];
int have_sType = 0;
int have_pNext = 0;
if ([parse string] == "skip") {
return;
@ -97,6 +98,10 @@
if (field.name == "sType") {
have_sType = 1;
}
if (field.name == "pNext") {
have_pNext = 1;
write_symtab = 1;
}
}
if (field_dict) {
PLItem *field_keys = [field_dict allKeys];
@ -133,6 +138,11 @@
fprintf (output_file,
"\t{\"@inherit\", 0, QFString, parse_inherit, &%s_fields},\n",
[self outname]);
if (have_pNext) {
fprintf (output_file,
"\t{\"@next\", field_offset (%s, pNext), "
"QFArray, parse_next, 0},", [self outname]);
}
for (int i = [field_defs count]; i-- > 0; ) {
FieldDef *field_def = [field_defs objectAtIndex:i];
[field_def writeField];
@ -140,14 +150,14 @@
fprintf (output_file, "\t{ }\n");
fprintf (output_file, "};\n");
fprintf (header_file, "int parse_%s (const plfield_t *field,"
fprintf (header_file, "int %s (const plfield_t *field,"
" const plitem_t *item, void *data, plitem_t *messages,"
" void *context);\n",
[self outname]);
fprintf (output_file, "int parse_%s (const plfield_t *field,"
[self parseFunc]);
fprintf (output_file, "int %s (const plfield_t *field,"
" const plitem_t *item, void *data, plitem_t *messages,"
" void *context)\n",
[self outname]);
[self parseFunc]);
fprintf (output_file, "{\n");
if (have_sType) {
fprintf (output_file, "\t((%s *) data)->sType", [self outname]);
@ -162,6 +172,12 @@
" context);\n",
[self outname], [self outname]);
fprintf (output_file, "}\n");
if (have_pNext) {
fprintf (output_file, "static parserref_t %s_parser = ",
[self outname]);
fprintf (output_file, "{\"%s\", %s, sizeof(%s)};\n",
[self outname], [self parseFunc], [self outname]);
}
fprintf (output_file, "static exprsym_t %s_symbols[] = {\n", [self outname]);
if (field_defs) {
@ -216,6 +232,12 @@
-(void) writeSymtabEntry
{
if (!write_symtab || [parse string] == "skip") {
return;
}
fprintf (output_file,
"\tHash_Add (parser_table, &%s_parser);\n",
[self outname]);
}
-(string) outname

View file

@ -1,3 +1,9 @@
#define __x86_64__
#include <vulkan/vulkan.h>
#include "QF/Vulkan/swapchain.h"
//FIXME copy of qfv_subpass_t in qf_renderpass.h
//except it doesn't really matter because a custom spec is used
typedef struct qfv_subpass_s {
vec4 color;
string name;
} qfv_subpass_t;

View file

@ -41,14 +41,14 @@
#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/qf_renderpass.h"
#include "vid_vulkan.h"
#define vkparse_internal
#include "vkparse.h"
#undef vkparse_internal
#include "libs/video/renderer/vulkan/vkparse.hinc"
typedef struct parseres_s {
const char *name;
@ -56,6 +56,12 @@ typedef struct parseres_s {
size_t offset;
} parseres_t;
typedef struct parseref_s {
const char *name;
plparser_t parse;
size_t size;
} parserref_t;
typedef struct handleref_s {
char *name;
uint64_t handle;
@ -150,6 +156,7 @@ parse_basic (const plfield_t *field, const plitem_t *item,
exprctx_t ectx = *((parsectx_t *) context)->ectx;
exprval_t result = { etype, data };
ectx.result = &result;
ectx.item = item;
const char *valstr = PL_String (item);
//Sys_MaskPrintf (SYS_vulkan_parse, "parse_basic: %s %zd %d %p %p: %s\n",
// field->name, field->offset, field->type, field->parser,
@ -169,6 +176,34 @@ parse_basic (const plfield_t *field, const plitem_t *item,
return ret;
}
static int
parse_int32_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;
exprval_t result = { &cexpr_size_t, &val };
exprctx_t ectx = *((parsectx_t *) context)->ectx;
ectx.result = &result;
ectx.item = item;
const char *valstr = PL_String (item);
//Sys_MaskPrintf (SYS_vulkan_parse,
// "parse_int32_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);
if (!ret) {
PL_Message (messages, item, "error parsing %s: %s",
field->name, valstr);
}
*(int32_t *) data = val;
//Sys_MaskPrintf (SYS_vulkan_parse, " %d\n", *(int32_t *)data);
return ret;
}
static int
parse_uint32_t (const plfield_t *field, const plitem_t *item,
void *data, plitem_t *messages, void *context)
@ -180,6 +215,7 @@ parse_uint32_t (const plfield_t *field, const plitem_t *item,
exprval_t result = { &cexpr_size_t, &val };
exprctx_t ectx = *((parsectx_t *) context)->ectx;
ectx.result = &result;
ectx.item = item;
const char *valstr = PL_String (item);
//Sys_MaskPrintf (SYS_vulkan_parse, "parse_uint32_t: %s %zd %d %p %p: %s\n",
// field->name, field->offset, field->type, field->parser,
@ -235,6 +271,7 @@ parse_reference (const plitem_t *item, const char *type, plitem_t *messages,
plitem_t *refItem = 0;
exprval_t result = { &cexpr_plitem, &refItem };
ectx.result = &result;
ectx.item = item;
const char *name = PL_String (item);
if (cexpr_eval_string (name, &ectx)) {
PL_Message (messages, item, "not a %s reference", type);
@ -383,6 +420,7 @@ parse_inherit (const plfield_t *field, const plitem_t *item,
plitem_t *inheritItem = 0;
exprval_t result = { &cexpr_plitem, &inheritItem };
ectx.result = &result;
ectx.item = item;
const char *inheritstr = PL_String (item);
Sys_MaskPrintf (SYS_vulkan_parse, "parse_inherit: %s\n", inheritstr);
int ret = !cexpr_eval_string (inheritstr, &ectx);
@ -393,6 +431,33 @@ parse_inherit (const plfield_t *field, const plitem_t *item,
return ret;
}
static hashtab_t *parser_table;
static int
parse_next (const plfield_t *field, const plitem_t *item, void *data,
plitem_t *messages, void *context)
{
const char *type_name = PL_String (PL_ObjectAtIndex (item, 0));
plitem_t *next_def = PL_ObjectAtIndex (item, 1);
if (!type_name || PL_Type (next_def) != QFDictionary) {
PL_Message (messages, item, "invalid @next");
return 0;
}
parserref_t *parser = Hash_Find (parser_table, type_name);
if (!parser) {
PL_Message (messages, item, "Invalid type for @next: %s", type_name);
return 0;
}
void *data_ptr = vkparse_alloc (context, parser->size);
memset (data_ptr, 0, parser->size);
if (!parser->parse (field, next_def, data_ptr, messages, context)) {
return 0;
}
*(void **) data = data_ptr;
return 1;
}
static int
parse_RGBA (const plitem_t *item, void **data,
plitem_t *messages, parsectx_t *context)
@ -401,6 +466,7 @@ parse_RGBA (const plitem_t *item, void **data,
exprctx_t ectx = *context->ectx;
exprval_t result = { &cexpr_vector, data[0] };
ectx.result = &result;
ectx.item = item;
const char *valstr = PL_String (item);
Sys_MaskPrintf (SYS_vulkan_parse, "parse_RGBA: %s\n", valstr);
ret = !cexpr_eval_string (valstr, &ectx);
@ -463,6 +529,7 @@ parse_VkRenderPass (const plitem_t *item, void **data,
plitem_t *setItem = 0;
exprval_t result = { &cexpr_plitem, &setItem };
ectx.result = &result;
ectx.item = item;
ret = !cexpr_eval_string (path, &ectx);
if (ret) {
VkRenderPass setLayout;
@ -471,7 +538,7 @@ parse_VkRenderPass (const plitem_t *item, void **data,
// path not guaranteed to survive cexpr_eval_string due to va
path = resource_path (ctx, 0, name);
QFV_AddHandle (ctx->setLayouts, path, (uint64_t) setLayout);
QFV_AddHandle (ctx->renderpasses, path, (uint64_t) setLayout);
}
return ret;
}
@ -523,6 +590,7 @@ parse_VkDescriptorSetLayout (const plfield_t *field, const plitem_t *item,
plitem_t *setItem = 0;
exprval_t result = { &cexpr_plitem, &setItem };
ectx.result = &result;
ectx.item = item;
ret = !cexpr_eval_string (path, &ectx);
if (ret) {
VkDescriptorSetLayout setLayout;
@ -558,6 +626,7 @@ parse_VkPipelineLayout (const plitem_t *item, void **data,
plitem_t *setItem = 0;
exprval_t result = { &cexpr_plitem, &setItem };
ectx.result = &result;
ectx.item = item;
ret = !cexpr_eval_string (path, &ectx);
if (ret) {
VkPipelineLayout layout;
@ -592,6 +661,7 @@ parse_VkImage (const plitem_t *item, void **data, plitem_t *messages,
plitem_t *imageItem = 0;
exprval_t result = { &cexpr_plitem, &imageItem };
ectx.result = &result;
ectx.item = item;
ret = !cexpr_eval_string (path, &ectx);
if (ret) {
VkImage image;
@ -635,6 +705,7 @@ parse_VkImageView (const plfield_t *field, const plitem_t *item, void *data,
exprval_t *value = 0;
exprval_t result = { &cexpr_exprval, &value };
ectx.result = &result;
ectx.item = item;
ret = !cexpr_eval_string (path, &ectx);
plitem_t *imageViewItem = 0;
@ -864,6 +935,7 @@ parse_specialization_data (const plitem_t *item, void **data,
ectx.parent = ((parsectx_t *)context)->ectx;
ectx.symtab = &data_array_symtab;
ectx.result = &result;
ectx.item = item;
const char *valstr = PL_String (item);
//Sys_MaskPrintf (SYS_vulkan_parse,
// "parse_specialization_data: %s %zd %d %p %p %s\n",
@ -918,46 +990,6 @@ exprtype_t vulkan_frameset_t_type = {
.data = &vulkan_frameset_t_symtab,
};
typedef struct {
qfv_attachmentdescription_t *attachments;
qfv_subpassparametersset_t *subpasses;
qfv_subpassdependency_t *dependencies;
} vkparse_renderpass_t;
static plelement_t parse_qfv_renderpass_attachments_data = {
QFDictionary,
sizeof (VkAttachmentDescription),
vkparse_alloc,
parse_VkAttachmentDescription,
0,
};
static plelement_t parse_qfv_renderpass_subpasses_data = {
QFDictionary,
sizeof (VkSubpassDescription),
vkparse_alloc,
parse_VkSubpassDescription,
0,
};
static plelement_t parse_qfv_renderpass_dependencies_data = {
QFDictionary,
sizeof (VkSubpassDependency),
vkparse_alloc,
parse_VkSubpassDependency,
0,
};
static plfield_t renderpass_fields[] = {
{ "attachments", field_offset(vkparse_renderpass_t,attachments), QFArray,
PL_ParseArray, &parse_qfv_renderpass_attachments_data },
{ "subpasses", field_offset(vkparse_renderpass_t,subpasses), QFArray,
PL_ParseArray, &parse_qfv_renderpass_subpasses_data },
{ "dependencies", field_offset(vkparse_renderpass_t,dependencies), QFArray,
PL_ParseArray, &parse_qfv_renderpass_dependencies_data },
{}
};
static hashtab_t *
handlref_symtab (void (*free_func)(void*,void*), vulkan_ctx_t *ctx)
{
@ -971,6 +1003,13 @@ enum_symtab_getkey (const void *e, void *unused)
return enm->type->name;
}
static const char *
parser_getkey (const void *e, void *unused)
{
__auto_type parser = (const parserref_t *) e;
return parser->name;
}
static exprtab_t root_symtab = {
.symbols = cexpr_lib_symbols,
};
@ -988,6 +1027,7 @@ QFV_InitParse (vulkan_ctx_t *ctx)
{
exprctx_t context = {};
enum_symtab = Hash_NewTable (61, enum_symtab_getkey, 0, 0, &ctx->hashctx);
parser_table = Hash_NewTable (61, parser_getkey, 0, 0, &ctx->hashctx);
context.hashctx = &ctx->hashctx;
vkgen_init_symtabs (&context);
cexpr_init_symtab (&qfv_output_t_symtab, &context);
@ -1024,7 +1064,7 @@ parse_object (vulkan_ctx_t *ctx, memsuper_t *memsuper, plitem_t *plist,
{"frames", &vulkan_frameset_t_type, &ctx->frames},
{"msaaSamples", &VkSampleCountFlagBits_type, &ctx->msaaSamples},
{"physDevLimits", &VkPhysicalDeviceLimits_type,
&ctx->device->physDev->properties.limits },
&ctx->device->physDev->properties->limits },
{QFV_PROPERTIES, &cexpr_plitem, &parsectx.properties},
{}
};
@ -1050,33 +1090,25 @@ parse_object (vulkan_ctx_t *ctx, memsuper_t *memsuper, plitem_t *plist,
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, plitem_t *properties)
{
memsuper_t *memsuper = new_memsuper ();
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
vkparse_renderpass_t renderpass_data = {};
VkRenderPassCreateInfo cInfo = {};
if (!parse_object (ctx, memsuper, plist, parse_qfv_renderpass,
&renderpass_data, properties)) {
if (!parse_object (ctx, memsuper, plist, parse_VkRenderPassCreateInfo,
&cInfo, properties)) {
delete_memsuper (memsuper);
return 0;
}
VkRenderPass renderpass;
qfvPushDebug (ctx, va (ctx->va_ctx, "QFV_ParseRenderPass: %d", PL_Line (plist)));
renderpass = QFV_CreateRenderPass (device,
renderpass_data.attachments,
renderpass_data.subpasses,
renderpass_data.dependencies);
qfvPushDebug (ctx, va (ctx->va_ctx, "QFV_ParseRenderPass: %d",
PL_Line (plist)));
dfunc->vkCreateRenderPass (device->dev, &cInfo, 0, &renderpass);
qfvPopDebug (ctx);
delete_memsuper (memsuper);
@ -1496,3 +1528,65 @@ QFV_ParseClearValues (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties)
delete_memsuper (memsuper);
return cv;
}
static int
parse_subpassset (const plfield_t *field, const plitem_t *item, void *data,
plitem_t *messages, void *context)
{
plelement_t element = {
QFDictionary,
sizeof (qfv_subpass_t),
vkparse_alloc,
parse_qfv_subpass_t,
0,
};
plfield_t f = { 0, 0, 0, 0, &element };
if (!PL_ParseArray (&f, item, data, messages, context)) {
return 0;
}
return 1;
}
qfv_subpassset_t *
QFV_ParseSubpasses (vulkan_ctx_t *ctx, plitem_t *plist, plitem_t *properties)
{
qfv_subpassset_t *sp = 0;
memsuper_t *memsuper = new_memsuper ();
qfv_subpassset_t *subpasses = 0;
if (parse_object (ctx, memsuper, plist, parse_subpassset, &subpasses,
properties)) {
sp = DARRAY_ALLOCFIXED (qfv_subpassset_t, subpasses->size, malloc);
memcpy (sp->a, subpasses->a, sp->size * sizeof (sp->a[0]));
// the name is in memsuper which is about to be freed
for (size_t i = 0; i < sp->size; i++) {
sp->a[i].name = strdup (sp->a[i].name);
}
}
delete_memsuper (memsuper);
return sp;
}
static int
parse_rgba (const plfield_t *field, const plitem_t *item, void *data,
plitem_t *messages, void *context)
{
return parse_RGBA (item, &data, messages, context);
}
int
QFV_ParseRGBA (vulkan_ctx_t *ctx, float *rgba, plitem_t *plist,
plitem_t *properties)
{
memsuper_t *memsuper = new_memsuper ();
int ret = 0;
vec4f_t color;
if (parse_object (ctx, memsuper, plist, parse_rgba, &color, properties)) {
memcpy (rgba, &color, sizeof (color));
ret = 1;
}
delete_memsuper (memsuper);
return ret;
}

View file

@ -10,9 +10,6 @@ typedef struct parsectx_s {
#include "QF/cexpr.h"
#include "QF/plist.h"
#ifdef vkparse_internal
#include "libs/video/renderer/vulkan/vkparse.hinc"
#endif
#define QFV_PROPERTIES "properties"
@ -52,5 +49,9 @@ struct clearvalueset_s *QFV_ParseClearValues (vulkan_ctx_t *ctx,
plitem_t *plist,
plitem_t *properties);
struct qfv_subpassset_s *QFV_ParseSubpasses (vulkan_ctx_t *ctx,
plitem_t *plist,
plitem_t *properties);
int QFV_ParseRGBA (vulkan_ctx_t *ctx, float *rgba, plitem_t *plist,
plitem_t *properties);
#endif//__vkparse_h

View file

@ -28,6 +28,10 @@
VkFramebufferCreateInfo,
VkClearValue,
VkPhysicalDeviceLimits,
VkRenderPassCreateInfo,
VkRenderPassMultiviewCreateInfo,
qfv_subpass_t,
);
parse = {
VkSubpassDescription = {
@ -359,5 +363,34 @@
};
depthStencil = auto;
};
}
VkRenderPassMultiviewCreateInfo = {
viewMasks = {
type = (array, uint32_t);
size = subpassCount;
values = pViewMasks;
};
viewOffsets = {
type = (array, int32_t);
size = dependencyCount;
values = pViewOffsets;
};
correlationMasks = {
type = (array, uint32_t);
size = correlationMaskCount;
values = pCorrelationMasks;
};
};
qfv_subpass_s = {
.name = qfv_subpass_t;
color = {
type = (custom, QFString, parse_RGBA);
fields = (color);
};
name = {
type = string;
string = name;
};
};
};
}

View file

@ -42,11 +42,11 @@
#include "QF/Vulkan/qf_alias.h"
#include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/debug.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/renderpass.h"
#include "r_internal.h"
#include "vid_vulkan.h"

View file

@ -51,11 +51,13 @@
#include "QF/sys.h"
#include "QF/va.h"
#include "QF/math/bitop.h"
#include "QF/scene/entity.h"
#include "QF/Vulkan/qf_bsp.h"
#include "QF/Vulkan/qf_lightmap.h"
#include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_scene.h"
#include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/buffer.h"
@ -66,7 +68,6 @@
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/image.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/renderpass.h"
#include "QF/Vulkan/scrap.h"
#include "QF/Vulkan/staging.h"
@ -79,6 +80,7 @@ typedef struct bsp_push_constants_s {
quat_t fog;
float time;
float alpha;
float turb_scale;
} bsp_push_constants_t;
static const char * __attribute__((used)) bsp_pass_names[] = {
@ -89,14 +91,12 @@ static const char * __attribute__((used)) bsp_pass_names[] = {
};
static QFV_Subpass subpass_map[] = {
QFV_passDepth, // QFV_bspDepth
QFV_passGBuffer, // QFV_bspGBuffer
QFV_passTranslucent, // QFV_bspSky
QFV_passTranslucent, // QFV_bspTurb
[QFV_bspDepth] = QFV_passDepth,
[QFV_bspGBuffer] = QFV_passGBuffer,
[QFV_bspSky] = QFV_passTranslucent,
[QFV_bspTurb] = QFV_passTranslucent,
};
#define ALLOC_CHUNK 64
static void
add_texture (texture_t *tx, vulkan_ctx_t *ctx)
{
@ -111,22 +111,16 @@ add_texture (texture_t *tx, vulkan_ctx_t *ctx)
}
}
void
Vulkan_ClearElements (vulkan_ctx_t *ctx)
{
// bspctx_t *bctx = ctx->bsp_context;
}
static inline void
chain_surface (const bsp_face_t *face, bsp_pass_t *pass, bspctx_t *bctx)
chain_surface (const bsp_face_t *face, bsp_pass_t *pass, const bspctx_t *bctx)
{
int ent_frame = pass->ent_frame;
// if the texture has no alt animations, anim_alt holds the sama data
// as anim_main
texanim_t *anim = ent_frame ? &bctx->texdata.anim_alt[face->tex_id]
: &bctx->texdata.anim_main[face->tex_id];
const texanim_t *anim = ent_frame ? &bctx->texdata.anim_alt[face->tex_id]
: &bctx->texdata.anim_main[face->tex_id];
int anim_ind = (bctx->anim_index + anim->offset) % anim->count;
int tex_id = bctx->texdata.anim_map[anim->base + anim_ind];
int tex_id = bctx->texdata.frame_map[anim->base + anim_ind];
DARRAY_APPEND (&pass->face_queue[tex_id],
((instface_t) { pass->inst_id, face - bctx->faces }));
}
@ -163,11 +157,14 @@ clear_textures (vulkan_ctx_t *ctx)
void
Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx)
{
mod_brush_t *brush = &r_refdef.worldmodel->brush;
clear_textures (ctx);
add_texture (r_notexture_mip, ctx);
register_textures (brush, ctx);
{
// FIXME make worldmodel non-special. needs smarter handling of
// textures on sub-models but not on main model.
mod_brush_t *brush = &r_refdef.worldmodel->brush;
register_textures (brush, ctx);
}
for (int i = 0; i < num_models; i++) {
model_t *m = models[i];
if (!m)
@ -176,9 +173,10 @@ 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
// FIXME see above
if (m == r_refdef.worldmodel || m->type != mod_brush)
continue;
brush = &m->brush;
mod_brush_t *brush = &m->brush;
brush->numsubmodels = 1; // no support for submodels in non-world model
register_textures (brush, ctx);
}
@ -194,7 +192,7 @@ Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx)
if (!m || *m->path == '*') {
continue;
}
brush = &m->brush;
mod_brush_t *brush = &m->brush;
for (unsigned j = 0; j < brush->numtextures; j++) {
if (brush->textures[j]) {
textures[t++] = brush->textures[j];
@ -202,11 +200,13 @@ Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx)
}
}
// 2.5 for two texanim_t structs (32-bits each) and 1 uint16_t for each
// element
size_t texdata_size = 2.5 * num_tex * sizeof (texanim_t);
texanim_t *texdata = Hunk_AllocName (0, texdata_size, "texdata");
bctx->texdata.anim_main = texdata;
bctx->texdata.anim_alt = texdata + num_tex;
bctx->texdata.anim_map = (uint16_t *) (texdata + 2 * num_tex);
bctx->texdata.frame_map = (uint16_t *) (texdata + 2 * num_tex);
int16_t map_index = 0;
for (int i = 0; i < num_tex; i++) {
texanim_t *anim = bctx->texdata.anim_main + i;
@ -215,7 +215,7 @@ Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx)
continue;
}
*anim = (texanim_t) { .base = map_index, .offset = 0, .count = 1 };
bctx->texdata.anim_map[anim->base] = i;
bctx->texdata.frame_map[anim->base] = i;
if (textures[i]->anim_total > 1) {
// bsp loader multiplies anim_total by ANIM_CYCLE to slow the
@ -233,7 +233,7 @@ Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx)
}
*a = *anim;
a->offset = j;
bctx->texdata.anim_map[a->base + a->offset] = vtex->tex_id;
bctx->texdata.frame_map[a->base + a->offset] = vtex->tex_id;
tx = tx->anim_next;
}
if (tx != textures[i]) {
@ -253,6 +253,7 @@ Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx)
}
}
// create face queue arrays
bctx->main_pass.face_queue = malloc (num_tex * sizeof (bsp_instfaceset_t));
for (int i = 0; i < num_tex; i++) {
bctx->main_pass.face_queue[i]
@ -269,13 +270,18 @@ typedef struct {
typedef struct DARRAY_TYPE (faceref_t) facerefset_t;
static void
count_verts_inds (faceref_t *faceref, uint32_t *verts, uint32_t *inds)
count_verts_inds (const faceref_t *faceref, uint32_t *verts, uint32_t *inds)
{
msurface_t *surf = faceref->face;
*verts = surf->numedges;
*inds = surf->numedges + 1;
}
typedef struct bspvert_s {
quat_t vertex;
quat_t tlst;
} bspvert_t;
typedef struct {
bsp_face_t *faces;
uint32_t *indices;
@ -367,11 +373,11 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx)
face_sets[i] = (facerefset_t) DARRAY_STATIC_INIT (1024);
}
for (int i = 0; i < bctx->model_id; i++) {
for (int i = 0; i < bctx->num_models; i++) {
DARRAY_CLEAR (&bctx->main_pass.instances[i].entities);
}
free (bctx->main_pass.instances);
bctx->model_id = 0;
bctx->num_models = 0;
// run through all surfaces, chaining them to their textures, thus
// effectively sorting the surfaces by texture (without worrying about
@ -384,7 +390,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx)
if (!m || m->type != mod_brush) {
continue;
}
m->render_id = bctx->model_id++;
m->render_id = bctx->num_models++;
if (*m->path == '*') {
continue;
}
@ -410,9 +416,9 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx)
}
face_base += brush->numsurfaces;
}
bctx->main_pass.instances = malloc (bctx->model_id
bctx->main_pass.instances = malloc (bctx->num_models
* sizeof (bsp_instance_t));
for (int i = 0; i < bctx->model_id; i++) {
for (int i = 0; i < bctx->num_models; i++) {
DARRAY_INIT (&bctx->main_pass.instances[i].entities, 16);
}
// All vertices from all brush models go into one giant vbo.
@ -434,7 +440,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx)
}
}
size_t atom = device->physDev->properties.limits.nonCoherentAtomSize;
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);
@ -457,7 +463,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx)
free (bctx->faces);
free (bctx->poly_indices);
free (bctx->models);
bctx->models = malloc (bctx->model_id * sizeof (bsp_model_t));
bctx->models = malloc (bctx->num_models * sizeof (bsp_model_t));
bctx->faces = malloc (face_base * sizeof (bsp_face_t));
bctx->poly_indices = malloc (index_count * sizeof (uint32_t));
@ -589,13 +595,13 @@ R_DrawBrushModel (entity_t *e, bsp_pass_t *pass, vulkan_ctx_t *ctx)
Transform_GetWorldMatrix (e->transform, mat);
if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) {
radius = model->radius;
if (R_CullSphere (r_refdef.frustum, (vec_t*)&mat[3], radius)) { //FIXME
if (R_CullSphere (pass->frustum, (vec_t*)&mat[3], radius)) { //FIXME
return 1;
}
} else {
VectorAdd (mat[3], model->mins, mins);
VectorAdd (mat[3], model->maxs, maxs);
if (R_CullBox (r_refdef.frustum, mins, maxs))
if (R_CullBox (pass->frustum, mins, maxs))
return 1;
}
if (Vulkan_Scene_AddEntity (ctx, e) < 0) {
@ -604,6 +610,7 @@ R_DrawBrushModel (entity_t *e, bsp_pass_t *pass, vulkan_ctx_t *ctx)
pass->ent_frame = e->animation.frame & 1;
pass->inst_id = model->render_id;
pass->inst_id |= e->renderer.colormod[3] < 1 ? INST_ALPHA : 0;
if (!pass->instances[model->render_id].entities.size) {
bsp_model_t *m = &bctx->models[model->render_id];
bsp_face_t *face = &bctx->faces[m->first_face];
@ -628,19 +635,18 @@ visit_leaf (mleaf_t *leaf)
// 1 = back side, 0 = front side
static inline int
get_side (mnode_t *node)
get_side (const bsp_pass_t *pass, const mnode_t *node)
{
// find the node side on which we are
vec4f_t org = r_refdef.frame.position;
vec4f_t org = pass->position;
return dotf (org, node->plane)[0] < 0;
}
static inline void
visit_node (mod_brush_t *brush, mnode_t *node, int side, vulkan_ctx_t *ctx)
visit_node (bsp_pass_t *pass, const mnode_t *node, int side)
{
bspctx_t *bctx = ctx->bsp_context;
bsp_pass_t *pass = &ctx->bsp_context->main_pass;
bspctx_t *bctx = pass->bsp_context;
int c;
// sneaky hack for side = side ? SURF_PLANEBACK : 0;
@ -651,8 +657,9 @@ visit_node (mod_brush_t *brush, mnode_t *node, int side, vulkan_ctx_t *ctx)
if ((c = node->numsurfaces)) {
const bsp_face_t *face = bctx->faces + node->firstsurface;
const int *frame = pass->face_frames + node->firstsurface;
int vis_frame = pass->vis_frame;
for (; c; c--, face++, frame++) {
if (*frame != r_visframecount)
if (*frame != vis_frame)
continue;
// side is either 0 or SURF_PLANEBACK
@ -667,21 +674,22 @@ visit_node (mod_brush_t *brush, mnode_t *node, int side, vulkan_ctx_t *ctx)
}
static inline int
test_node (mod_brush_t *brush, int node_id)
test_node (const bsp_pass_t *pass, int node_id)
{
if (node_id < 0)
return 0;
if (r_node_visframes[node_id] != r_visframecount)
if (pass->node_frames[node_id] != pass->vis_frame)
return 0;
mnode_t *node = brush->nodes + node_id;
if (R_CullBox (r_refdef.frustum, node->minmaxs, node->minmaxs + 3))
mnode_t *node = pass->brush->nodes + node_id;
if (R_CullBox (pass->frustum, node->minmaxs, node->minmaxs + 3))
return 0;
return 1;
}
static void
R_VisitWorldNodes (mod_brush_t *brush, vulkan_ctx_t *ctx)
R_VisitWorldNodes (bsp_pass_t *pass, vulkan_ctx_t *ctx)
{
const mod_brush_t *brush = pass->brush;
typedef struct {
int node_id;
int side;
@ -698,11 +706,11 @@ R_VisitWorldNodes (mod_brush_t *brush, vulkan_ctx_t *ctx)
node_ptr = node_stack;
while (1) {
while (test_node (brush, node_id)) {
while (test_node (pass, node_id)) {
mnode_t *node = brush->nodes + node_id;
side = get_side (node);
side = get_side (pass, node);
front = node->children[side];
if (test_node (brush, front)) {
if (test_node (pass, front)) {
node_ptr->node_id = node_id;
node_ptr->side = side;
node_ptr++;
@ -719,7 +727,7 @@ R_VisitWorldNodes (mod_brush_t *brush, vulkan_ctx_t *ctx)
visit_leaf (leaf);
}
}
visit_node (brush, node, side, ctx);
visit_node (pass, node, side);
node_id = node->children[side ^ 1];
}
if (node_id < 0) {
@ -733,7 +741,7 @@ R_VisitWorldNodes (mod_brush_t *brush, vulkan_ctx_t *ctx)
node_id = node_ptr->node_id;
side = node_ptr->side;
mnode_t *node = brush->nodes + node_id;
visit_node (brush, node, side, ctx);
visit_node (pass, node, side);
node_id = node->children[side ^ 1];
continue;
}
@ -767,8 +775,11 @@ push_fragconst (bsp_push_constants_t *constants, VkPipelineLayout layout,
{ VK_SHADER_STAGE_FRAGMENT_BIT,
field_offset (bsp_push_constants_t, alpha),
sizeof (constants->alpha), &constants->alpha },
{ VK_SHADER_STAGE_FRAGMENT_BIT,
field_offset (bsp_push_constants_t, turb_scale),
sizeof (constants->turb_scale), &constants->turb_scale },
};
QFV_PushConstants (device, cmd, layout, 3, push_constants);
QFV_PushConstants (device, cmd, layout, 4, push_constants);
}
static void
@ -840,9 +851,6 @@ bsp_begin (qfv_renderframe_t *rFrame)
bspctx_t *bctx = ctx->bsp_context;
//XXX quat_t fog;
bctx->default_color[3] = 1;
QuatCopy (bctx->default_color, bctx->last_color);
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passDepth],
@ -872,10 +880,6 @@ turb_begin (qfv_renderframe_t *rFrame)
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
bspctx_t *bctx = ctx->bsp_context;
bctx->default_color[3] = bound (0, r_wateralpha, 1);
QuatCopy (bctx->default_color, bctx->last_color);
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucent],
@ -901,9 +905,6 @@ sky_begin (qfv_renderframe_t *rFrame)
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
bspctx_t *bctx = ctx->bsp_context;
bctx->default_color[3] = 1;
QuatCopy (bctx->default_color, bctx->last_color);
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucent],
@ -936,7 +937,7 @@ clear_queues (bspctx_t *bctx, bsp_pass_t *pass)
for (int i = 0; i < pass->num_queues; i++) {
DARRAY_RESIZE (&pass->draw_queues[i], 0);
}
for (int i = 0; i < bctx->model_id; i++) {
for (int i = 0; i < bctx->num_models; i++) {
pass->instances[i].first_instance = -1;
DARRAY_RESIZE (&pass->instances[i].entities, 0);
}
@ -944,7 +945,7 @@ clear_queues (bspctx_t *bctx, bsp_pass_t *pass)
}
static void
queue_faces (bsp_pass_t *pass, bspctx_t *bctx, bspframe_t *bframe)
queue_faces (bsp_pass_t *pass, const bspctx_t *bctx, bspframe_t *bframe)
{
pass->indices = bframe->index_data + bframe->index_count;
for (size_t i = 0; i < bctx->registered_textures.size; i++) {
@ -956,6 +957,10 @@ queue_faces (bsp_pass_t *pass, bspctx_t *bctx, bspframe_t *bframe)
__auto_type is = queue->a[j];
__auto_type f = bctx->faces[is.face];
f.flags |= ((is.inst_id & INST_ALPHA)
>> (BITOP_LOG2(INST_ALPHA)
- BITOP_LOG2(SURF_DRAWALPHA))) & SURF_DRAWALPHA;
is.inst_id &= ~INST_ALPHA;
if (pass->instances[is.inst_id].first_instance == -1) {
uint32_t count = pass->instances[is.inst_id].entities.size;
pass->instances[is.inst_id].first_instance = pass->entid_count;
@ -966,12 +971,15 @@ queue_faces (bsp_pass_t *pass, bspctx_t *bctx, bspframe_t *bframe)
}
int dq = 0;
if (bctx->faces[queue->a[0].face].flags & SURF_DRAWSKY) {
if (f.flags & SURF_DRAWSKY) {
dq = 1;
}
if (bctx->faces[queue->a[0].face].flags & SURF_DRAWTURB) {
if (f.flags & SURF_DRAWALPHA) {
dq = 2;
}
if (f.flags & SURF_DRAWTURB) {
dq = 3;
}
size_t dq_size = pass->draw_queues[dq].size;
bsp_draw_t *draw = &pass->draw_queues[dq].a[dq_size - 1];
@ -1033,8 +1041,11 @@ Vulkan_DrawWorld (qfv_renderframe_t *rFrame)
//qfv_devfuncs_t *dfunc = device->funcs;
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
mod_brush_t *brush;
bctx->main_pass.bsp_context = bctx;
bctx->main_pass.position = r_refdef.frame.position;
bctx->main_pass.frustum = r_refdef.frustum;
bctx->main_pass.vis_frame = r_visframecount;
bctx->main_pass.face_frames = r_face_visframes;
bctx->main_pass.leaf_frames = r_leaf_visframes;
bctx->main_pass.node_frames = r_node_visframes;
@ -1052,18 +1063,18 @@ Vulkan_DrawWorld (qfv_renderframe_t *rFrame)
.colormod = { 1, 1, 1, 1 },
},
};
brush = &r_refdef.worldmodel->brush;
Vulkan_Scene_AddEntity (ctx, &worldent);
int world_id = worldent.renderer.model->render_id;
bctx->main_pass.ent_frame = 0; // world is always frame 0
bctx->main_pass.inst_id = world_id;
bctx->main_pass.brush = &worldent.renderer.model->brush;
if (bctx->main_pass.instances) {
DARRAY_APPEND (&bctx->main_pass.instances[world_id].entities,
worldent.renderer.render_id);
}
R_VisitWorldNodes (brush, ctx);
R_VisitWorldNodes (&bctx->main_pass, ctx);
if (!bctx->vertex_buffer) {
return;
}
@ -1105,7 +1116,7 @@ Vulkan_Bsp_Flush (vulkan_ctx_t *ctx)
qfv_devfuncs_t *dfunc = device->funcs;
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
size_t atom = device->physDev->properties.limits.nonCoherentAtomSize;
size_t atom = device->physDev->properties->limits.nonCoherentAtomSize;
size_t atom_mask = atom - 1;
size_t index_offset = bframe->index_offset;
size_t index_size = bframe->index_count * sizeof (uint32_t);
@ -1140,22 +1151,30 @@ Vulkan_DrawWaterSurfaces (qfv_renderframe_t *rFrame)
bspctx_t *bctx = ctx->bsp_context;
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
if (!bctx->main_pass.draw_queues[2].size)
if (!bctx->main_pass.draw_queues[3].size)
return;
turb_begin (rFrame);
bsp_push_constants_t frag_constants = {
.time = vr_data.realtime,
.alpha = r_wateralpha
};
push_fragconst (&frag_constants, bctx->layout, device,
bframe->cmdSet.a[QFV_bspTurb]);
VkPipelineLayout layout = bctx->layout;
bsp_push_constants_t frag_constants = {
.time = vr_data.realtime,
.alpha = 1,
.turb_scale = 0,
};
push_fragconst (&frag_constants, layout, device,
bframe->cmdSet.a[QFV_bspTurb]);
__auto_type pass = &bctx->main_pass;
pass->textures = &bctx->registered_textures;
draw_queue (pass, 2, layout, device, bframe->cmdSet.a[QFV_bspTurb]);
frag_constants.alpha = r_wateralpha;
frag_constants.turb_scale = 1;
push_fragconst (&frag_constants, bctx->layout, device,
bframe->cmdSet.a[QFV_bspTurb]);
draw_queue (pass, 3, layout, device, bframe->cmdSet.a[QFV_bspTurb]);
turb_end (ctx);
}
@ -1381,7 +1400,7 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx)
DARRAY_INIT (&bctx->registered_textures, 64);
bctx->main_pass.num_queues = 3;//solid, sky, water
bctx->main_pass.num_queues = 4;//solid, sky, water, transparent
bctx->main_pass.draw_queues = malloc (bctx->main_pass.num_queues
* sizeof (bsp_drawset_t));
for (int i = 0; i < bctx->main_pass.num_queues; i++) {
@ -1403,7 +1422,7 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx)
size_t entid_count = Vulkan_Scene_MaxEntities (ctx);
size_t entid_size = entid_count * sizeof (uint32_t);
size_t atom = device->physDev->properties.limits.nonCoherentAtomSize;
size_t atom = device->physDev->properties->limits.nonCoherentAtomSize;
size_t atom_mask = atom - 1;
entid_size = (entid_size + atom_mask) & ~atom_mask;
bctx->entid_buffer
@ -1482,7 +1501,7 @@ Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx)
free (bctx->models);
free (bctx->main_pass.draw_queues);
for (int i = 0; i < bctx->model_id; i++) {
for (int i = 0; i < bctx->num_models; i++) {
DARRAY_CLEAR (&bctx->main_pass.instances[i].entities);
}
free (bctx->main_pass.instances);

View file

@ -45,12 +45,12 @@
#include "QF/sys.h"
#include "QF/Vulkan/qf_compose.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/debug.h"
#include "QF/Vulkan/descriptor.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/image.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/renderpass.h"
#include "r_internal.h"
#include "vid_vulkan.h"

View file

@ -52,6 +52,7 @@
#include "compat.h"
#include "QF/Vulkan/qf_draw.h"
#include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/barrier.h"
@ -62,7 +63,6 @@
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/image.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/renderpass.h"
#include "QF/Vulkan/scrap.h"
#include "QF/Vulkan/staging.h"
#include "QF/ui/view.h"

View file

@ -41,12 +41,12 @@
#include "QF/Vulkan/qf_iqm.h"
#include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/debug.h"
#include "QF/Vulkan/descriptor.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/renderpass.h"
#include "QF/Vulkan/resource.h"
#include "r_internal.h"

View file

@ -52,8 +52,11 @@
#include "QF/va.h"
#include "QF/scene/scene.h"
#include "QF/ui/view.h"
#include "QF/Vulkan/qf_draw.h"
#include "QF/Vulkan/qf_lighting.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/barrier.h"
#include "QF/Vulkan/buffer.h"
@ -63,13 +66,13 @@
#include "QF/Vulkan/image.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/projection.h"
#include "QF/Vulkan/renderpass.h"
#include "QF/Vulkan/staging.h"
#include "compat.h"
#include "r_internal.h"
#include "vid_vulkan.h"
#include "vkparse.h"
static void
update_lights (vulkan_ctx_t *ctx)
@ -118,6 +121,11 @@ update_lights (vulkan_ctx_t *ctx)
light->color[3] *= style_intensities[ldata->lightstyles.a[i]];
}
}
if (developer & SYS_lighting) {
Vulkan_Draw_String (vid.conview->xlen - 32, 8,
va (ctx->va_ctx, "%3d", light_data->lightCount),
ctx);
}
qfv_bufferbarrier_t bb = bufferBarriers[qfv_BB_Unknown_to_TransferWrite];
bb.barrier.buffer = lframe->light_buffer;
@ -210,6 +218,75 @@ Vulkan_Lighting_Draw (qfv_renderframe_t *rFrame)
dfunc->vkEndCommandBuffer (cmd);
}
static void
lighting_draw_maps (qfv_renderframe_t *rFrame)
{
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
lightingctx_t *lctx = ctx->lighting_context;
if (rFrame->subpassCmdSets[0].size) {
__auto_type sets = &rFrame->subpassCmdSets[0];
dfunc->vkFreeCommandBuffers (device->dev, lctx->cmdpool,
sets->size, sets->a);
sets->size = 0;
}
if (!lctx->ldata) {
return;
}
__auto_type bufferset = QFV_AllocCommandBufferSet (1, alloca);
QFV_AllocateCommandBuffers (device, lctx->cmdpool, 0, bufferset);
VkCommandBuffer cmd = bufferset->a[0];
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER,
cmd, va (ctx->va_ctx, "lighting:%zd", ctx->curFrame));
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
};
dfunc->vkBeginCommandBuffer (cmd, &beginInfo);
__auto_type rp = rFrame->renderpass;
QFV_CmdBeginLabel (device, cmd, rp->name, rp->color);
__auto_type lr = &lctx->light_renderers.a[0];
VkRenderPassBeginInfo renderPassInfo = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderArea = { {0, 0}, {lr->size, lr->size} },
.framebuffer = lr->framebuffer,
.renderPass = lr->renderPass,
.pClearValues = lctx->qfv_renderpass->clearValues->a,
};
__auto_type subpassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
dfunc->vkCmdBeginRenderPass (cmd, &renderPassInfo, subpassContents);
//...
dfunc->vkCmdEndRenderPass (cmd);
QFV_CmdEndLabel (device, cmd);
dfunc->vkEndCommandBuffer (cmd);
DARRAY_APPEND (&rFrame->subpassCmdSets[0], cmd);
}
void
Vulkan_Lighting_CreateRenderPasses (vulkan_ctx_t *ctx)
{
lightingctx_t *lctx = calloc (1, sizeof (lightingctx_t));
ctx->lighting_context = lctx;
// extents are dynamic and filled in for each light
// frame buffers are highly dynamic
qfv_output_t output = {};
__auto_type rp = Vulkan_CreateRenderPass (ctx, "shadow",
&output, lighting_draw_maps);
rp->primary_commands = 1;
rp->order = QFV_rp_shadowmap;
DARRAY_APPEND (&ctx->renderPasses, rp);
lctx->qfv_renderpass = rp;
}
static VkDescriptorBufferInfo base_buffer_info = {
0, 0, VK_WHOLE_SIZE
};
@ -243,13 +320,24 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
qfvPushDebug (ctx, "lighting init");
lightingctx_t *lctx = calloc (1, sizeof (lightingctx_t));
ctx->lighting_context = lctx;
// lighting_context initialized in Vulkan_Lighting_CreateRenderPasses
DARRAY_INIT (&lctx->lightmats, 16);
DARRAY_INIT (&lctx->lightlayers, 16);
DARRAY_INIT (&lctx->lightimages, 16);
DARRAY_INIT (&lctx->lightviews, 16);
ctx->output = (qfv_output_t) {.format = VK_FORMAT_X8_D24_UNORM_PACK32 };
lightingctx_t *lctx = ctx->lighting_context;
plitem_t *rp_def = lctx->qfv_renderpass->renderpassDef;
plitem_t *rp_cfg = PL_ObjectForKey (rp_def, "renderpass_6");
lctx->renderpass_6 = QFV_ParseRenderPass (ctx, rp_cfg, rp_def);
rp_cfg = PL_ObjectForKey (rp_def, "renderpass_4");
lctx->renderpass_4 = QFV_ParseRenderPass (ctx, rp_cfg, rp_def);
rp_cfg = PL_ObjectForKey (rp_def, "renderpass_1");
lctx->renderpass_1 = QFV_ParseRenderPass (ctx, rp_cfg, rp_def);
lctx->cmdpool = QFV_CreateCommandPool (device, device->queue.queueFamily,
1, 1);
DARRAY_INIT (&lctx->light_mats, 16);
DARRAY_INIT (&lctx->light_images, 16);
DARRAY_INIT (&lctx->light_renderers, 16);
size_t frames = ctx->frames.size;
DARRAY_INIT (&lctx->frames, frames);
@ -355,7 +443,7 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
lframe->shadowWrite.dstBinding = 0;
lframe->shadowWrite.descriptorCount
= min (MaxLights,
device->physDev->properties.limits.maxPerStageDescriptorSamplers);
device->physDev->properties->limits.maxPerStageDescriptorSamplers);
lframe->shadowWrite.pImageInfo = lframe->shadowInfo;
}
free (shadow_set);
@ -375,14 +463,16 @@ clear_shadows (vulkan_ctx_t *ctx)
dfunc->vkFreeMemory (device->dev, lctx->shadow_memory, 0);
lctx->shadow_memory = 0;
}
for (size_t i = 0; i < lctx->lightviews.size; i++) {
dfunc->vkDestroyImageView (device->dev, lctx->lightviews.a[i], 0);
for (size_t i = 0; i < lctx->light_renderers.size; i++) {
__auto_type lr = &lctx->light_renderers.a[i];
dfunc->vkDestroyFramebuffer (device->dev, lr->framebuffer, 0);
dfunc->vkDestroyImageView (device->dev, lr->view, 0);
}
for (size_t i = 0; i < lctx->lightimages.size; i++) {
dfunc->vkDestroyImage (device->dev, lctx->lightimages.a[i], 0);
for (size_t i = 0; i < lctx->light_images.size; i++) {
dfunc->vkDestroyImage (device->dev, lctx->light_images.a[i], 0);
}
lctx->lightimages.size = 0;
lctx->lightviews.size = 0;
lctx->light_images.size = 0;
lctx->light_renderers.size = 0;
}
void
@ -394,16 +484,20 @@ Vulkan_Lighting_Shutdown (vulkan_ctx_t *ctx)
clear_shadows (ctx);
dfunc->vkDestroyCommandPool (device->dev, lctx->cmdpool, 0);
dfunc->vkDestroyRenderPass (device->dev, lctx->renderpass_6, 0);
dfunc->vkDestroyRenderPass (device->dev, lctx->renderpass_4, 0);
dfunc->vkDestroyRenderPass (device->dev, lctx->renderpass_1, 0);
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);
DARRAY_CLEAR (&lctx->lightmats);
DARRAY_CLEAR (&lctx->lightimages);
DARRAY_CLEAR (&lctx->lightlayers);
DARRAY_CLEAR (&lctx->lightviews);
DARRAY_CLEAR (&lctx->light_mats);
DARRAY_CLEAR (&lctx->light_images);
DARRAY_CLEAR (&lctx->light_renderers);
free (lctx->frames.a);
free (lctx);
}
@ -414,7 +508,7 @@ static void
create_light_matrices (lightingctx_t *lctx)
{
lightingdata_t *ldata = lctx->ldata;
DARRAY_RESIZE (&lctx->lightmats, ldata->lights.size);
DARRAY_RESIZE (&lctx->light_mats, ldata->lights.size);
for (size_t i = 0; i < ldata->lights.size; i++) {
light_t *light = &ldata->lights.a[i];
mat4f_t view;
@ -462,7 +556,7 @@ create_light_matrices (lightingctx_t *lctx)
QFV_PerspectiveCos (proj, -light->direction[3]);
break;
}
mmulf (lctx->lightmats.a[i], proj, view);
mmulf (lctx->light_mats.a[i], proj, view);
}
}
@ -514,30 +608,26 @@ create_map (int size, int layers, int cube, vulkan_ctx_t *ctx)
}
static VkImageView
create_view (VkImage image, int baseLayer, int mode, int id, vulkan_ctx_t *ctx)
create_view (const light_renderer_t *lr, int id, vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
int layers = 0;
VkImageViewType type = 0;
const char *viewtype = 0;
switch (mode) {
switch (lr->mode) {
case ST_NONE:
return 0;
case ST_PLANE:
layers = 1;
type = VK_IMAGE_VIEW_TYPE_2D;
viewtype = "plane";
break;
case ST_CASCADE:
layers = 4;
type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
viewtype = "cascade";
break;
case ST_CUBE:
layers = 6;
type = VK_IMAGE_VIEW_TYPE_CUBE;
viewtype = "cube";
break;
@ -546,14 +636,14 @@ create_view (VkImage image, int baseLayer, int mode, int id, vulkan_ctx_t *ctx)
VkImageViewCreateInfo createInfo = {
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 0,
0,
image, type, VK_FORMAT_X8_D24_UNORM_PACK32,
lr->image, type, VK_FORMAT_X8_D24_UNORM_PACK32,
{
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
},
{ VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, baseLayer, layers }
{ VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, lr->layer, lr->numLayers }
};
VkImageView view;
@ -565,13 +655,33 @@ create_view (VkImage image, int baseLayer, int mode, int id, vulkan_ctx_t *ctx)
return view;
}
static VkFramebuffer
create_framebuffer (const light_renderer_t *lr, vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
VkFramebuffer framebuffer;
VkFramebufferCreateInfo cInfo = {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.renderPass = lr->renderPass,
.attachmentCount = 1,
.pAttachments = &lr->view,
.width = lr->size,
.height = lr->size,
.layers = 1,
};
dfunc->vkCreateFramebuffer (device->dev, &cInfo, 0, &framebuffer);
return framebuffer;
}
static void
build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
qfv_physdev_t *physDev = device->physDev;
int maxLayers = physDev->properties.limits.maxImageArrayLayers;
int maxLayers = physDev->properties->limits.maxImageArrayLayers;
lightingdata_t *ldata = lctx->ldata;
light_t *lights = ldata->lights.a;
int numLights = ldata->lights.size;
@ -585,126 +695,128 @@ build_shadow_maps (lightingctx_t *lctx, vulkan_ctx_t *ctx)
for (int i = 0; i < numLights; i++) {
lightMap[i] = i;
}
DARRAY_RESIZE (&lctx->lightlayers, numLights);
heapsort_r (lightMap, numLights, sizeof (int), light_compare, ldata);
DARRAY_RESIZE (&lctx->light_renderers, numLights);
for (int i = 0; i < numLights; i++) {
int layers = 1;
int shadow = ST_NONE;
int li = lightMap[i];
__auto_type lr = &lctx->light_renderers.a[li];
*lr = (light_renderer_t) {};
if (!lights[li].position[3]) {
shadow = ST_CASCADE;
if (!VectorIsZero (lights[li].direction)) {
lr->mode = ST_CASCADE;
}
} else {
if (lights[li].direction[3] > -0.5) {
shadow = ST_CUBE;
lr->mode = ST_CUBE;
} else {
shadow = ST_PLANE;
lr->mode = ST_PLANE;
}
}
if (shadow == ST_CASCADE || shadow == ST_NONE) {
if (lr->mode == ST_CASCADE || lr->mode == ST_NONE) {
// cascade shadows will be handled separately, and "none" has no
// shadow map at all
imageMap[li] = -1;
continue;
}
if (shadow == ST_CUBE) {
if (lr->mode == ST_CUBE) {
layers = 6;
}
if (size != abs ((int) lights[li].color[3])
|| numLayers + layers > maxLayers) {
if (numLayers) {
VkImage shadow_map = create_map (size, numLayers, 1, ctx);
DARRAY_APPEND (&lctx->lightimages, shadow_map);
DARRAY_APPEND (&lctx->light_images, shadow_map);
numLayers = 0;
}
size = abs ((int) lights[li].color[3]);
}
imageMap[li] = lctx->lightimages.size;
lctx->lightlayers.a[li] = numLayers;
imageMap[li] = lctx->light_images.size;
lr->size = size;
lr->layer = numLayers;
lr->numLayers = layers;
numLayers += layers;
totalLayers += layers;
}
if (numLayers) {
VkImage shadow_map = create_map (size, numLayers, 1, ctx);
DARRAY_APPEND (&lctx->lightimages, shadow_map);
DARRAY_APPEND (&lctx->light_images, shadow_map);
}
numLayers = 0;
size = 1024;
for (int i = 0; i < numLights; i++) {
int layers = 4;
int shadow = ST_NONE;
int li = lightMap[i];
__auto_type lr = &lctx->light_renderers.a[li];
if (!lights[li].position[3]) {
shadow = ST_CASCADE;
} else {
if (lights[li].direction[3] > -0.5) {
shadow = ST_CUBE;
} else {
shadow = ST_PLANE;
}
}
if (shadow != ST_CASCADE) {
if (lr->mode != ST_CASCADE) {
continue;
}
if (numLayers + layers > maxLayers) {
VkImage shadow_map = create_map (size, numLayers, 0, ctx);
DARRAY_APPEND (&lctx->lightimages, shadow_map);
DARRAY_APPEND (&lctx->light_images, shadow_map);
numLayers = 0;
}
imageMap[li] = lctx->lightimages.size;
lctx->lightlayers.a[li] = numLayers;
imageMap[li] = lctx->light_images.size;
lr->size = size;
lr->layer = numLayers;
lr->numLayers = layers;
numLayers += layers;
totalLayers += layers;
}
if (numLayers) {
VkImage shadow_map = create_map (size, numLayers, 0, ctx);
DARRAY_APPEND (&lctx->lightimages, shadow_map);
DARRAY_APPEND (&lctx->light_images, shadow_map);
}
for (size_t i = 0; i < lctx->lightimages.size; i++) {
memsize += QFV_GetImageSize (device, lctx->lightimages.a[i]);
for (size_t i = 0; i < lctx->light_images.size; i++) {
memsize += QFV_GetImageSize (device, lctx->light_images.a[i]);
}
lctx->shadow_memory = QFV_AllocImageMemory (device, lctx->lightimages.a[0],
lctx->shadow_memory = QFV_AllocImageMemory (device, lctx->light_images.a[0],
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
memsize, 0);
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY,
lctx->shadow_memory, "memory:shadowmap");
size_t offset = 0;
for (size_t i = 0; i < lctx->lightimages.size; i++) {
dfunc->vkBindImageMemory (device->dev, lctx->lightimages.a[i],
for (size_t i = 0; i < lctx->light_images.size; i++) {
dfunc->vkBindImageMemory (device->dev, lctx->light_images.a[i],
lctx->shadow_memory, offset);
offset += QFV_GetImageSize (device, lctx->lightimages.a[i]);
offset += QFV_GetImageSize (device, lctx->light_images.a[i]);
}
DARRAY_RESIZE (&lctx->lightviews, numLights);
for (int i = 0; i < numLights; i++) {
int li = lightMap[i];
__auto_type lr = &lctx->light_renderers.a[li];
if (imageMap[li] == -1) {
lctx->lightviews.a[li] = 0;
continue;
}
int mode = ST_NONE;
if (!ldata->lights.a[li].position[3]) {
mode = ST_CASCADE;
} else {
if (ldata->lights.a[li].direction[3] > -0.5) {
mode = ST_CUBE;
} else {
mode = ST_PLANE;
}
switch (lr->numLayers) {
case 6:
lr->renderPass = lctx->renderpass_6;
break;
case 4:
lr->renderPass = lctx->renderpass_4;
break;
case 1:
lr->renderPass = lctx->renderpass_1;
break;
default:
Sys_Error ("build_shadow_maps: invalid light layer count: %u",
lr->numLayers);
}
lctx->lightviews.a[li] = create_view (lctx->lightimages.a[imageMap[li]],
lctx->lightlayers.a[li],
mode, li, ctx);
lr->image = lctx->light_images.a[imageMap[li]];
lr->view = create_view (lr, li, ctx);
lr->framebuffer = create_framebuffer(lr, ctx);
}
Sys_MaskPrintf (SYS_vulkan, "shadow maps: %d layers in %zd images: %zd\n",
totalLayers, lctx->lightimages.size, memsize);
Sys_MaskPrintf (SYS_vulkan,
"shadow maps: %d layers in %zd images: %zd\n",
totalLayers, lctx->light_images.size, memsize);
}
void

View file

@ -48,18 +48,21 @@
#include "QF/scene/entity.h"
#include "QF/scene/scene.h"
#include "QF/Vulkan/qf_vid.h"
#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_iqm.h"
#include "QF/Vulkan/qf_lighting.h"
#include "QF/Vulkan/qf_lightmap.h"
#include "QF/Vulkan/qf_main.h"
#include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_particles.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_scene.h"
#include "QF/Vulkan/qf_sprite.h"
//#include "QF/Vulkan/qf_textures.h"
#include "QF/Vulkan/renderpass.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/swapchain.h"
#include "mod_internal.h"
#include "r_internal.h"
@ -129,6 +132,7 @@ Vulkan_RenderView (qfv_renderframe_t *rFrame)
}
Vulkan_DrawWaterSurfaces (rFrame);
Vulkan_Bsp_Flush (ctx);
Vulkan_RenderEntities (r_ent_queue, rFrame);
Vulkan_Scene_Flush (ctx);
}
@ -152,3 +156,28 @@ Vulkan_NewScene (scene_t *scene, vulkan_ctx_t *ctx)
Vulkan_BuildDisplayLists (scene->models, scene->num_models, ctx);
Vulkan_LoadLights (scene, ctx);
}
static void
main_draw (qfv_renderframe_t *rFrame)
{
Vulkan_Matrix_Draw (rFrame);
Vulkan_RenderView (rFrame);
Vulkan_FlushText (rFrame);//FIXME delayed by a frame?
Vulkan_Lighting_Draw (rFrame);
Vulkan_Compose_Draw (rFrame);
}
void
Vulkan_Main_CreateRenderPasses (vulkan_ctx_t *ctx)
{
qfv_output_t output = {
.extent = ctx->swapchain->extent,
.view = ctx->swapchain->imageViews->a[0],
.format = ctx->swapchain->format,
.view_list = ctx->swapchain->imageViews->a,
};
__auto_type rp = Vulkan_CreateRenderPass (ctx, "deferred",
&output, main_draw);
rp->order = QFV_rp_main;
DARRAY_APPEND (&ctx->renderPasses, rp);
}

View file

@ -43,13 +43,13 @@
#include "QF/sys.h"
#include "QF/va.h"
#include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_renderpass.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/instance.h"
#include "QF/Vulkan/renderpass.h"
#include "QF/Vulkan/staging.h"
#include "r_internal.h"

View file

@ -0,0 +1,283 @@
/*
renderpass.c
Vulkan render pass and frame buffer functions
Copyright (C) 2020 Bill Currie <bill@taniwha.org>
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/cvar.h"
#include "QF/hash.h"
#include "QF/plist.h"
#include "QF/va.h"
#include "QF/Vulkan/command.h"
#include "QF/Vulkan/debug.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/image.h"
#include "QF/Vulkan/swapchain.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "vid_vulkan.h"
#include "vkparse.h"
static plitem_t *
get_rp_item (vulkan_ctx_t *ctx, qfv_renderpass_t *rp, const char *name)
{
if (!rp->renderpassDef) {
rp->renderpassDef = Vulkan_GetConfig (ctx, rp->name);
}
plitem_t *item = rp->renderpassDef;
if (!item) {
Sys_Printf ("error loading %s\n", rp->name);
} else if ((item = PL_ObjectForKey (item, name))) {
Sys_MaskPrintf (SYS_vulkan_parse, "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;
}
static void
create_attachements (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
plitem_t *item = get_rp_item (ctx, rp, "images");
if (!item) {
return;
}
__auto_type images = QFV_ParseImageSet (ctx, item, rp->renderpassDef);
rp->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);
rp->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 = get_rp_item (ctx, rp, "imageViews");
if (!item) {
return;
}
__auto_type views = QFV_ParseImageViewSet (ctx, item, rp->renderpassDef);
rp->attachment_views = views;
item = get_rp_item (ctx, rp, "framebuffer");
if (!item) {
return;
}
rp->framebuffers = QFV_AllocFrameBuffers (ctx->swapchain->numImages,
malloc);
for (size_t i = 0; i < rp->framebuffers->size; i++) {
ctx->output.view = ctx->output.view_list[i];
rp->framebuffers->a[i] = QFV_ParseFramebuffer (ctx, item,
rp->renderpassDef);
}
}
static void
init_renderframe (vulkan_ctx_t *ctx, qfv_renderpass_t *rp,
qfv_renderframe_t *rFrame)
{
rFrame->subpassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
rFrame->vulkan_ctx = ctx;
rFrame->renderpass = rp;
rFrame->subpassCount = rp->subpassCount;
if (rp->subpass_info) {
rFrame->subpassInfo = rp->subpass_info->a;
}
rFrame->subpassCmdSets = malloc (rp->subpassCount
* sizeof (qfv_cmdbufferset_t));
for (size_t j = 0; j < rp->subpassCount; j++) {
DARRAY_INIT (&rFrame->subpassCmdSets[j], 4);
}
}
static void
destroy_attachments (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
if (rp->attachment_views) {
for (size_t i = 0; i < rp->attachment_views->size; i++) {
dfunc->vkDestroyImageView (device->dev,
rp->attachment_views->a[i], 0);
}
}
if (rp->attachment_images) {
for (size_t i = 0; i < rp->attachment_images->size; i++) {
dfunc->vkDestroyImage (device->dev, rp->attachment_images->a[i], 0);
}
}
dfunc->vkFreeMemory (device->dev, rp->attachmentMemory, 0);
free (rp->attachment_images);
free (rp->attachment_views);
}
static void
destroy_renderframes (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
for (size_t i = 0; i < rp->frames.size; i++) {
__auto_type rFrame = &rp->frames.a[i];
for (int j = 0; j < rFrame->subpassCount; j++) {
DARRAY_CLEAR (&rFrame->subpassCmdSets[j]);
}
free (rFrame->subpassCmdSets);
}
}
static void
destroy_framebuffers (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
for (size_t i = 0; i < rp->framebuffers->size; i++) {
dfunc->vkDestroyFramebuffer (device->dev, rp->framebuffers->a[i], 0);
}
free (rp->framebuffers);
}
qfv_renderpass_t *
Vulkan_CreateRenderPass (vulkan_ctx_t *ctx, const char *name,
qfv_output_t *output, qfv_draw_t draw)
{
plitem_t *item;
qfv_renderpass_t *rp = calloc (1, sizeof (qfv_renderpass_t));
rp->name = name;
plitem_t *rp_cfg = get_rp_item (ctx, rp, "renderpass");
if (rp_cfg) {
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) {
rp->renderpass = renderpass;
} else {
ctx->output = *output;
rp->renderpass = QFV_ParseRenderPass (ctx, rp_cfg,
rp->renderpassDef);
QFV_AddHandle (tab, path, (uint64_t) rp->renderpass);
QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_RENDER_PASS,
rp->renderpass, va (ctx->va_ctx,
"renderpass:%s", name));
}
rp->subpassCount = PL_A_NumObjects (PL_ObjectForKey (rp_cfg,
"subpasses"));
}
plitem_t *rp_info = get_rp_item (ctx, rp, "info");
if (rp_info) {
plitem_t *subpass_info = PL_ObjectForKey (rp_info, "subpass_info");
if (subpass_info) {
rp->subpass_info = QFV_ParseSubpasses (ctx, subpass_info,
rp->renderpassDef);
if (rp->subpass_info->size < rp->subpassCount) {
Sys_Printf ("warning:%s:%d: insufficient entries in "
"subpass_info\n", name, PL_Line (subpass_info));
}
if (!rp->subpassCount) {
rp->subpassCount = rp->subpass_info->size;
}
}
plitem_t *color = PL_ObjectForKey (rp_info, "color");
if (color) {
QFV_ParseRGBA (ctx, (float *)&rp->color, color, rp->renderpassDef);
}
}
int width = output->extent.width;
int height = output->extent.height;
rp->viewport = (VkViewport) { 0, 0, width, height, 0, 1 };
rp->scissor = (VkRect2D) { {0, 0}, {width, height} };
DARRAY_INIT (&rp->frames, 4);
DARRAY_RESIZE (&rp->frames, ctx->frames.size);
for (size_t i = 0; i < rp->frames.size; i++) {
init_renderframe (ctx, rp, &rp->frames.a[i]);
}
create_attachements (ctx, rp);
item = get_rp_item (ctx, rp, "clearValues");
rp->clearValues = QFV_ParseClearValues (ctx, item, rp->renderpassDef);
rp->draw = draw;
return rp;
}
void
Vulkan_DestroyRenderPass (vulkan_ctx_t *ctx, qfv_renderpass_t *renderpass)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
PL_Free (renderpass->renderpassDef);
destroy_attachments (ctx, renderpass);
dfunc->vkDestroyRenderPass (device->dev, renderpass->renderpass, 0);
destroy_renderframes (ctx, renderpass);
if (renderpass->framebuffers) {
destroy_framebuffers (ctx, renderpass);
}
DARRAY_CLEAR (&renderpass->frames);
free (renderpass->clearValues);
free (renderpass);
}

View file

@ -54,6 +54,7 @@
#include "QF/scene/entity.h"
#include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_sprite.h"
#include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/buffer.h"
@ -62,7 +63,6 @@
#include "QF/Vulkan/descriptor.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/renderpass.h"
#include "r_internal.h"
#include "vid_vulkan.h"

View file

@ -39,31 +39,27 @@
#include "QF/cvar.h"
#include "QF/dstring.h"
#include "QF/hash.h"
#include "QF/heapsort.h"
#include "QF/plist.h"
#include "QF/va.h"
#include "QF/scene/entity.h"
#include "QF/Vulkan/capture.h"
#include "QF/Vulkan/command.h"
#include "QF/Vulkan/debug.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/renderpass.h"
#include "QF/Vulkan/staging.h"
#include "QF/Vulkan/swapchain.h"
#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_main.h"
#include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_renderpass.h"
#include "QF/Vulkan/qf_vid.h"
#include "r_internal.h"
#include "vid_vulkan.h"
#include "vkparse.h"
#include "libs/video/renderer/vulkan/vkparse.hinc"
static exprsym_t builtin_plist_syms[] = {
@ -75,6 +71,10 @@ static exprsym_t builtin_plist_syms[] = {
.value = (void *)
#include "libs/video/renderer/vulkan/deferred.plc"
},
{ .name = "shadow",
.value = (void *)
#include "libs/video/renderer/vulkan/shadow.plc"
},
{ .name = "forward",
.value = (void *)
#include "libs/video/renderer/vulkan/forward.plc"
@ -314,8 +314,8 @@ build_configs (vulkan_ctx_t *ctx)
cexpr_init_symtab (&builtin_configs, &ectx);
}
static plitem_t *
get_builtin_config (vulkan_ctx_t *ctx, const char *name)
plitem_t *
Vulkan_GetConfig (vulkan_ctx_t *ctx, const char *name)
{
if (!builtin_configs.tab) {
build_configs (ctx);
@ -350,7 +350,7 @@ static plitem_t *
qfv_load_pipeline (vulkan_ctx_t *ctx, const char *name)
{
if (!ctx->pipelineDef) {
ctx->pipelineDef = get_builtin_config (ctx, "qfpipeline");
ctx->pipelineDef = Vulkan_GetConfig (ctx, "qfpipeline");
}
plitem_t *item = ctx->pipelineDef;
@ -362,240 +362,29 @@ qfv_load_pipeline (vulkan_ctx_t *ctx, const char *name)
return item;
}
static plitem_t *
qfv_load_renderpass (vulkan_ctx_t *ctx, qfv_renderpass_t *rp, const char *name)
static int
renderpass_cmp (const void *_a, const void *_b)
{
if (!rp->renderpassDef) {
rp->renderpassDef = get_builtin_config (ctx, "deferred");
}
plitem_t *item = rp->renderpassDef;
if (!item || !(item = PL_ObjectForKey (item, name))) {
Sys_Printf ("error loading %s\n", name);
} else {
Sys_MaskPrintf (SYS_vulkan_parse, "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;
}
static void
renderpass_draw (qfv_renderframe_t *rFrame)
{
Vulkan_Matrix_Draw (rFrame);
Vulkan_RenderView (rFrame);
Vulkan_FlushText (rFrame);//FIXME delayed by a frame?
Vulkan_Lighting_Draw (rFrame);
Vulkan_Compose_Draw (rFrame);
}
static void
create_attachements (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
plitem_t *item = qfv_load_renderpass (ctx, rp, "images");
if (!item) {
return;
}
__auto_type images = QFV_ParseImageSet (ctx, item, rp->renderpassDef);
rp->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);
rp->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, rp, "imageViews");
if (!item) {
return;
}
__auto_type views = QFV_ParseImageViewSet (ctx, item, rp->renderpassDef);
rp->attachment_views = views;
item = qfv_load_renderpass (ctx, rp, "framebuffer");
if (!item) {
return;
}
rp->framebuffers = QFV_AllocFrameBuffers (ctx->swapchain->numImages,
malloc);
for (size_t i = 0; i < rp->framebuffers->size; i++) {
ctx->output = (qfv_output_t) {
.extent = ctx->swapchain->extent,
.view = ctx->swapchain->imageViews->a[i],
.format = ctx->swapchain->format,
};
rp->framebuffers->a[i] = QFV_ParseFramebuffer (ctx, item,
rp->renderpassDef);
}
}
static void
init_renderframe (vulkan_ctx_t *ctx, qfv_renderpass_t *rp,
qfv_renderframe_t *rFrame)
{
// FIXME should not be hard-coded
static qfv_subpass_t subpass_info[] = {
{ .name = "depth", .color = { 0.5, 0.5, 0.5, 1} },
{ .name = "translucent", .color = { 0.25, 0.25, 0.6, 1} },
{ .name = "g-buffef", .color = { 0.3, 0.7, 0.3, 1} },
{ .name = "lighting", .color = { 0.8, 0.8, 0.8, 1} },
{ .name = "compose", .color = { 0.7, 0.3, 0.3, 1} },
};
rFrame->subpassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
rFrame->vulkan_ctx = ctx;
rFrame->renderpass = rp;
rFrame->subpassCount = QFV_NumPasses;
rFrame->subpassInfo = subpass_info; //FIXME
rFrame->subpassCmdSets = malloc (QFV_NumPasses
* sizeof (qfv_cmdbufferset_t));
for (int j = 0; j < QFV_NumPasses; j++) {
DARRAY_INIT (&rFrame->subpassCmdSets[j], 4);
}
const qfv_renderpass_t *a = _a;
const qfv_renderpass_t *b = _b;
return a->order - b->order;
}
void
Vulkan_CreateRenderPass (vulkan_ctx_t *ctx)
Vulkan_CreateRenderPasses (vulkan_ctx_t *ctx)
{
const char *name = "renderpass";//FIXME
plitem_t *item;
Vulkan_Main_CreateRenderPasses (ctx);
Vulkan_Lighting_CreateRenderPasses (ctx);
qfv_renderpass_t *rp = calloc (1, sizeof (qfv_renderpass_t));
rp->name = name;
rp->color = (vec4f_t) { 0, 1, 0, 1 }; //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) {
rp->renderpass = renderpass;
} else {
ctx->output = (qfv_output_t) {
.extent = ctx->swapchain->extent,
.view = ctx->swapchain->imageViews->a[0],
.format = ctx->swapchain->format,
};
item = qfv_load_renderpass (ctx, rp, name);
rp->renderpass = QFV_ParseRenderPass (ctx, item, rp->renderpassDef);
QFV_AddHandle (tab, path, (uint64_t) rp->renderpass);
QFV_duSetObjectName (ctx->device, VK_OBJECT_TYPE_RENDER_PASS,
rp->renderpass, va (ctx->va_ctx, "renderpass:%s",
name));
}
int width = ctx->window_width;
int height = ctx->window_height;
rp->viewport = (VkViewport) { 0, 0, width, height, 0, 1 };
rp->scissor = (VkRect2D) { {0, 0}, {width, height} };
DARRAY_INIT (&rp->frames, 4);
DARRAY_RESIZE (&rp->frames, ctx->frames.size);
for (size_t i = 0; i < rp->frames.size; i++) {
init_renderframe (ctx, rp, &rp->frames.a[i]);
}
create_attachements (ctx, rp);
item = qfv_load_renderpass (ctx, rp, "clearValues");
rp->clearValues = QFV_ParseClearValues (ctx, item, rp->renderpassDef);
rp->draw = renderpass_draw;
DARRAY_APPEND (&ctx->renderPasses, rp);
}
static void
destroy_attachments (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
for (size_t i = 0; i < rp->attachment_views->size; i++) {
dfunc->vkDestroyImageView (device->dev, rp->attachment_views->a[i], 0);
}
for (size_t i = 0; i < rp->attachment_images->size; i++) {
dfunc->vkDestroyImage (device->dev, rp->attachment_images->a[i], 0);
}
dfunc->vkFreeMemory (device->dev, rp->attachmentMemory, 0);
free (rp->attachment_images);
free (rp->attachment_views);
}
static void
destroy_renderframes (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
for (size_t i = 0; i < rp->frames.size; i++) {
__auto_type rFrame = &rp->frames.a[i];
for (int j = 0; j < rFrame->subpassCount; j++) {
DARRAY_CLEAR (&rFrame->subpassCmdSets[j]);
}
free (rFrame->subpassCmdSets);
}
}
static void
destroy_framebuffers (vulkan_ctx_t *ctx, qfv_renderpass_t *rp)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
for (size_t i = 0; i < rp->framebuffers->size; i++) {
dfunc->vkDestroyFramebuffer (device->dev, rp->framebuffers->a[i], 0);
}
free (rp->framebuffers);
heapsort (ctx->renderPasses.a, ctx->renderPasses.size,
sizeof (qfv_renderpass_t *), renderpass_cmp);
}
void
Vulkan_DestroyRenderPasses (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
for (size_t i = 0; i < ctx->renderPasses.size; i++) {
__auto_type rp = ctx->renderPasses.a[i];
PL_Free (rp->renderpassDef);
destroy_attachments (ctx, rp);
dfunc->vkDestroyRenderPass (device->dev, rp->renderpass, 0);
destroy_renderframes (ctx, rp);
destroy_framebuffers (ctx, rp);
DARRAY_CLEAR (&rp->frames);
free (rp->clearValues);
free (rp);
Vulkan_DestroyRenderPass (ctx, ctx->renderPasses.a[i]);
}
}

View file

@ -15,7 +15,7 @@ ruamoko_gui_libgui_a_SOURCES= \
ruamoko/gui/View.r
ruamoko_gui_libgui_a_dep=$(call qcautodep,$(ruamoko_gui_libgui_a_SOURCES))
ruamoko_gui_libgui_a_AR= $(PAK) -cf
EXTRA_ruamoko_gui_libgui_a_DEPENDENCIES=pak
EXTRA_ruamoko_gui_libgui_a_DEPENDENCIES=$(PAK)
include $(ruamoko_gui_libgui_a_dep) # am--include-marker
r_depfiles_remade += $(ruamoko_gui_libgui_a_dep)

View file

@ -33,7 +33,7 @@ ruamoko_lib_libr_a_SOURCES=\
ruamoko/lib/Set.r
ruamoko_lib_libr_a_dep=$(call qcautodep,$(ruamoko_lib_libr_a_SOURCES))
ruamoko_lib_libr_a_AR=$(PAK) -cf
EXTRA_ruamoko_lib_libr_a_DEPENDENCIES=pak
EXTRA_ruamoko_lib_libr_a_DEPENDENCIES=$(PAK)
include $(ruamoko_lib_libr_a_dep) # am--include-marker
r_depfiles_remade += $(ruamoko_lib_libr_a_dep)
@ -83,7 +83,7 @@ ruamoko_lib_libqw_a_SOURCES= \
ruamoko/lib/math.r
ruamoko_lib_libqw_a_dep=$(call qcautodep,$(ruamoko_lib_libqw_a_src))
ruamoko_lib_libqw_a_AR=$(PAK) -cf
EXTRA_ruamoko_lib_libqw_a_DEPENDENCIES=pak
EXTRA_ruamoko_lib_libqw_a_DEPENDENCIES=$(PAK)
include $(ruamoko_lib_libqw_a_dep) # am--include-marker
r_depfiles_remade += $(ruamoko_lib_libqw_a_dep)
@ -94,7 +94,7 @@ ruamoko_lib_libnq_a_SOURCES=\
ruamoko/lib/math.r
ruamoko_lib_libnq_a_dep=$(call qcautodep,$(ruamoko_lib_libnq_a_src))
ruamoko_lib_libnq_a_AR=$(PAK) -cf
EXTRA_ruamoko_lib_libnq_a_DEPENDENCIES=pak
EXTRA_ruamoko_lib_libnq_a_DEPENDENCIES=$(PAK)
include $(ruamoko_lib_libnq_a_dep) # am--include-marker
r_depfiles_remade += $(ruamoko_lib_libnq_a_dep)
@ -103,7 +103,7 @@ ruamoko_lib_libcsqc_a_SOURCES=\
$(ruamoko_lib_common_src)
ruamoko_lib_libcsqc_a_dep=$(call qcautodep,$(ruamoko_lib_libcsqc_a_src))
ruamoko_lib_libcsqc_a_AR= $(PAK) -cf
EXTRA_ruamoko_lib_libcsqc_a_DEPENDENCIES=pak
EXTRA_ruamoko_lib_libcsqc_a_DEPENDENCIES=$(PAK)
include $(ruamoko_lib_libcsqc_a_dep) # am--include-marker
r_depfiles_remade += $(ruamoko_lib_libcsqc_a_dep)

View file

@ -24,7 +24,7 @@ ruamoko_qwaq_libui_a_SOURCES= \
ruamoko/qwaq/ui/window.r
ruamoko_qwaq_libui_a_dep=$(call qcautodep,$(ruamoko_qwaq_libui_a_SOURCES))
ruamoko_qwaq_libui_a_AR=$(PAK) -cf
EXTRA_ruamoko_qwaq_libui_a_DEPENDENCIES=pak
EXTRA_ruamoko_qwaq_libui_a_DEPENDENCIES=$(PAK)
include $(ruamoko_qwaq_libui_a_dep) # am--include-marker
r_depfiles_remade += $(ruamoko_qwaq_libui_a_dep)

View file

@ -33,7 +33,7 @@ ruamoko_scheme_libscheme_a_SOURCES=\
ruamoko/scheme/BaseContinuation.r
ruamoko_scheme_libscheme_a_dep=$(call qcautodep,$(ruamoko_scheme_libscheme_a_SOURCES))
ruamoko_scheme_libscheme_a_AR=$(PAK) -cf
EXTRA_ruamoko_scheme_libscheme_a_DEPENDENCIES=pak
EXTRA_ruamoko_scheme_libscheme_a_DEPENDENCIES=$(PAK)
include $(ruamoko_scheme_libscheme_a_dep) # am--include-marker
r_depfiles_remade += $(ruamoko_scheme_libscheme_a_dep)

View file

@ -253,7 +253,7 @@ class pldata:
elif type(item) in [int, float]:
self.write_string(str(item))
else:
raise PListError(0, "unsupported type")
raise PListError(0, f"unsupported type {type(item)}")
def write(self, item):
self.data = []
self.write_item(item, 0)

View file

@ -25,6 +25,9 @@ from bpy.props import BoolProperty, FloatProperty, StringProperty, EnumProperty
from bpy.props import BoolVectorProperty, CollectionProperty, PointerProperty
from bpy.props import FloatVectorProperty, IntProperty
from mathutils import Vector
from math import ceil
from textwrap import TextWrapper
from .entityclass import EntityClass
@ -158,23 +161,6 @@ class QFEntpropRemove(bpy.types.Operator):
qfentity.fields.remove(qfentity.field_idx)
return {'FINISHED'}
def reflow_text(text, max_width):
lines = []
for text_line in text.split("\n"):
if not text_line:
continue
words = text_line.split(" ")
flowed_line = ""
while words:
if len(flowed_line) + len(words[0]) > max_width:
lines.append(flowed_line)
flowed_line = ""
flowed_line += (" " if flowed_line else "") + words[0]
del words[0]
if flowed_line:
lines.append(flowed_line)
return lines
class OBJECT_PT_EntityPanel(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
@ -198,9 +184,22 @@ class OBJECT_PT_EntityPanel(bpy.types.Panel):
row = layout.row()
row.prop(qfentity, "classname")
box=layout.box()
lines = reflow_text(ec.comment, 40)
for l in lines:
box.label(text=l)
width = int(ceil(context.region.width / 6))
mainwrap = TextWrapper(width = width)
subwrap = TextWrapper(width = width - 8)
for c in ec.comment:
clines = mainwrap.wrap(c)
for l in clines:
box.label(text=l)
for f in ec.fields.values():
print(f.name)
flines = subwrap.wrap(f.comment)
box.label(text=f"{f.name}")
for l in flines:
box.label(text=f" {l}")
if hasattr(f, "sounds"):
for s in f.sounds:
box.label(text=f" {s[0]} {s[1]}")
row = layout.row()
for c in range(3):
col = row.column()
@ -269,7 +268,7 @@ def set_entity_props(obj, ent):
qfe.classname = ent.d["classname"]
except TypeError:
#FIXME hmm, maybe an enum wasn't the most brilliant idea?
qfe.classname = ''
qfe.classname = '.'
if "spawnflags" in ent.d:
flags = int(float(ent.d["spawnflags"]))
for i in range(12):

View file

@ -20,9 +20,14 @@
# <pep8 compliant>
import os
from .script import Script
from .qfplist import pldata
from . import quakechr
try:
from .script import Script
from .qfplist import pldata
from . import quakechr
except ImportError:
from script import Script
from qfplist import pldata
import quakechr
MAX_FLAGS = 8
@ -34,16 +39,46 @@ class EntityClassError(Exception):
def entclass_error(self, msg):
raise EntityClassError(self.filename, self.line, msg)
class EntityField:
def __init__(self, name, default, comment):
self.name = name
self.default = default
self.comment = comment
def to_dictionary(self):
d = {}
if self.default != None:
d["default"] = self.default
if self.comment:
d["comment"] = self.comment
if hasattr(self, "sounds"):
d["sounds"] = self.sounds
return d
@classmethod
def from_dictionary(cls, name, d):
if "default" in d:
default = d["default"]
else:
default = None
if "comment" in d:
comment = d["comment"]
else:
comment = ""
field = cls(name, default, comment)
if "sounds" in d:
field.sounds = d["sounds"]
return field
class EntityClass:
def __init__(self, name, color, size, flagnames, comment):
def __init__(self, name, color, size, flagnames, comment, fields):
self.name = name
self.color = color
self.size = size
self.flagnames = flagnames
self.comment = comment
self.fields = fields
@classmethod
def null(cls):
return cls('', (1, 1, 1), None, (), "")
return cls('', (1, 1, 1), None, (), "", {})
@classmethod
def from_quaked(cls, text, filename, line = 0):
script = Script(filename, text)
@ -59,8 +94,49 @@ class EntityClass:
else:
size = None
flagnames = ()
comment = cls.extract_comment(script)
return cls(name, color, size, flagnames, comment)
comment = []
fields = {}
script.quotes = False
script.single = ""
while script.tokenAvailable(True):
line = []
while script.tokenAvailable():
script.getToken()
if script.token[-2:] == "*/":
break;
line.append(script.token)
if line:
if ((line[0][0] == '"' and line[0][-1] == '"')
or (len(line) > 1 and line[1] == '=')):
if line[0][0] == '"':
fname = line[0][1:-1]
line = line[1:]
else:
fname = line[0]
line = line[2:]
default = None
for i, t in enumerate(line[:-1]):
if t[0] == '(' and line[i + 1] == "default)":
default = t[1:]
break
line = " ".join(line)
fields[fname] = EntityField(fname, default, line)
line = None
elif "sounds" in fields:
sounds = fields["sounds"]
if not hasattr(sounds, "sounds"):
sounds.sounds = []
if line[0][-1] == ')':
line[0] = line[0][:-1]
sounds.sounds.append((line[0], " ".join(line[1:])))
line = None
else:
line = " ".join(line)
if line:
comment.append(line)
if script.token[-2:] == "*/":
break;
return cls(name, color, size, flagnames, comment, fields)
@classmethod
def from_dictionary(cls, name, d):
if "color" in d:
@ -81,11 +157,21 @@ class EntityClass:
if "comment" in d:
comment = d["comment"]
else:
comment = ""
return cls(name, color, size, flagnames, comment)
comment = []
if "fields" in d:
field_dict = d["fields"]
fields = {}
for f in field_dict:
fields[f] = EntityField.from_dictionary(f, field_dict[f])
else:
fields = {}
return cls(name, color, size, flagnames, comment, fields)
def to_dictionary(self):
fields = {}
for f in self.fields:
fields[f] = self.fields[f].to_dictionary()
d = {"color":self.color, "flagnames":self.flagnames,
"comment":self.comment}
"comment":self.comment, "fields":fields}
if self.size:
d["size"] = self.size
return d
@ -93,8 +179,11 @@ class EntityClass:
def parse_vector(cls, script):
if script.getToken() != "(":
script.error("Missing (")
v = (float(script.getToken()), float(script.getToken()),
float(script.getToken()))
s = script.getToken(), script.getToken(), script.getToken()
try:
v = (float(s[0]), float(s[1]), float(s[2]))
except ValueError:
v = s
if script.getToken() != ")":
script.error("Missing )")
return v
@ -118,7 +207,6 @@ class EntityClass:
if len(flagnames) < MAX_FLAGS:
flagnames.append(script.token)
return tuple(flagnames)
@classmethod
def extract_comment(cls, script):
if not script.tokenAvailable(True):
return ""
@ -203,3 +291,35 @@ class EntityClassDict:
self.entity_classes = {}
for k in ec.keys():
self.entity_classes[k] = EntityClass.from_dictionary(k, ec[k])
if __name__ == "__main__":
import sys
from pprint import pprint
from textwrap import TextWrapper
mainwrap = TextWrapper(width = 70)
fieldwrap = TextWrapper(width = 50)
ecd = EntityClassDict()
for fname in sys.argv[1:]:
ecd.scan_source(fname)
text = ecd.to_plist()
print(text)
ecd.from_plist(text)
for ec in ecd.entity_classes.values():
print(f"{ec.name}: {ec.color} {ec.size} {ec.flagnames}")
for c in ec.comment:
mlines = mainwrap.wrap(c)
for m in mlines:
print(f" {m}")
print()
for f in ec.fields.values():
print(f" {f.name}: {f.default}")
flines = fieldwrap.wrap(f.comment)
for l in flines:
print(f" {l}")
if f.name == "sounds":
for s in f.sounds:
print(f" {s[0]} {s[1]}")
print()
print()

View file

@ -175,8 +175,8 @@ def process_entity(ent, wads):
obj = bpy.data.objects.new(name, mesh)
else:
obj = bpy.data.objects.new(name, None)
obj.empty_draw_type = 'CUBE'
obj.empty_draw_size = 8
obj.empty_display_type = 'CUBE'
obj.empty_display_size = 8
obj.show_name = True
if "origin" in ent.d:
obj.location = parse_vector (ent.d["origin"])

View file

@ -26,17 +26,19 @@ class ScriptError(Exception):
class Script:
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.token = ""
self.unget = False
self.text = text
self.pos = 0
self.filename = filename
self.line = 1
self.no_quote_lines = False
self.single = single
self.quotes = quotes
self.pos = 0
self.line = 1
self.unget = False
def error(self, msg):
raise ScriptError(self.filename, self.line, msg)
def tokenAvailable(self, crossline=False):
@ -102,6 +104,9 @@ class Script:
self.error("EOF inside quoted string")
return None
if self.text[self.pos] == "\n":
if self.no_quote_lines:
self.error("EOL inside quoted string")
return None
self.line += 1
self.pos += 1
self.token = self.text[start:self.pos]

View file

@ -494,7 +494,7 @@ dagnode_set_edges (dag_t *dag, dagnode_t *n, statement_t *s)
set_remove (gn->edges, n->number);
}
}
if (num_params && isdigit (*num_params)) {
if (num_params && isdigit ((byte) *num_params)) {
for (i = first_param; i < *num_params - '0'; i++) {
flowvar_t *var = flowvars[i + 1];
def_t *param_def = var->op->def;

View file

@ -279,7 +279,10 @@ merge_method_lists (methodlist_t *dst, methodlist_t *src)
s->next = 0;
if (method_in_list (dst, s)) {
debug (0, "dropping duplicate method: %s", s->name);
free (s);
//FIXME this free is currently erroneous as it remains in
//known_methods, but it may also be a leak, thus only
//commented out for now.
//free (s);
} else {
// add_method does the duplicate check
*dst->tail = s;

View file

@ -63,6 +63,7 @@
//the first place, but not at all sure what to do about that)
#ifdef _WIN32
#define aligned_alloc(al, sz) _aligned_malloc(sz, al)
#define free(x) _aligned_free(x)
#endif
typedef struct {