rallyunlimited-engine/code/renderervk/vk.h
2024-02-02 19:46:17 +03:00

595 lines
15 KiB
C

#pragma once
#include "../renderercommon/vulkan/vulkan.h"
#include "tr_common.h"
#define MAX_SWAPCHAIN_IMAGES 8
#define MIN_SWAPCHAIN_IMAGES_IMM 3
#define MIN_SWAPCHAIN_IMAGES_FIFO 3
#define MIN_SWAPCHAIN_IMAGES_FIFO_0 4
#define MIN_SWAPCHAIN_IMAGES_MAILBOX 3
#define MAX_VK_SAMPLERS 32
#define MAX_VK_PIPELINES (1024 + 128)
#define VERTEX_BUFFER_SIZE (4 * 1024 * 1024)
#define IMAGE_CHUNK_SIZE (32 * 1024 * 1024)
#define MAX_IMAGE_CHUNKS 48
#define NUM_COMMAND_BUFFERS 2 // number of command buffers / render semaphores / framebuffer sets
#define USE_REVERSED_DEPTH
//#define USE_BUFFER_CLEAR
#define VK_NUM_BLOOM_PASSES 4
#define USE_DEDICATED_ALLOCATION
//#define MIN_IMAGE_ALIGN (128*1024)
#define MAX_ATTACHMENTS_IN_POOL (8+VK_NUM_BLOOM_PASSES*2) // depth + msaa + msaa-resolve + depth-resolve + screenmap.msaa + screenmap.resolve + screenmap.depth + bloom_extract + blur pairs
typedef enum {
TYPE_COLOR_WHITE,
TYPE_COLOR_GREEN,
TYPE_COLOR_RED,
TYPE_FOG_ONLY,
TYPE_DOT,
TYPE_SIGNLE_TEXTURE_LIGHTING,
TYPE_SIGNLE_TEXTURE_LIGHTING_LINEAR,
TYPE_SIGNLE_TEXTURE_DF,
TYPE_SIGNLE_TEXTURE_IDENTITY,
TYPE_GENERIC_BEGIN,
TYPE_SIGNLE_TEXTURE = TYPE_GENERIC_BEGIN,
TYPE_SIGNLE_TEXTURE_ENV,
TYPE_MULTI_TEXTURE_MUL2,
TYPE_MULTI_TEXTURE_MUL2_ENV,
TYPE_MULTI_TEXTURE_ADD2_IDENTITY,
TYPE_MULTI_TEXTURE_ADD2_IDENTITY_ENV,
TYPE_MULTI_TEXTURE_ADD2,
TYPE_MULTI_TEXTURE_ADD2_ENV,
TYPE_MULTI_TEXTURE_MUL3,
TYPE_MULTI_TEXTURE_MUL3_ENV,
TYPE_MULTI_TEXTURE_ADD3_IDENTITY,
TYPE_MULTI_TEXTURE_ADD3_IDENTITY_ENV,
TYPE_MULTI_TEXTURE_ADD3,
TYPE_MULTI_TEXTURE_ADD3_ENV,
TYPE_BLEND2_ADD,
TYPE_BLEND2_ADD_ENV,
TYPE_BLEND2_MUL,
TYPE_BLEND2_MUL_ENV,
TYPE_BLEND2_ALPHA,
TYPE_BLEND2_ALPHA_ENV,
TYPE_BLEND2_ONE_MINUS_ALPHA,
TYPE_BLEND2_ONE_MINUS_ALPHA_ENV,
TYPE_BLEND2_MIX_ALPHA,
TYPE_BLEND2_MIX_ALPHA_ENV,
TYPE_BLEND2_MIX_ONE_MINUS_ALPHA,
TYPE_BLEND2_MIX_ONE_MINUS_ALPHA_ENV,
TYPE_BLEND2_DST_COLOR_SRC_ALPHA,
TYPE_BLEND2_DST_COLOR_SRC_ALPHA_ENV,
TYPE_BLEND3_ADD,
TYPE_BLEND3_ADD_ENV,
TYPE_BLEND3_MUL,
TYPE_BLEND3_MUL_ENV,
TYPE_BLEND3_ALPHA,
TYPE_BLEND3_ALPHA_ENV,
TYPE_BLEND3_ONE_MINUS_ALPHA,
TYPE_BLEND3_ONE_MINUS_ALPHA_ENV,
TYPE_BLEND3_MIX_ALPHA,
TYPE_BLEND3_MIX_ALPHA_ENV,
TYPE_BLEND3_MIX_ONE_MINUS_ALPHA,
TYPE_BLEND3_MIX_ONE_MINUS_ALPHA_ENV,
TYPE_BLEND3_DST_COLOR_SRC_ALPHA,
TYPE_BLEND3_DST_COLOR_SRC_ALPHA_ENV,
TYPE_GENERIC_END = TYPE_BLEND3_MIX_ONE_MINUS_ALPHA_ENV
} Vk_Shader_Type;
// used with cg_shadows == 2
typedef enum {
SHADOW_DISABLED,
SHADOW_EDGES,
SHADOW_FS_QUAD,
} Vk_Shadow_Phase;
typedef enum {
TRIANGLE_LIST = 0,
TRIANGLE_STRIP,
LINE_LIST,
POINT_LIST
} Vk_Primitive_Topology;
typedef enum {
DEPTH_RANGE_NORMAL, // [0..1]
DEPTH_RANGE_ZERO, // [0..0]
DEPTH_RANGE_ONE, // [1..1]
DEPTH_RANGE_WEAPON, // [0..0.3]
DEPTH_RANGE_COUNT
} Vk_Depth_Range;
typedef struct {
VkSamplerAddressMode address_mode; // clamp/repeat texture addressing mode
int gl_mag_filter; // GL_XXX mag filter
int gl_min_filter; // GL_XXX min filter
qboolean max_lod_1_0; // fixed 1.0 lod
qboolean noAnisotropy;
} Vk_Sampler_Def;
typedef enum {
RENDER_PASS_SCREENMAP = 0,
RENDER_PASS_MAIN,
RENDER_PASS_POST_BLOOM,
RENDER_PASS_COUNT
} renderPass_t;
typedef struct {
Vk_Shader_Type shader_type;
unsigned int state_bits; // GLS_XXX flags
cullType_t face_culling;
qboolean polygon_offset;
qboolean mirror;
Vk_Shadow_Phase shadow_phase;
Vk_Primitive_Topology primitives;
int fog_stage; // off, fog-in / fog-out
int line_width;
int abs_light;
int allow_discard;
} Vk_Pipeline_Def;
typedef struct VK_Pipeline {
Vk_Pipeline_Def def;
VkPipeline handle[ RENDER_PASS_COUNT ];
} VK_Pipeline_t;
// this structure must be in sync with shader uniforms!
typedef struct vkUniform_s {
// vertex shader reference
vec4_t eyePos;
vec4_t lightPos;
// vertex - fog parameters
vec4_t fogDistanceVector;
vec4_t fogDepthVector;
vec4_t fogEyeT;
// fragment shader reference
vec4_t lightColor; // rgb + 1/(r*r)
vec4_t fogColor;
// fragment - linear dynamic light
vec4_t lightVector;
} vkUniform_t;
#define TESS_XYZ (1)
#define TESS_RGBA0 (2)
#define TESS_RGBA1 (4)
#define TESS_RGBA2 (8)
#define TESS_ST0 (16)
#define TESS_ST1 (32)
#define TESS_ST2 (64)
#define TESS_NNN (128)
#define TESS_VPOS (256) // uniform with eyePos
#define TESS_ENV (512) // mark shader stage with environment mapping
//
// Initialization.
//
// Initializes VK_Instance structure.
// After calling this function we get fully functional vulkan subsystem.
void vk_initialize( void );
// Called after initialization or renderer restart
void vk_init_descriptors( void );
// Shutdown vulkan subsystem by releasing resources acquired by Vk_Instance.
void vk_shutdown( void );
// Releases vulkan resources allocated during program execution.
// This effectively puts vulkan subsystem into initial state (the state we have after vk_initialize call).
void vk_release_resources( void );
void vk_wait_idle( void );
//
// Resources allocation.
//
void vk_create_image( image_t *image, int width, int height, int mip_levels );
void vk_upload_image_data( image_t *image, int x, int y, int width, int height, int miplevels, byte *pixels, int size );
void vk_update_descriptor_set( image_t *image, qboolean mipmap );
void vk_destroy_image_resources( VkImage *image, VkImageView *imageView );
uint32_t vk_find_pipeline_ext( uint32_t base, const Vk_Pipeline_Def *def, qboolean use );
void vk_get_pipeline_def( uint32_t pipeline, Vk_Pipeline_Def *def );
void vk_create_post_process_pipeline( int program_index, uint32_t width, uint32_t height );
void vk_create_pipelines( void );
//
// Rendering setup.
//
void vk_clear_color( const vec4_t color );
void vk_clear_depth( qboolean clear_stencil );
void vk_begin_frame( void );
void vk_end_frame( void );
void vk_end_render_pass( void );
void vk_begin_main_render_pass( void );
void vk_bind_pipeline( uint32_t pipeline );
void vk_bind_index( void );
void vk_bind_index_ext( const int numIndexes, const uint32_t*indexes );
void vk_bind_geometry( uint32_t flags );
void vk_bind_lighting( int stage, int bundle );
void vk_draw_geometry( Vk_Depth_Range depth_range, qboolean indexed );
void vk_read_pixels( byte* buffer, uint32_t width, uint32_t height ); // screenshots
qboolean vk_bloom( void );
qboolean vk_alloc_vbo( const byte *vbo_data, int vbo_size );
void vk_update_mvp( const float *m );
uint32_t vk_tess_index( uint32_t numIndexes, const void *src );
void vk_bind_index_buffer( VkBuffer buffer, uint32_t offset );
void vk_draw_indexed( uint32_t indexCount, uint32_t firstIndex );
void vk_reset_descriptor( int index );
void vk_update_descriptor( int index, VkDescriptorSet descriptor );
void vk_update_descriptor_offset( int index, uint32_t offset );
void vk_update_post_process_pipelines( void );
const char *vk_format_string( VkFormat format );
void VBO_PrepareQueues( void );
void VBO_RenderIBOItems( void );
void VBO_ClearQueue( void );
typedef struct vk_tess_s {
VkCommandBuffer command_buffer;
VkSemaphore image_acquired;
VkSemaphore rendering_finished;
VkFence rendering_finished_fence;
qboolean waitForFence;
VkBuffer vertex_buffer;
byte *vertex_buffer_ptr; // pointer to mapped vertex buffer
VkDeviceSize vertex_buffer_offset;
VkDescriptorSet uniform_descriptor;
uint32_t uniform_read_offset;
VkDeviceSize buf_offset[8];
VkDeviceSize vbo_offset[8];
VkBuffer curr_index_buffer;
uint32_t curr_index_offset;
struct {
uint32_t start, end;
VkDescriptorSet current[6]; // 0:storage, 1:uniform, 2:color0, 3:color1, 4:color2, 5:fog
uint32_t offset[2]; // 0 (uniform) and 5 (storage)
} descriptor_set;
Vk_Depth_Range depth_range;
VkPipeline last_pipeline;
uint32_t num_indexes; // value from most recent vk_bind_index() call
VkRect2D scissor_rect;
} vk_tess_t;
// Vk_Instance contains engine-specific vulkan resources that persist entire renderer lifetime.
// This structure is initialized/deinitialized by vk_initialize/vk_shutdown functions correspondingly.
typedef struct {
VkInstance instance;
VkPhysicalDevice physical_device;
VkSurfaceKHR surface;
VkSurfaceFormatKHR base_format;
VkSurfaceFormatKHR present_format;
uint32_t queue_family_index;
VkDevice device;
VkQueue queue;
VkSwapchainKHR swapchain;
uint32_t swapchain_image_count;
VkImage swapchain_images[MAX_SWAPCHAIN_IMAGES];
VkImageView swapchain_image_views[MAX_SWAPCHAIN_IMAGES];
uint32_t swapchain_image_index;
VkCommandPool command_pool;
VkDeviceMemory image_memory[ MAX_ATTACHMENTS_IN_POOL ];
uint32_t image_memory_count;
struct {
VkRenderPass main;
VkRenderPass screenmap;
VkRenderPass gamma;
VkRenderPass capture;
VkRenderPass bloom_extract;
VkRenderPass blur[VK_NUM_BLOOM_PASSES*2]; // horizontal-vertical pairs
VkRenderPass post_bloom;
} render_pass;
VkDescriptorPool descriptor_pool;
VkDescriptorSetLayout set_layout_sampler; // combined image sampler
VkDescriptorSetLayout set_layout_uniform; // dynamic uniform buffer
VkDescriptorSetLayout set_layout_storage; // feedback buffer
VkPipelineLayout pipeline_layout; // default shaders
//VkPipelineLayout pipeline_layout_storage; // flare test shader layout
VkPipelineLayout pipeline_layout_post_process; // post-processing
VkPipelineLayout pipeline_layout_blend; // post-processing
VkDescriptorSet color_descriptor;
VkImage color_image;
VkImageView color_image_view;
VkImage bloom_image[1+VK_NUM_BLOOM_PASSES*2];
VkImageView bloom_image_view[1+VK_NUM_BLOOM_PASSES*2];
VkDescriptorSet bloom_image_descriptor[1+VK_NUM_BLOOM_PASSES*2];
VkImage depth_image;
VkImageView depth_image_view;
VkImage msaa_image;
VkImageView msaa_image_view;
// screenMap
struct {
VkDescriptorSet color_descriptor;
VkImage color_image;
VkImageView color_image_view;
VkImage color_image_msaa;
VkImageView color_image_view_msaa;
VkImage depth_image;
VkImageView depth_image_view;
} screenMap;
struct {
VkImage image;
VkImageView image_view;
} capture;
struct {
VkFramebuffer blur[VK_NUM_BLOOM_PASSES*2];
VkFramebuffer bloom_extract;
VkFramebuffer main[MAX_SWAPCHAIN_IMAGES];
VkFramebuffer gamma[MAX_SWAPCHAIN_IMAGES];
VkFramebuffer screenmap;
VkFramebuffer capture;
} framebuffers;
vk_tess_t tess[ NUM_COMMAND_BUFFERS ], *cmd;
int cmd_index;
struct {
VkBuffer buffer;
byte *buffer_ptr;
VkDeviceMemory memory;
VkDescriptorSet descriptor;
} storage;
uint32_t uniform_item_size;
uint32_t uniform_alignment;
uint32_t storage_alignment;
struct {
VkBuffer vertex_buffer;
VkDeviceMemory buffer_memory;
} vbo;
// host visible memory that holds vertex, index and uniform data
VkDeviceMemory geometry_buffer_memory;
VkDeviceSize geometry_buffer_size;
VkDeviceSize geometry_buffer_size_new;
// statistics
struct {
VkDeviceSize vertex_buffer_max;
uint32_t push_size;
uint32_t push_size_max;
} stats;
//
// Shader modules.
//
struct {
struct {
VkShaderModule gen[3][2][2][2]; // tx[0,1,2], cl[0,1] env0[0,1] fog[0,1]
VkShaderModule light[2]; // fog[0,1]
VkShaderModule gen0_ident;
} vert;
struct {
VkShaderModule gen0_ident;
VkShaderModule gen0_df;
VkShaderModule gen[3][2][2]; // tx[0,1,2] cl[0,1] fog[0,1]
VkShaderModule light[2][2]; // linear[0,1] fog[0,1]
} frag;
VkShaderModule color_fs;
VkShaderModule color_vs;
VkShaderModule bloom_fs;
VkShaderModule blur_fs;
VkShaderModule blend_fs;
VkShaderModule gamma_fs;
VkShaderModule gamma_vs;
VkShaderModule fog_fs;
VkShaderModule fog_vs;
VkShaderModule dot_fs;
VkShaderModule dot_vs;
} modules;
VkPipelineCache pipelineCache;
VK_Pipeline_t pipelines[ MAX_VK_PIPELINES ];
uint32_t pipelines_count;
uint32_t pipelines_world_base;
// pipeline statistics
int32_t pipeline_create_count;
//
// Standard pipelines.
//
uint32_t skybox_pipeline;
// dim 0: 0 - front side, 1 - back size
// dim 1: 0 - normal view, 1 - mirror view
uint32_t shadow_volume_pipelines[2][2];
uint32_t shadow_finish_pipeline;
// dim 0 is based on fogPass_t: 0 - corresponds to FP_EQUAL, 1 - corresponds to FP_LE.
// dim 1 is directly a cullType_t enum value.
// dim 2 is a polygon offset value (0 - off, 1 - on).
uint32_t fog_pipelines[2][3][2];
// dim 0 is based on dlight additive flag: 0 - not additive, 1 - additive
// dim 1 is directly a cullType_t enum value.
// dim 2 is a polygon offset value (0 - off, 1 - on).
#ifdef USE_LEGACY_DLIGHTS
uint32_t dlight_pipelines[2][3][2];
#endif
// cullType[3], polygonOffset[2], fogStage[2], absLight[2]
#ifdef USE_PMLIGHT
uint32_t dlight_pipelines_x[3][2][2][2];
uint32_t dlight1_pipelines_x[3][2][2][2];
#endif
// debug visualization pipelines
uint32_t tris_debug_pipeline;
uint32_t tris_mirror_debug_pipeline;
uint32_t tris_debug_green_pipeline;
uint32_t tris_mirror_debug_green_pipeline;
uint32_t tris_debug_red_pipeline;
uint32_t tris_mirror_debug_red_pipeline;
uint32_t normals_debug_pipeline;
uint32_t surface_debug_pipeline_solid;
uint32_t surface_debug_pipeline_outline;
uint32_t images_debug_pipeline;
uint32_t surface_beam_pipeline;
uint32_t surface_axis_pipeline;
uint32_t dot_pipeline;
VkPipeline gamma_pipeline;
VkPipeline capture_pipeline;
VkPipeline bloom_extract_pipeline;
VkPipeline blur_pipeline[VK_NUM_BLOOM_PASSES*2]; // horizontal & vertical pairs
VkPipeline bloom_blend_pipeline;
#ifndef NDEBUG
VkDebugReportCallbackEXT debug_callback;
#endif
uint32_t frame_count;
qboolean active;
qboolean wideLines;
qboolean samplerAnisotropy;
qboolean fragmentStores;
qboolean dedicatedAllocation;
qboolean debugMarkers;
float maxAnisotropy;
float maxLod;
VkFormat color_format;
VkFormat capture_format;
VkFormat depth_format;
VkFormat bloom_format;
VkImageLayout initSwapchainLayout;
qboolean fastSky; // requires VK_IMAGE_USAGE_TRANSFER_DST_BIT
qboolean fboActive;
qboolean blitEnabled;
qboolean msaaActive;
qboolean offscreenRender;
qboolean windowAdjusted;
int blitX0;
int blitY0;
int blitFilter;
uint32_t renderWidth;
uint32_t renderHeight;
float renderScaleX;
float renderScaleY;
renderPass_t renderPassIndex;
uint32_t screenMapWidth;
uint32_t screenMapHeight;
uint32_t screenMapSamples;
uint32_t image_chunk_size;
uint32_t maxBoundDescriptorSets;
} Vk_Instance;
typedef struct {
VkDeviceMemory memory;
VkDeviceSize used;
} ImageChunk;
// Vk_World contains vulkan resources/state requested by the game code.
// It is reinitialized on a map change.
typedef struct {
//
// Resources.
//
int num_samplers;
Vk_Sampler_Def sampler_defs[MAX_VK_SAMPLERS];
VkSampler samplers[MAX_VK_SAMPLERS];
//
// Memory allocations.
//
int num_image_chunks;
ImageChunk image_chunks[MAX_IMAGE_CHUNKS];
// Host visible memory used to copy image data to device local memory.
VkBuffer staging_buffer;
VkDeviceMemory staging_buffer_memory;
VkDeviceSize staging_buffer_size;
byte *staging_buffer_ptr; // pointer to mapped staging buffer
//
// State.
//
// Descriptor sets corresponding to bound texture images.
//VkDescriptorSet current_descriptor_sets[ MAX_TEXTURE_UNITS ];
// This flag is used to decide whether framebuffer's depth attachment should be cleared
// with vmCmdClearAttachment (dirty_depth_attachment != 0), or it have just been
// cleared by render pass instance clear op (dirty_depth_attachment == 0).
int dirty_depth_attachment;
float modelview_transform[16];
} Vk_World;
extern Vk_Instance vk; // shouldn't be cleared during ref re-init
extern Vk_World vk_world; // this data is cleared during ref re-init