vulkan: fixed anisotropy

vulkan: fixed msaa
vulkan: fixed some validation errors
input: fixed bug with mwheel etc failing to register
screenshot_360: default to vid width/height instead of assuming a megascreeny
images: reworked Image_ResampleTexture to handle image formats in a more generic way
console: toggle command now accepts two args to toggle the cvar between
skyrooms: fixed a couple of bugs.
x11-egl: should actually work now
wayland: fixed up some omissions. still needs more work but should at least be somewhat tolerable now.
server: be a little more friendly towards ktx
server: added sv_use_dns cvar, to report reverse-dns instead of ip addresses.



git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5491 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2019-07-16 02:59:12 +00:00
parent f75beaff81
commit e0fe3c8dec
45 changed files with 1966 additions and 684 deletions

View file

@ -810,7 +810,7 @@ void CL_GatherButtons (usercmd_t *cmd, int pnum)
GATHERBIT(in_button[14-3], 16);
GATHERBIT(in_button[15-3], 17);
GATHERBIT(in_button[16-3], 18);
cmd->buttons = bits;
cmd->buttons |= bits;
}
/*
@ -1331,6 +1331,7 @@ void CLNQ_SendCmd(sizebuf_t *buf)
#ifdef CSQC_DAT
CSQC_Input_Frame(seat, cmd);
#endif
memset(&cl_pendingcmd[seat], 0, sizeof(cl_pendingcmd[seat]));
}
//inputs are only sent once we receive an entity.

View file

@ -203,19 +203,20 @@ cvar_t cl_dlemptyterminate = CVAR("cl_dlemptyterminate", "1");
cvar_t host_mapname = CVARAF("mapname", "",
"host_mapname", 0);
cvar_t ruleset_allow_playercount = CVAR("ruleset_allow_playercount", "1");
cvar_t ruleset_allow_frj = CVAR("ruleset_allow_frj", "1");
cvar_t ruleset_allow_semicheats = CVAR("ruleset_allow_semicheats", "1");
cvar_t ruleset_allow_packet = CVAR("ruleset_allow_packet", "1");
cvar_t ruleset_allow_particle_lightning = CVAR("ruleset_allow_particle_lightning", "1");
cvar_t ruleset_allow_overlongsounds = CVAR("ruleset_allow_overlong_sounds", "1");
cvar_t ruleset_allow_larger_models = CVAR("ruleset_allow_larger_models", "1");
cvar_t ruleset_allow_modified_eyes = CVAR("ruleset_allow_modified_eyes", "0");
cvar_t ruleset_allow_sensitive_texture_replacements = CVAR("ruleset_allow_sensitive_texture_replacements", "1");
cvar_t ruleset_allow_localvolume = CVAR("ruleset_allow_localvolume", "1");
cvar_t ruleset_allow_shaders = CVARF("ruleset_allow_shaders", "1", CVAR_SHADERSYSTEM);
cvar_t ruleset_allow_watervis = CVARF("ruleset_allow_watervis", "1", CVAR_SHADERSYSTEM);
cvar_t ruleset_allow_fbmodels = CVARF("ruleset_allow_fbmodels", "0", CVAR_SHADERSYSTEM);
#define RULESETADVICE " You should not normally change this cvar from its permissive default, instead impose limits on yourself only through the 'ruleset' cvar."
cvar_t ruleset_allow_playercount = CVARD("ruleset_allow_playercount", "1", "Specifies whether teamplay triggers that count nearby players are allowed in the current ruleset."RULESETADVICE);
cvar_t ruleset_allow_frj = CVARD("ruleset_allow_frj", "1", "Specifies whether Forward-Rocket-Jump scripts are allowed in the current ruleset. If 0, limits on yaw speed will be imposed so they cannot be scripted."RULESETADVICE);
cvar_t ruleset_allow_semicheats = CVARD("ruleset_allow_semicheats", "1", "If 0, this blocks a range of cvars that are marked as semi-cheats. Such cvars will be locked to their empty/0 value."RULESETADVICE);
cvar_t ruleset_allow_packet = CVARD("ruleset_allow_packet", "1", "If 0, network packets sent via the 'packet' command will be blocked. This makes scripting timers a little harder."RULESETADVICE);
cvar_t ruleset_allow_particle_lightning = CVARD("ruleset_allow_particle_lightning", "1", "A setting of 0 blocks using the particle system to replace lightning gun trails. This prevents making the trails thinner thus preventing them from obscuring your view of your enemies."RULESETADVICE);
cvar_t ruleset_allow_overlongsounds = CVARD("ruleset_allow_overlong_sounds", "1", "A setting of 0 will block the use of extra-long pickup sounds as item respawn timers."RULESETADVICE);
cvar_t ruleset_allow_larger_models = CVARD("ruleset_allow_larger_models", "1", "Enforces a maximum bounds limit on models, to prevent the use of additional spikes attached to the model from being used as a kind of wallhack."RULESETADVICE);
cvar_t ruleset_allow_modified_eyes = CVARD("ruleset_allow_modified_eyes", "0", "When 0, completely hides progs/eyes.mdl if it is not strictly identical to vanilla quake."RULESETADVICE);
cvar_t ruleset_allow_sensitive_texture_replacements = CVARD("ruleset_allow_sensitive_texture_replacements", "1", "Allows the replacement of certain model textures (as well as the models themselves). This prevents adding extra fullbrights to make them blatently obvious."RULESETADVICE);
cvar_t ruleset_allow_localvolume = CVARD("ruleset_allow_localvolume", "1", "Allows the use of the snd_playersoundvolume cvar. Muting your own sounds can make it easier to hear where your opponent is."RULESETADVICE);
cvar_t ruleset_allow_shaders = CVARFD("ruleset_allow_shaders", "1", CVAR_SHADERSYSTEM, "When 0, this completely disables the use of external shader files, preventing custom shaders from being used for wallhacks."RULESETADVICE);
cvar_t ruleset_allow_watervis = CVARFD("ruleset_allow_watervis", "1", CVAR_SHADERSYSTEM, "When 0, this enforces ugly opaque water."RULESETADVICE);
cvar_t ruleset_allow_fbmodels = CVARFD("ruleset_allow_fbmodels", "0", CVAR_SHADERSYSTEM, "When 1, allows all models to be displayed fullbright, completely ignoring the lightmaps. This feature exists only for parity with ezquake's defaults."RULESETADVICE);
extern cvar_t cl_hightrack;
extern cvar_t vid_renderer;
@ -4247,7 +4248,10 @@ void CL_ServerInfo_f(void)
if (!sv.state && cls.state && Cmd_Argc() < 2)
{
if (cl.haveserverinfo)
{
InfoBuf_Print (&cl.serverinfo, "");
Con_Printf("[%u, %s]\n", (unsigned int)cl.serverinfo.totalsize, cls.servername);
}
else
Cmd_ForwardToServer ();
}

View file

@ -2572,6 +2572,15 @@ static void SCR_ScreenShot_Mega_f(void)
return;
}
if (strcmp(Cmd_Argv(0), "screenshot_mega"))
{ //screenshot_360, screenshot_stereo etc probably don't want to capture mega screenshots
//so default to something more realistic instead.
if (!fbwidth)
fbwidth = vid.pixelwidth;
if (!fbheight)
fbheight = vid.pixelheight;
}
if (!fbwidth)
fbwidth = sh_config.texture2d_maxsize;
fbwidth = bound(1, fbwidth, sh_config.texture2d_maxsize);

View file

@ -789,7 +789,7 @@ qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, uploadfmt_
return NULL;
}
qboolean WriteTGA(char *filename, enum fs_relative fsroot, const qbyte *fte_restrict rgb_buffer, int bytestride, int width, int height, enum uploadfmt fmt)
qboolean WriteTGA(char *filename, enum fs_relative fsroot, const qbyte *fte_restrict rgb_buffer, qintptr_t bytestride, int width, int height, enum uploadfmt fmt)
{
qboolean success = false;
size_t c, i;
@ -844,20 +844,20 @@ qboolean WriteTGA(char *filename, enum fs_relative fsroot, const qbyte *fte_rest
if (ipx == opx && !rgb)
{ //can just directly write it
//bgr24, bgra24
c = width*height*opx;
c = (size_t)width*height*opx;
VFS_WRITE(vfs, header, sizeof(header));
VFS_WRITE(vfs, rgb_buffer, c);
}
else
{
qbyte *fte_restrict rgb_out = malloc(width*opx*height);
qbyte *fte_restrict rgb_out = malloc((size_t)width*opx*height);
//no need to swap alpha, and if we're just swapping alpha will be fine in-place.
if (rgb)
{ //rgb24, rgbx32, rgba32
// compact, and swap
c = width*height;
c = (size_t)width*height;
for (i=0 ; i<c ; i++)
{
rgb_out[i*opx+2] = rgb_buffer[i*ipx+0];
@ -868,7 +868,7 @@ qboolean WriteTGA(char *filename, enum fs_relative fsroot, const qbyte *fte_rest
else
{ //(bgr24), bgrx32, (bgra32)
// compact
c = width*height;
c = (size_t)width*height;
for (i=0 ; i<c ; i++)
{
rgb_out[i*opx+0] = rgb_buffer[i*ipx+0];
@ -1255,7 +1255,7 @@ error:
#ifndef NPFTE
static int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, void **buffers, int numbuffers, int bufferstride, int width, int height, enum uploadfmt fmt, qboolean writemetadata)
static int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, void **buffers, int numbuffers, qintptr_t bufferstride, int width, int height, enum uploadfmt fmt, qboolean writemetadata)
{
char name[MAX_OSPATH];
int i;
@ -1924,7 +1924,7 @@ METHODDEF(void) jpeg_error_exit (j_common_ptr cinfo)
{
longjmp(((jpeg_error_mgr_wrapper *) cinfo->err)->setjmp_buffer, 1);
}
static qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int stride, int screenwidth, int screenheight, enum uploadfmt fmt, unsigned int writemeta)
static qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, qintptr_t stride, int screenwidth, int screenheight, enum uploadfmt fmt, unsigned int writemeta)
{
qbyte *buffer;
vfsfile_t *outfile;
@ -2550,7 +2550,7 @@ static qbyte *ReadBMPFile(qbyte *buf, int length, int *width, int *height)
return ReadRawBMPFile(buf + 14, length-14, width, height, OffsetofBMPBits - 14);
}
qboolean WriteBMPFile(char *filename, enum fs_relative fsroot, qbyte *in, int instride, int width, int height, uploadfmt_t fmt)
qboolean WriteBMPFile(char *filename, enum fs_relative fsroot, qbyte *in, qintptr_t instride, int width, int height, uploadfmt_t fmt)
{
int y;
bmpheader_t h;
@ -5407,18 +5407,12 @@ static void Image_Resample32Lerp(const void *indata, int inwidth, int inheight,
GL_ResampleTexture
================
*/
void Image_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight)
static void Image_ResampleTexture32Nearest (const unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight)
{
int i, j;
unsigned *inrow;
const unsigned *inrow;
unsigned frac, fracstep;
if (gl_lerpimages.ival)
{
Image_Resample32Lerp(in, inwidth, inheight, out, outwidth, outheight);
return;
}
fracstep = inwidth*0x10000/outwidth;
for (i=0 ; i<outheight ; i++, out += outwidth)
{
@ -5446,18 +5440,12 @@ void Image_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *o
}
}
void Image_ResampleTexture8 (unsigned char *in, int inwidth, int inheight, unsigned char *out, int outwidth, int outheight)
static void Image_ResampleTexture8Nearest (const unsigned char *in, int inwidth, int inheight, unsigned char *out, int outwidth, int outheight)
{
int i, j;
unsigned char *inrow;
const unsigned char *inrow;
unsigned frac, fracstep;
/*if (gl_lerpimages.ival)
{
Image_Resample32Lerp(in, inwidth, inheight, out, outwidth, outheight);
return;
}*/
fracstep = inwidth*0x10000/outwidth;
for (i=0 ; i<outheight ; i++, out += outwidth)
{
@ -5484,18 +5472,12 @@ void Image_ResampleTexture8 (unsigned char *in, int inwidth, int inheight, unsig
}
}
}
void Image_ResampleTexture16 (unsigned short *in, int inwidth, int inheight, unsigned short *out, int outwidth, int outheight)
static void Image_ResampleTexture16Nearest (const unsigned short *in, int inwidth, int inheight, unsigned short *out, int outwidth, int outheight)
{
int i, j;
unsigned short *inrow;
const unsigned short *inrow;
unsigned frac, fracstep;
/*if (gl_lerpimages.ival)
{
Image_Resample32Lerp(in, inwidth, inheight, out, outwidth, outheight);
return;
}*/
fracstep = inwidth*0x10000/outwidth;
for (i=0 ; i<outheight ; i++, out += outwidth)
{
@ -5523,6 +5505,72 @@ void Image_ResampleTexture16 (unsigned short *in, int inwidth, int inheight, uns
}
}
//returns out on success. if out is null then returns a new BZ_Malloced buffer
void *Image_ResampleTexture (uploadfmt_t format, const void *in, int inwidth, int inheight, void *out, int outwidth, int outheight)
{
switch(format)
{
case PTI_INVALID:
default:
return NULL;
//we don't care about byte order etc, just channels+sizes.
case PTI_LLLX8:
case PTI_LLLA8:
case PTI_RGBA8:
case PTI_RGBX8:
case PTI_BGRA8:
case PTI_BGRX8:
case PTI_RGBA8_SRGB:
case PTI_RGBX8_SRGB:
case PTI_BGRA8_SRGB:
case PTI_BGRX8_SRGB:
if (!out)
out = BZ_Malloc(((outwidth+3)&~3)*outheight*4);
if (gl_lerpimages.ival)
Image_Resample32Lerp(in, inwidth, inheight, out, outwidth, outheight); //FIXME: should be sRGB-aware, but probably not a common path on hardware that can actually do srgb.
else
Image_ResampleTexture32Nearest(in, inwidth, inheight, out, outwidth, outheight);
return out;
case PTI_R32F:
case PTI_A2BGR10:
case PTI_E5BGR9:
if (!out)
out = BZ_Malloc(((outwidth+3)&~3)*outheight*4);
Image_ResampleTexture32Nearest(in, inwidth, inheight, out, outwidth, outheight);
return out;
case PTI_P8:
case PTI_L8:
case PTI_R8:
case PTI_L8_SRGB:
case PTI_R8_SNORM:
if (!out)
out = BZ_Malloc((outwidth+3)*outheight);
Image_ResampleTexture8Nearest(in, inwidth, inheight, out, outwidth, outheight);
return out;
case PTI_RG8:
case PTI_RG8_SNORM:
case PTI_L8A8:
case PTI_L8A8_SRGB:
case PTI_R16:
case PTI_R16F:
case PTI_RGB565:
case PTI_RGBA4444:
case PTI_ARGB4444:
case PTI_RGBA5551:
case PTI_ARGB1555:
if (!out)
out = BZ_Malloc((outwidth+3)*outheight*2);
Image_ResampleTexture16Nearest(in, inwidth, inheight, out, outwidth, outheight);
return out;
case PTI_RGB8:
case PTI_BGR8:
case PTI_RGBA16:
case PTI_RGBA16F:
case PTI_RGBA32F:
return NULL; //fixmes
}
}
//ripped from tenebrae
static unsigned int * Image_GenerateNormalMap(qbyte *pixels, unsigned int *nmap, int w, int h, float scale, float offsetscale)
{
@ -7700,48 +7748,19 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
mips->mip[0].data = rgbadata;
else
{
switch(mips->encoding)
mips->mip[0].data = Image_ResampleTexture(mips->encoding, rgbadata, imgwidth, imgheight, NULL, mips->mip[0].width, mips->mip[0].height);
if (mips->mip[0].data)
{
case PTI_LLLX8:
case PTI_RGBA8:
case PTI_RGBX8:
case PTI_BGRA8:
case PTI_BGRX8:
case PTI_RGBA8_SRGB:
case PTI_RGBX8_SRGB:
case PTI_BGRA8_SRGB:
case PTI_BGRX8_SRGB:
mips->mip[0].data = BZ_Malloc(((mips->mip[0].width+3)&~3)*mips->mip[0].height*4);
//FIXME: should be sRGB-aware, but probably not a common path on hardware that can actually do srgb.
Image_ResampleTexture(rgbadata, imgwidth, imgheight, mips->mip[0].data, mips->mip[0].width, mips->mip[0].height);
if (freedata)
BZ_Free(rgbadata);
freedata = true;
break;
case PTI_L8:
case PTI_L8_SRGB:
mips->mip[0].data = BZ_Malloc(mips->mip[0].width*mips->mip[0].height);
//FIXME: should be sRGB-aware, but probably not a common path on hardware that can actually do srgb.
Image_ResampleTexture8((void*)rgbadata, imgwidth, imgheight, mips->mip[0].data, mips->mip[0].width, mips->mip[0].height);
if (freedata)
BZ_Free(rgbadata);
freedata = true;
break;
case PTI_L8A8:
case PTI_L8A8_SRGB:
mips->mip[0].data = BZ_Malloc(mips->mip[0].width*mips->mip[0].height*2);
//FIXME: should be sRGB-aware, but probably not a common path on hardware that can actually do srgb.
Image_ResampleTexture16((void*)rgbadata, imgwidth, imgheight, mips->mip[0].data, mips->mip[0].width, mips->mip[0].height);
if (freedata)
BZ_Free(rgbadata);
freedata = true;
break;
default: //scaling not supported...
}
else
{ //rescaling unsupported
mips->mip[0].data = rgbadata;
mips->mip[0].width = imgwidth;
mips->mip[0].height = imgheight;
mips->mip[0].depth = 1;
break;
}
}
}
@ -9419,7 +9438,7 @@ int MipColor(int r, int g, int b)
return best;
}
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer, int numbuffers, int bytestride, int width, int height, enum uploadfmt fmt, qboolean writemeta)
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer, int numbuffers, qintptr_t bytestride, int width, int height, enum uploadfmt fmt, qboolean writemeta)
{
char ext[8];
void *nbuffers[2];
@ -9443,7 +9462,7 @@ qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer,
COM_FileExtension(filename, ext, sizeof(ext));
#ifdef AVAIL_PNGLIB
#ifdef AVAIL_PNGLIB
if (!Q_strcasecmp(ext, "png") || !Q_strcasecmp(ext, "pns"))
{
//png can do bgr+rgb
@ -9473,9 +9492,9 @@ qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer,
int y, x, s;
qbyte *src, *dest;
qbyte *srcbuf = buffer[0], *dstbuf;
if (fmt == TF_RGB24 || fmt == TF_RGBA32 || fmt == TF_RGBX32)
if (fmt == TF_RGB24 || fmt == TF_RGBA32 || fmt == TF_RGBX32 || fmt == PTI_LLLA8 || fmt == PTI_LLLX8)
{
dstbuf = malloc(width*height);
dstbuf = malloc((intptr_t)width*height);
s = (fmt == TF_RGB24)?3:4;
// convert in-place to eight bit
for (y = 0; y < height; y++)
@ -9491,7 +9510,7 @@ qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer,
}
else if (fmt == TF_BGR24 || fmt == TF_BGRA32 || fmt == TF_BGRX32)
{
dstbuf = malloc(width*height);
dstbuf = malloc((intptr_t)width*height);
s = (fmt == TF_BGR24)?3:4;
// convert in-place to eight bit
for (y = 0; y < height; y++)

View file

@ -1099,6 +1099,23 @@ void FPS_Preset_f (void)
return;
}
if (!stricmp("qw", arg))
{ //enable qwisms
Cbuf_InsertText(
"set sv_nqplayerphysics 0\n"
"set sv_gameplayfix_multiplethinks 1\n"
, RESTRICT_LOCAL, false);
return;
}
if (!stricmp("nq", arg))
{ //disable qwisms, for better mod compat
Cbuf_InsertText(
"set sv_nqplayerphysics 1\n"
"set sv_gameplayfix_multiplethinks 0\n"
, RESTRICT_LOCAL, false);
return;
}
if (!stricmp("dp", arg))
{
#ifdef HAVE_SERVER
@ -1106,6 +1123,7 @@ void FPS_Preset_f (void)
Cbuf_InsertText("echo Be sure to restart your server\n", RESTRICT_LOCAL, false);
#endif
Cbuf_InsertText(
"fps_preset nq\n"
//these are for smc+derived mods
"sv_listen_dp 1\n" //awkward, but forces the server to load the effectinfo.txt in advance.
"sv_bigcoords 1\n" //for viewmodel lep precision (would be better to use csqc)
@ -1135,6 +1153,7 @@ void FPS_Preset_f (void)
if (!stricmp("tenebrae", arg))
{ //for the luls. combine with the tenebrae mod for maximum effect.
Cbuf_InsertText(
"fps_preset nq\n"
"set r_shadow_realtime_world 1\n"
"set r_shadow_realtime_dlight 1\n"
"set r_shadow_bumpscale_basetexture 4\n"

View file

@ -182,6 +182,8 @@ int MP_TranslateFTEtoQCCodes(int code)
case K_SEARCH: return -code;
default:
if (code == -1) //mod bug
return code;
if (code < 0) //negative values are 'qc-native' keys, for stuff that the api lacks.
return -code;
if (code >= 0 && code < 128) //ascii codes identical
@ -344,7 +346,9 @@ int MP_TranslateQCtoFTECodes(int code)
case 841: return K_JOY_DOWN;
case 842: return K_JOY_LEFT;
case 843: return K_JOY_RIGHT;
default:
default:
if (code == -1) //mod bug
return -1;
if (code < 0) //negative values are 'fte-native' keys, for stuff that the api lacks.
return -code;
if (code >= 0 && code < 128)

View file

@ -843,9 +843,14 @@ void QCBUILTIN PF_CL_drawcharacter (pubprogfuncs_t *prinst, struct globalvars_s
}
//no control chars. use quake ones if so
if (!(flag & 4))
if (chara < 32 && chara != '\t')
chara |= 0xe000;
if (!(flag & 4) && !com_parseutf8.ival)
{
//ugly quake chars...
if (chara >= 32 && chara < 128)
; //ascii-comptaible range
else
chara |= 0xe000; //use quake glyphs (including for red text, unfortunately)
}
r2d_be_flags = PF_SelectDPDrawFlag(prinst, flag);
PR_CL_BeginString(prinst, pos[0], pos[1], size[0], size[1], &x, &y);

View file

@ -3726,9 +3726,9 @@ int Surf_NewLightmaps(int count, int width, int height, uploadfmt_t fmt, qboolea
if (pixw != 1 || pixh != 1)
return -1; //compressed formats are unsupported
dfmt = PTI_BGRX8;
if (!sh_config.texfmt[dfmt])
if (!sh_config.texfmt[dfmt])
dfmt = PTI_RGBX8;
if (!sh_config.texfmt[dfmt])
if (!sh_config.texfmt[dfmt])
dfmt = PTI_RGB8;
Image_BlockSizeForEncoding(dfmt, &dpixbytes, &dpixw, &dpixh);

View file

@ -597,8 +597,7 @@ qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, uploadfmt_
qbyte *ReadJPEGFile(qbyte *infile, int length, int *width, int *height);
qbyte *ReadPNGFile(const char *fname, qbyte *buf, int length, int *width, int *height, uploadfmt_t *format);
qbyte *ReadPCXPalette(qbyte *buf, int len, qbyte *out);
void Image_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight);
void Image_ResampleTexture8 (unsigned char *in, int inwidth, int inheight, unsigned char *out, int outwidth, int outheight);
void *Image_ResampleTexture (uploadfmt_t format, const void *in, int inwidth, int inheight, void *out, int outwidth, int outheight);
void BoostGamma(qbyte *rgba, int width, int height, uploadfmt_t fmt);
void SaturateR8G8B8(qbyte *data, int size, float sat);

View file

@ -231,7 +231,7 @@ typedef enum uploadfmt
#define PTI_EMULATED TF_INVALID:case TF_BGR24_FLIP:case TF_MIP4_P8:case TF_MIP4_SOLID8:case TF_MIP4_8PAL24:case TF_MIP4_8PAL24_T255:case TF_SOLID8:case TF_TRANS8:case TF_TRANS8_FULLBRIGHT:case TF_HEIGHT8:case TF_HEIGHT8PAL:case TF_H2_T7G1:case TF_H2_TRANS8_0:case TF_H2_T4A4:case TF_8PAL24:case TF_8PAL32:case PTI_LLLX8:case PTI_LLLA8
} uploadfmt_t;
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer, int numbuffers, int bytestride, int width, int height, enum uploadfmt fmt, qboolean writemeta);
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void **buffer, int numbuffers, qintptr_t bytestride, int width, int height, enum uploadfmt fmt, qboolean writemeta);
void SCR_DrawTwoDimensional(int uimenu, qboolean nohud);
@ -258,6 +258,7 @@ void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx,
void Font_Transform(float vx, float vy, int *px, int *py);
int Font_CharHeight(void);
float Font_CharVHeight(struct font_s *font);
int Font_CharPHeight(struct font_s *font);
float Font_CharScaleHeight(void);
int Font_CharWidth(unsigned int charflags, unsigned int codepoint);
float Font_CharScaleWidth(unsigned int charflags, unsigned int codepoint);

View file

@ -65,8 +65,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef malloc
int noconinput = 0;
int nostdout = 0;
static int noconinput = 0;
static int nostdout = 0;
int isPlugin;
int sys_parentleft;
@ -78,8 +78,6 @@ qboolean sys_gracefulexit;
qboolean X11_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate);
char *basedir = "./";
qboolean Sys_InitTerminal (void) //we either have one or we don't.
{
return true;
@ -311,9 +309,10 @@ static void Sys_Register_File_Associations_f(void)
//we need to create some .desktop file first, so stuff knows how to start us up.
{
char iconsyspath[MAX_OSPATH];
char *exe = realpath(host_parms.argv[0], NULL);
char *basedir = realpath(com_gamepath, NULL);
char *iconname = fs_manifest->installation;
const char *iconname = fs_manifest->installation;
const char *desktopfile =
"[Desktop Entry]\n"
"Type=Application\n"
@ -329,6 +328,10 @@ static void Sys_Register_File_Associations_f(void)
;
if (!strcmp(iconname, "afterquake") || !strcmp(iconname, "nq")) //hacks so that we don't need to create icons.
iconname = "quake";
if (FS_NativePath("icon.png", FS_GAME, iconsyspath, sizeof(iconsyspath)))
iconname = iconsyspath;
desktopfile = va(desktopfile,
fs_manifest->formalname?fs_manifest->formalname:fs_manifest->installation,
exe, basedir, iconname);

View file

@ -3625,7 +3625,6 @@ static void Sys_MakeInstaller(const char *name)
for (i = 0; i < sizeof(icosizes)/sizeof(icosizes[0]); i++)
{
unsigned int x,y;
unsigned int pixels;
if (icosizes[i].width > imgwidth || icosizes[i].height > imgheight)
continue; //ignore icons if they're bigger than the original icon.
@ -3642,8 +3641,6 @@ static void Sys_MakeInstaller(const char *name)
qbyte *in, *inrow;
unsigned int outidx;
pixels = icosizes[i].width * icosizes[i].height;
bi = data = Z_Malloc(sizeof(*bi) + icosizes[i].width * icosizes[i].height * 5 + icosizes[i].height*4);
memset(bi,0, sizeof(BITMAPINFOHEADER));
bi->bV4Size = sizeof(BITMAPINFOHEADER);
@ -3660,8 +3657,7 @@ static void Sys_MakeInstaller(const char *name)
outmask = (qbyte*)data + datalen;
datalen += ((icosizes[i].width+31)&~31)/8 * icosizes[i].height;
in = malloc(pixels*4);
Image_ResampleTexture((unsigned int*)rgbadata, imgwidth, imgheight, (unsigned int*)in, icosizes[i].width, icosizes[i].height);
in = Image_ResampleTexture(format, rgbadata, imgwidth, imgheight, NULL, icosizes[i].width, icosizes[i].height);
inrow = in;
outidx = 0;
@ -4267,8 +4263,7 @@ void *WIN_CreateCursor(const qbyte *imagedata, int width, int height, uploadfmt_
nh = height * scale;
if (nw <= 0 || nh <= 0 || nw > 128 || nh > 128) //don't go crazy.
return NULL;
nd = BZ_Malloc(nw*nh*4);
Image_ResampleTexture((unsigned int*)imagedata, width, height, (unsigned int*)nd, nw, nh);
nd = Image_ResampleTexture(format, imagedata, width, height, NULL, nw, nh);
width = nw;
height = nh;
imagedata = scaled = nd;

View file

@ -30,7 +30,7 @@ cvar_t allow_f_fakeshaft = CVAR("allow_f_fakeshaft", "1");
cvar_t allow_f_system = CVAR("allow_f_system", "0");
cvar_t allow_f_cmdline = CVAR("allow_f_cmdline", "0");
cvar_t auth_validateclients = CVAR("auth_validateclients", "1");
cvar_t ruleset = CVARC("ruleset", "none", rulesetcallback);
cvar_t ruleset = CVARCD("ruleset", "none", rulesetcallback, "Known rulesets are:\nnone: no explicit rules, all 'minor cheats' are allowed.\nstrict: equivelent to the smackdown ruleset. Note that this will block certain graphical enhancements too.");
#define SECURITY_INIT_BAD_CHECKSUM 1
@ -369,7 +369,7 @@ typedef struct {
qboolean flagged;
} ruleset_t;
rulesetrule_t rulesetrules_strict[] = {
static rulesetrule_t rulesetrules_strict[] = {
{"ruleset_allow_shaders", "0"}, /*users can potentially create all sorts of wallhacks or spiked models with this*/
{"ruleset_allow_watervis", "0"}, /*oh noes! users might be able to see underwater if they're already in said water. oh wait. what? why do we care, dude*/
{"r_vertexlight", "0"},
@ -395,7 +395,7 @@ rulesetrule_t rulesetrules_strict[] = {
{NULL}
};
rulesetrule_t rulesetrules_nqr[] = {
static rulesetrule_t rulesetrules_nqr[] = {
{"ruleset_allow_larger_models", "0"},
{"ruleset_allow_watervis", "0"}, /*block seeing through turbs, as well as all our cool graphics stuff. apparently we're not allowed.*/
{"ruleset_allow_overlong_sounds", "0"},
@ -438,7 +438,7 @@ void Validation_DelatchRulesets(void)
Con_DPrintf("Ruleset deactivated\n");
}
qboolean Validation_GetCurrentRulesetName(char *rsnames, int resultbuflen, qboolean enforcechosenrulesets)
static qboolean Validation_GetCurrentRulesetName(char *rsnames, int resultbuflen, qboolean enforcechosenrulesets)
{ //this code is more complex than it needs to be
//this allows for the ruleset code to print a ruleset name that is applied via the cvars, but not directly named by the user
cvar_t *var;
@ -501,7 +501,7 @@ qboolean Validation_GetCurrentRulesetName(char *rsnames, int resultbuflen, qbool
return false;
}
void Validation_OldRuleset(void)
static void Validation_OldRuleset(void)
{
char rsnames[1024];
@ -511,7 +511,7 @@ void Validation_OldRuleset(void)
Cbuf_AddText("say No specific ruleset\n", RESTRICT_LOCAL);
}
void Validation_AllChecks(void)
static void Validation_AllChecks(void)
{
char servername[22];
char playername[16];

View file

@ -3616,10 +3616,22 @@ static void Cmd_toggle_f(void)
if (!v)
return;
if (v->value)
Cvar_Set(v, "0");
if (Cmd_Argc() >= 3)
{
const char *newval = Cmd_Argv(2);
const char *defval = (Cmd_Argc()>3)?Cmd_Argv(3):v->defaultstr;
if (!strcmp(newval, v->string))
Cvar_Set(v, defval);
else
Cvar_Set(v, newval);
}
else
Cvar_Set(v, "1");
{
if (v->value)
Cvar_Set(v, "0");
else
Cvar_Set(v, "1");
}
}
static void Cmd_Set_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx)
@ -4220,7 +4232,7 @@ void Cmd_Init (void)
// Cmd_AddCommand ("msg_trigger", Cmd_Msg_Trigger_f);
// Cmd_AddCommand ("filter", Cmd_Msg_Filter_f);
Cmd_AddCommand ("toggle", Cmd_toggle_f);
Cmd_AddCommandAD ("toggle", Cmd_toggle_f, Cmd_Set_c, "Toggles a cvar between two values\ntoggle CVARNAME [newval [altval]]");
Cmd_AddCommandAD ("set", Cmd_set_f, Cmd_Set_c, "Changes the current value of the named cvar, creating it if it doesn't yet exist.");
Cmd_AddCommandAD ("setfl", Cmd_set_f, Cmd_Set_c, "Changes the current value of the named cvar, creating it if it doesn't yet exist. The third arg allows setting cvar flags and should be u, s, or a. This command should normally be used only inside default.cfg.");
Cmd_AddCommandAD ("set_calc", Cmd_set_f, Cmd_Set_c, "Sets the named cvar to the result of a (complex) expression.");

View file

@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <ctype.h>
#include <errno.h>
qboolean sys_nounload;
#ifndef HAVE_CLIENT
double host_frametime;
double realtime; // without any filtering or bounding
@ -5824,6 +5825,9 @@ void COM_Init (void)
LittleFloat = FloatSwap;
}
//random should be random from the start...
srand(time(0));
#ifdef MULTITHREAD
Sys_ThreadsInit();
#endif

View file

@ -5800,15 +5800,17 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
if (allowreloadconfigs)
{
for (i = 0; i < countof(conffile); i++)
{
FS_FLocateFile(conffile[i], FSLF_IFFOUND|FSLF_IGNOREPURE, &loc);
if (confpath[i] != (loc.search?loc.search->handle:NULL))
if (!reloadconfigs)
for (i = 0; i < countof(conffile); i++)
{
reloadconfigs = true;
Con_DPrintf("Reloading configs because %s has changed\n", conffile[i]);
FS_FLocateFile(conffile[i], FSLF_IFFOUND|FSLF_IGNOREPURE, &loc);
if (confpath[i] != (loc.search?loc.search->handle:NULL))
{
reloadconfigs = true;
Con_DPrintf("Reloading configs because %s has changed\n", conffile[i]);
break;
}
}
}
if (reloadconfigs)
{

View file

@ -12,10 +12,10 @@ cvar_t log_enable[LOG_TYPES] = { CVARF("log_enable", "0", CVAR_NOTFROMSERVER),
CVARF("log_enable_players", "0", CVAR_NOTFROMSERVER),
CVARF("log_enable_rcon", "1", CVAR_NOTFROMSERVER)
};
cvar_t log_name[LOG_TYPES] = { CVARFC("log_name", "", CVAR_NOTFROMSERVER, Log_Name_Callback),
cvar_t log_name[LOG_TYPES] = { CVARFC("log_name", "qconsole", CVAR_NOTFROMSERVER, Log_Name_Callback),
CVARFC("log_name_players", "players", CVAR_NOTFROMSERVER, Log_Name_Callback),
CVARFC("log_name_rcon", "rcon", CVAR_NOTFROMSERVER, Log_Name_Callback)};
cvar_t log_dir_var = CVARFC("log_dir", "", CVAR_NOTFROMSERVER, Log_Dir_Callback);
cvar_t log_dir_var = CVARAFC("log_dir", "", "sv_logdir", CVAR_NOTFROMSERVER, Log_Dir_Callback);
cvar_t log_readable = CVARFD("log_readable", "7", CVAR_NOTFROMSERVER, "Bitfield describing what to convert/strip. If 0, exact byte representation will be used.\n&1: Dequakify text.\n&2: Strip special markup.\n&4: Strip ansi control codes.");
cvar_t log_developer = CVARFD("log_developer", "0", CVAR_NOTFROMSERVER, "Enables logging of console prints when set to 1. Otherwise unimportant messages will not fill up your log files.");
cvar_t log_rotate_files = CVARF("log_rotate_files", "0", CVAR_NOTFROMSERVER);
@ -47,7 +47,7 @@ static void QDECL Log_Dir_Callback (struct cvar_s *var, char *oldvalue)
{
Con_Printf(CON_NOTICE "%s forced to default due to invalid characters.\n", var->name);
// recursion is avoided by assuming the default value is sane
Cvar_ForceSet(var, var->defaultstr);
Cvar_ForceSet(var, var->enginevalue);
}
if (!strncmp(var->string, "./", 2)||!strncmp(var->string, ".\\", 2))
@ -72,7 +72,7 @@ static void QDECL Log_Name_Callback (struct cvar_s *var, char *oldvalue)
{
Con_Printf(CON_NOTICE "%s forced to default due to invalid characters.\n", var->name);
// recursion is avoided by assuming the default value is sane
Cvar_ForceSet(var, var->defaultstr);
Cvar_ForceSet(var, var->enginevalue);
}
}
@ -89,27 +89,13 @@ void Log_String (logtype_t lognum, const char *s)
conchar_t cline[2048], *c;
unsigned int u, flags;
f = NULL;
switch(lognum)
{
case LOG_CONSOLE:
f = "qconsole";
break;
case LOG_PLAYER:
f = "players";
break;
case LOG_RCON:
f = "rcon";
break;
default:
return;
}
if (!log_enable[lognum].value)
return;
if (log_name[lognum].string[0])
f = log_name[lognum].string;
else
f = log_name[lognum].enginevalue;
if (!f)
return;
@ -268,24 +254,39 @@ void SV_LogPlayer(client_t *cl, char *msg)
#endif
#ifdef HAVE_LEGACY
static struct {
const char *commandname;
const char *desc;
} legacylog[] =
{
{"logfile", ""},
{"logplayers", " players"},
{"logrcon", " frags"},
};
void Log_Logfile_f (void)
{
if (log_enable[LOG_CONSOLE].value)
size_t logtype;
const char *cmd = Cmd_Argv(0);
for (logtype = 0; logtype < countof(legacylog); logtype++)
if (!Q_strcasecmp(legacylog[logtype].commandname, cmd))
break;
if (log_enable[logtype].value)
{
Cvar_SetValue(&log_enable[LOG_CONSOLE], 0);
Con_Printf("Logging disabled.\n");
Cvar_SetValue(&log_enable[logtype], 0);
Con_Printf("Logging%s disabled.\n", legacylog[logtype].desc);
}
else
{
char *f;
const char *f;
char syspath[MAX_OSPATH];
f = "qconsole";
if (log_name[LOG_CONSOLE].string[0])
f = log_name[LOG_CONSOLE].string;
if (log_name[logtype].string[0])
f = log_name[logtype].string;
else
f = log_name[logtype].enginevalue;
if (*log_dir)
f = va("%s/%s.log", log_dir, f);
@ -293,10 +294,10 @@ void Log_Logfile_f (void)
f = va("%s.log", f);
if (FS_NativePath(f, log_root, syspath, sizeof(syspath)))
Con_Printf("%s", va("Logging to %s\n", syspath));
Con_Printf("%s", va("Logging%s to %s\n", legacylog[logtype].desc, syspath));
else
Con_Printf("%s", va("Logging to %s\n", f));
Cvar_SetValue(&log_enable[LOG_CONSOLE], 1);
Con_Printf("%s", va("Logging%s to %s\n", legacylog[logtype].desc, f));
Cvar_SetValue(&log_enable[logtype], 1);
}
}
@ -338,6 +339,7 @@ void SV_Fraglogfile_f (void)
Con_TPrintf ("Logging frags to %s.\n", name);
}
*/
#endif
#ifdef IPLOG
/*for fuck sake, why can people still not write simple files. proquake is writing binary files as text ones. this function is to try to deal with that fuckup*/
@ -626,7 +628,7 @@ static void IPLog_Merge_f(void)
{
const char *fname = Cmd_Argv(1);
if (!IPLog_Merge_File(fname))
Con_Printf("unable to read %s\n", fname);
Con_Printf("unable to read iplog \"%s\" for merging\n", fname);
}
#endif
@ -975,9 +977,16 @@ void Log_Init(void)
// register cvars
for (i = 0; i < LOG_TYPES; i++)
{
#ifdef CLIENTONLY
if (i != LOG_CONSOLE)
continue;
#endif
Cvar_Register (&log_enable[i], CONLOGGROUP);
Cvar_Register (&log_name[i], CONLOGGROUP);
log_newline[i] = true;
#ifdef HAVE_LEGACY
Cmd_AddCommand(legacylog[i].commandname, IPLog_Merge_f);
#endif
}
Cvar_Register (&log_dir_var, CONLOGGROUP);
Cvar_Register (&log_readable, CONLOGGROUP);
@ -987,8 +996,6 @@ void Log_Init(void)
Cvar_Register (&log_dosformat, CONLOGGROUP);
Cvar_Register (&log_timestamps, CONLOGGROUP);
Cmd_AddCommand("logfile", Log_Logfile_f);
#ifdef IPLOG
Cmd_AddCommandD("identify", IPLog_Identify_f, "Looks up a player's ip to see if they're using a different name");
Cmd_AddCommand("ipmerge", IPLog_Merge_f);

View file

@ -586,7 +586,6 @@ qboolean NET_AddressSmellsFunny(netadr_t *a)
}
}
/*
static void NET_AdrToStringDoResolve(void *ctx, void *data, size_t a, size_t b)
{
netadr_t *n = data;
@ -615,7 +614,6 @@ void NET_AdrToStringResolve (netadr_t *adr, void (*resolved)(void *ctx, void *da
*(void**)(n+1) = resolved;
COM_AddWork(WG_LOADER, NET_AdrToStringDoResolve, ctx, n, a, b);
}
*/
char *NET_AdrToString (char *s, int len, netadr_t *a)
{

View file

@ -555,7 +555,7 @@ void QCBUILTIN PF_ExecuteCommand (pubprogfuncs_t *prinst, struct globalvars_s *
void QCBUILTIN PF_setspawnparms (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_precache_vwep_model(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
int PF_checkclient_Internal (pubprogfuncs_t *prinst);
int PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s);
int PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s, qboolean queryonly);
int PF_precache_model_Internal (pubprogfuncs_t *prinst, const char *s, qboolean queryonly);
void PF_setmodel_Internal (pubprogfuncs_t *prinst, edict_t *e, const char *m);
char *PF_infokey_Internal (int entnum, const char *value);

View file

@ -1361,6 +1361,7 @@ typedef struct q1usercmd_s
#define RDF_RENDERSCALE (1u<<21)
#define RDF_SCENEGAMMA (1u<<22)
#define RDF_DISABLEPARTICLES (1u<<23) //mostly for skyrooms
#define RDF_SKIPSKY (1u<<24) //we have a skyroom, skip drawing sky chains for this scene.
#define RDF_ALLPOSTPROC (RDF_BLOOM|RDF_FISHEYE|RDF_WATERWARP|RDF_CUSTOMPOSTPROC|RDF_ANTIALIAS|RDF_SCENEGAMMA) //these flags require rendering to an fbo for the various different post-processing shaders.

View file

@ -105,21 +105,8 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
if (binroot)
{
//load eg: basedir/module_gamedir_arch.ext
Con_DPrintf("Attempting to load native library: %s\n", name);
#ifdef ANDROID
if (!hVM && FS_NativePath(dllname_anycpu, FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
#else
if (!hVM && FS_NativePath(dllname_archpri, FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(dllname_anycpu, FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(dllname_archpri, FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(dllname_anycpu, FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
#endif
// run through the search paths
iterator = NULL;
@ -151,9 +138,25 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
hVM = Sys_LoadLibrary(fname, funcs);
}
}
#ifdef ANDROID
if (!hVM && FS_NativePath(dllname_anycpu, FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
#else
if (!hVM && FS_NativePath(dllname_archpri, FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(dllname_anycpu, FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(dllname_archpri, FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(dllname_anycpu, FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs);
#endif
}
else
{
//load eg: basedir/gamedir/module_arch.ext
Con_DPrintf("Attempting to load (unsafe) native library: %s\n", name);
// run through the search paths

View file

@ -58,6 +58,7 @@ typedef struct {
char *name;
} dllfunction_t;
typedef void dllhandle_t; //typically used as void*
extern qboolean sys_nounload; //blocks Sys_CloseLibrary. set before stack trace fatal shutdowns.
dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs);
void Sys_CloseLibrary(dllhandle_t *lib);
void *Sys_GetAddressForName(dllhandle_t *module, const char *exportname);

View file

@ -1696,7 +1696,7 @@ void GLBE_Init(void)
//end tables
#define MAX_ARRAY_VERTS 65535
#define MAX_ARRAY_VERTS 65536
static vecV_t vertexarray[MAX_ARRAY_VERTS];
#if 1//ndef GLSLONLY
static avec4_t coloursarray[MAX_ARRAY_VERTS];
@ -5220,7 +5220,7 @@ static qboolean GLBE_GenerateBatchTextures(batch_t *batch, shader_t *bs)
int oldfbo;
float oldil;
int oldbem;
if (r_refdef.recurse == r_portalrecursion.ival || r_refdef.recurse == R_MAX_RECURSE)
if (r_refdef.recurse >= r_portalrecursion.ival || r_refdef.recurse == R_MAX_RECURSE)
return false;
//these flags require rendering some view as an fbo
//(BEM_DEPTHDARK is used when lightmap scale is 0, but still shows any emissive stuff)
@ -6211,6 +6211,8 @@ void GLBE_DrawLightPrePass(void)
qglClearColor (1,0,0,1);
}
qboolean R_DrawSkyroom(shader_t *skyshader);
void GLBE_DrawWorld (batch_t **worldbatches)
{
#ifdef RTLIGHTS
@ -6268,6 +6270,21 @@ void GLBE_DrawWorld (batch_t **worldbatches)
BE_UpdateLightmaps();
if (worldbatches)
{
if (worldbatches[SHADER_SORT_SKY] && r_refdef.skyroom_enabled)
{
batch_t *b;
for (b = worldbatches[SHADER_SORT_SKY]; b; b = b->next)
if (R_DrawSkyroom(b->shader))
{
GL_CullFace(0);//make sure flipcull reversion takes effect
currententity = NULL;
GLBE_SelectEntity(&r_worldentity);
GL_ForceDepthWritable();
qglClear(GL_DEPTH_BUFFER_BIT);
r_refdef.flags |= RDF_SKIPSKY;
break;
}
}
if (gl_overbright.modified)
{
int i;

View file

@ -1130,13 +1130,13 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx)
else if (bm->pixel_mode == FT_PIXEL_MODE_BGRA)
{
unsigned int *out = alloca(nw*nh*sizeof(*out));
Image_ResampleTexture((void*)bm->buffer, bm->width, bm->rows, out, nw, nh);
Image_ResampleTexture(PTI_BGRA8, (void*)bm->buffer, bm->width, bm->rows, out, nw, nh);
c = Font_LoadGlyphData(f, charidx, bm->pixel_mode, out, nw, nh, nw*sizeof(*out));
}
else if (bm->pixel_mode == FT_PIXEL_MODE_GRAY)
{
unsigned char *out = alloca(nw*nh*sizeof(*out));
Image_ResampleTexture8((void*)bm->buffer, bm->width, bm->rows, out, nw, nh);
Image_ResampleTexture(PTI_L8, (void*)bm->buffer, bm->width, bm->rows, out, nw, nh);
c = Font_LoadGlyphData(f, charidx, bm->pixel_mode, out, nw, nh, nw*sizeof(*out));
}
else
@ -1204,7 +1204,7 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx)
int ngh = f->charheight;
qbyte *out2 = alloca(ngw*ngh*4);
if (ngw&&ngh)
Image_ResampleTexture((unsigned int *)out, gw, gh, (unsigned int *)out2, ngw, ngh);
Image_ResampleTexture(PTI_RGBA8, out, gw, gh, out2, ngw, ngh);
c = Font_LoadGlyphData(f, charidx, FT_PIXEL_MODE_RGBA, out2, ngw, ngh, ngw*4);
gw = ngw;
}
@ -1263,7 +1263,7 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx)
for (y = 0; y < gh; y++)
for (x = 0; x < gw; x++)
out1[x+y*gw] = out[x+y*gs];
Image_ResampleTexture((unsigned int *)out1, gw, gh, (unsigned int *)out2, ngw, ngh);
Image_ResampleTexture(PTI_RGBA8, out1, gw, gh, out2, ngw, ngh);
}
c = Font_LoadGlyphData(f, charidx, FT_PIXEL_MODE_RGBA, out2, ngw, ngh, ngw*4);
gw = ngw;
@ -2404,6 +2404,10 @@ int Font_CharHeight(void)
{
return curfont->charheight;
}
int Font_CharPHeight(struct font_s *font)
{
return font->charheight;
}
float Font_CharVHeight(struct font_s *font)
{
return ((float)font->charheight * vid.height)/vid.rotpixelheight;

View file

@ -68,6 +68,11 @@ qboolean GLSCR_UpdateScreen (void)
vid.numpages = 2 + vid_triplebuffer.value;
if (!scr_initialized || !con_initialized)
{
return false; // not initialized yet
}
R2D_Font_Changed();
if (vid_srgb.modified)
@ -95,11 +100,6 @@ qboolean GLSCR_UpdateScreen (void)
}
}
if (!scr_initialized || !con_initialized)
{
return false; // not initialized yet
}
if (scr_disabled_for_loading)
{
extern float scr_disabled_time;
@ -138,19 +138,16 @@ qboolean GLSCR_UpdateScreen (void)
{
Editor_Draw();
V_UpdatePalette (false);
Media_RecordFrame();
R2D_BrightenScreen();
Media_RecordFrame();
if (key_dest_mask & kdm_console)
Con_DrawConsole(vid.height/2, false);
else
Con_DrawConsole(0, false);
SCR_DrawCursor();
if (R2D_Flush)
R2D_Flush();
VID_SwapBuffers();
return true;
}
else
#endif
if (Media_ShowFilm())
{
@ -158,76 +155,71 @@ qboolean GLSCR_UpdateScreen (void)
V_UpdatePalette (false);
R2D_BrightenScreen();
Media_RecordFrame();
if (R2D_Flush)
R2D_Flush();
GL_Set2D (false);
VID_SwapBuffers();
return true;
}
//
// do 3D refresh drawing, and then update the screen
//
SCR_SetUpToDrawConsole ();
noworld = false;
nohud = false;
if (r_clear.ival)
else
{
GL_ForceDepthWritable();
qglClearColor((r_clear.ival&1)?1:0, (r_clear.ival&2)?1:0, (r_clear.ival&4)?1:0, 1);
qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
depthcleared = true;
}
//
// do 3D refresh drawing, and then update the screen
//
SCR_SetUpToDrawConsole ();
noworld = false;
nohud = false;
if (r_clear.ival)
{
GL_ForceDepthWritable();
qglClearColor((r_clear.ival&1)?1:0, (r_clear.ival&2)?1:0, (r_clear.ival&4)?1:0, 1);
qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
depthcleared = true;
}
#ifdef VM_CG
if (CG_Refresh())
nohud = true;
else
if (CG_Refresh())
nohud = true;
else
#endif
#ifdef CSQC_DAT
if (CSQC_DrawView())
nohud = true;
else
if (CSQC_DrawView())
nohud = true;
else
#endif
{
if (uimenu != 1)
{
if (r_worldentity.model && cls.state == ca_active)
V_RenderView (nohud);
else
if (uimenu != 1)
{
noworld = true;
if (r_worldentity.model && cls.state == ca_active)
V_RenderView (nohud);
else
{
noworld = true;
}
}
}
GL_Set2D (false);
scr_con_forcedraw = false;
if (noworld)
{
//draw the levelshot or the conback fullscreen
if (R2D_DrawLevelshot())
;
else if (scr_con_current != vid.height)
R2D_ConsoleBackground(0, vid.height, true);
else
scr_con_forcedraw = true;
nohud = true;
}
SCR_DrawTwoDimensional(uimenu, nohud);
V_UpdatePalette (false);
R2D_BrightenScreen();
Media_RecordFrame();
}
GL_Set2D (false);
scr_con_forcedraw = false;
if (noworld)
{
//draw the levelshot or the conback fullscreen
if (R2D_DrawLevelshot())
;
else if (scr_con_current != vid.height)
R2D_ConsoleBackground(0, vid.height, true);
else
scr_con_forcedraw = true;
nohud = true;
}
SCR_DrawTwoDimensional(uimenu, nohud);
V_UpdatePalette (false);
R2D_BrightenScreen();
Media_RecordFrame();
RSpeedShow();
if (R2D_Flush)
R2D_Flush();

View file

@ -1444,7 +1444,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
for(;;)
{
size_t len;
int i;
int i, j;
char *type, *idx, *next;
char *token = com_token;
@ -1487,6 +1487,15 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
if (prog->numsamplers < i+1)
prog->numsamplers = i+1;
/*for (j = 0; sh_defaultsamplers[j].name; j++)
{
if (!strcmp(token, sh_defaultsamplers[j].name+2))
{
Con_Printf("%s: %s is an internal texture name\n", name, token);
break;
}
}*/
//I really want to use layout(binding = %i) here, but its specific to the glsl version (which we don't really know yet)
Q_strlcatfz(prescript, &offset, sizeof(prescript), "#define s_%s s_t%u\nuniform %s%s s_%s;\n", token, i, strncmp(type, "sampler", 7)?"sampler":"", type, token);
}
@ -3947,13 +3956,15 @@ qboolean Shader_Init (void)
}
}
memset(wibuf, 0xff, sizeof(wibuf));
if (!qrenderer)
r_whiteimage = r_nulltex;
else
{
memset(wibuf, 0xff, sizeof(wibuf));
r_whiteimage = R_LoadTexture("$whiteimage", 4, 4, TF_RGBA32, wibuf, IF_NOMIPMAP|IF_NOPICMIP|IF_NEAREST|IF_NOGAMMA);
memset(wibuf, 0, sizeof(wibuf));
r_blackimage = R_LoadTexture("$blackimage", 4, 4, TF_RGBA32, wibuf, IF_NOMIPMAP|IF_NOPICMIP|IF_NEAREST|IF_NOGAMMA);
memset(wibuf, 0, sizeof(wibuf));
r_blackimage = R_LoadTexture("$blackimage", 4, 4, TF_RGBA32, wibuf, IF_NOMIPMAP|IF_NOPICMIP|IF_NEAREST|IF_NOGAMMA);
}
Shader_NeedReload(true);
Shader_DoReload();

View file

@ -3689,7 +3689,7 @@ void Sh_CheckSettings(void)
#ifdef VKQUAKE
case QR_VULKAN:
canshadowless = true;
cansmap = true;
cansmap = vk.multisamplebits==VK_SAMPLE_COUNT_1_BIT; //FIXME - we need to render shadowmaps without needing to restart the current scene.
canstencil = false;
break;
#endif

View file

@ -2,6 +2,17 @@
#if defined(GLQUAKE) && defined(USE_EGL)
#include "gl_videgl.h"
//EGL_KHR_gl_colorspace
#ifndef EGL_GL_COLORSPACE_KHR
#define EGL_GL_COLORSPACE_KHR 0x309D
#endif
#ifndef EGL_GL_COLORSPACE_SRGB_KHR
#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
#endif
#ifndef EGL_GL_COLORSPACE_LINEAR_KHR
#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A
#endif
extern cvar_t vid_vsync;
EGLContext eglctx = EGL_NO_CONTEXT;
@ -13,15 +24,16 @@ static dllhandle_t *eslibrary;
static EGLint (EGLAPIENTRY *qeglGetError)(void);
static EGLDisplay (EGLAPIENTRY *qeglGetPlatformDisplay)(EGLenum platform, void *native_display, const EGLint *attrib_list);
static EGLDisplay (EGLAPIENTRY *qeglGetPlatformDisplay)(EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
static EGLDisplay (EGLAPIENTRY *qeglGetDisplay)(EGLNativeDisplayType display_id);
static EGLBoolean (EGLAPIENTRY *qeglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor);
static EGLBoolean (EGLAPIENTRY *qeglTerminate)(EGLDisplay dpy);
static EGLBoolean (EGLAPIENTRY *qeglGetConfigs)(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
static EGLBoolean (EGLAPIENTRY *qeglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
EGLBoolean (EGLAPIENTRY *qeglGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
static EGLSurface (EGLAPIENTRY *qeglCreatePlatformWindowSurface)(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
static EGLSurface (EGLAPIENTRY *qeglCreatePlatformWindowSurface)(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
static EGLSurface (EGLAPIENTRY *qeglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
static EGLBoolean (EGLAPIENTRY *qeglDestroySurface)(EGLDisplay dpy, EGLSurface surface);
static EGLBoolean (EGLAPIENTRY *qeglQuerySurface)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
@ -44,6 +56,7 @@ static dllfunction_t qeglfuncs[] =
{(void*)&qeglGetConfigs, "eglGetConfigs"},
{(void*)&qeglChooseConfig, "eglChooseConfig"},
{(void*)&qeglGetConfigAttrib, "eglGetConfigAttrib"},
{(void*)&qeglCreateWindowSurface, "eglCreateWindowSurface"},
{(void*)&qeglDestroySurface, "eglDestroySurface"},
@ -156,7 +169,7 @@ qboolean EGL_LoadLibrary(char *driver)
#endif
if (!eslibrary)
Sys_Printf("unable to load some libGL\n");
Sys_Printf("Attempting to dlopen libEGL... ");
egllibrary = Sys_LoadLibrary("libEGL", qeglfuncs);
if (!egllibrary)
@ -243,10 +256,10 @@ void EGL_Shutdown(void)
for (i = 0; i < countof(eglattrs); i++)
{
if (qeglGetContifAttrib(egldpy, cfg, eglattrs[i].attr, &val))
Con_DPrintf("%i.%s: %i\n", cfg, eglattrs[i].attrname, val);
if (qeglGetConfigAttrib(egldpy, cfg, eglattrs[i].attr, &val))
Con_DPrintf("%p.%s: %i\n", cfg, eglattrs[i].attrname, val);
else
Con_DPrintf("%i.%s: UNKNOWN\n", cfg, eglattrs[i].attrname);
Con_DPrintf("%p.%s: UNKNOWN\n", cfg, eglattrs[i].attrname);
}
}*/
@ -273,15 +286,15 @@ void EGL_SwapBuffers (void)
qeglSwapBuffers(egldpy, eglsurf);
/* TODO: check result? */
TRACE(("EGL_SwapBuffers done\n"));
Con_Printf("EGL_SwapBuffers\n");
}
qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, int eglplat, void *nwindow, void *ndpy, EGLNativeWindowType windowid, EGLNativeDisplayType dpyid)
qboolean EGL_InitDisplay (rendererstate_t *info, int eglplat, void *ndpy, EGLNativeDisplayType dpyid, EGLConfig *outconfig)
{
EGLint numconfig;
EGLConfig cfg;
EGLint major, minor;
EGLint numconfig=0;
EGLConfig cfg=0;
EGLint major=0, minor=0;
EGLint attrib[] =
{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
@ -296,17 +309,6 @@ qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, int eglplat, v
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
EGLint wndattrib[] =
{
// EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_LINEAR_KHR,
EGL_NONE
};
EGLint contextattr[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2, //requires EGL 1.3
EGL_NONE, EGL_NONE
};
/* if (!EGL_LoadLibrary(""))
{
@ -354,7 +356,6 @@ qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, int eglplat, v
Con_Printf(CON_ERROR "EGL: can't choose config!\n");
return false;
}
if (!numconfig)
{
Con_Printf(CON_ERROR "EGL: no configs!\n");
@ -362,11 +363,38 @@ qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, int eglplat, v
}
// EGL_ShowConfig(egldpy, cfg);
*outconfig = cfg;
return true;
}
qboolean EGL_InitWindow (rendererstate_t *info, int eglplat, void *nwindow, EGLNativeWindowType windowid, EGLConfig cfg)
{
EGLint contextattr[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2, //requires EGL 1.3
EGL_NONE, EGL_NONE
};
if (qeglCreatePlatformWindowSurface)
{
EGLAttrib wndattrib[] =
{
// EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR,
EGL_NONE
};
eglsurf = qeglCreatePlatformWindowSurface(egldpy, cfg, nwindow, info->srgb?wndattrib:NULL);
}
else
{
EGLint wndattrib[] =
{
// EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR,
EGL_NONE
};
eglsurf = qeglCreateWindowSurface(egldpy, cfg, windowid, info->srgb?wndattrib:NULL);
}
if (eglsurf == EGL_NO_SURFACE)
{
int err = qeglGetError();
@ -376,7 +404,7 @@ qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, int eglplat, v
Con_Printf(CON_ERROR "EGL: eglCreateWindowSurface failed: %s\n", EGL_GetErrorString(err));
return false;
}
eglctx = qeglCreateContext(egldpy, cfg, EGL_NO_SURFACE, contextattr);
if (eglctx == EGL_NO_CONTEXT)
{
@ -389,7 +417,7 @@ qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, int eglplat, v
Con_Printf(CON_ERROR "EGL: can't make current!\n");
return false;
}
if (eglplat == EGL_PLATFORM_WAYLAND_KHR)
{ //if we don't do this, only the first frame will get displayed, and we'll lock up
qeglSwapInterval = NULL;
@ -400,5 +428,6 @@ qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, int eglplat, v
return true;
}
#endif

View file

@ -26,6 +26,13 @@ void EGL_UnloadLibrary(void);
qboolean EGL_LoadLibrary(char *driver);
void EGL_Shutdown(void);
void EGL_SwapBuffers (void);
qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, int eglplatform, void *nwindow, void *ndpy, EGLNativeWindowType owindow, EGLNativeDisplayType odpy);
qboolean EGL_InitDisplay (rendererstate_t *info, int eglplat, void *ndpy, EGLNativeDisplayType dpyid, EGLConfig *outconfig);
qboolean EGL_InitWindow (rendererstate_t *info, int eglplat, void *nwindow, EGLNativeWindowType windowid, EGLConfig cfg);
//qboolean EGL_Init (rendererstate_t *info, unsigned char *palette, int eglplatform, void *nwindow, void *ndpy, EGLNativeWindowType owindow, EGLNativeDisplayType odpy);
//once you've created an egl display and got an egl config, some windowing systems require querying said egl config to create the window properly.
extern EGLDisplay egldpy;
extern EGLBoolean (EGLAPIENTRY *qeglGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
#endif

View file

@ -199,6 +199,8 @@ static struct
int (*pXUngrabPointer)(Display *display, Time time);
int (*pXWarpPointer)(Display *display, Window src_w, Window dest_w, int src_x, int src_y, unsigned int src_width, unsigned int src_height, int dest_x, int dest_y);
Status (*pXMatchVisualInfo)(Display *display, int screen, int depth, int class, XVisualInfo *vinfo_return);
XVisualInfo *(*pXGetVisualInfo)(Display *display, long vinfo_mask, XVisualInfo *vinfo_template, int *nitems_return);
qXErrorHandler (*pXSetErrorHandler)(XErrorHandler);
@ -295,6 +297,7 @@ static qboolean x11_initlib(void)
{(void**)&x11.pXUngrabPointer, "XUngrabPointer"},
{(void**)&x11.pXWarpPointer, "XWarpPointer"},
{(void**)&x11.pXMatchVisualInfo, "XMatchVisualInfo"},
{(void**)&x11.pXGetVisualInfo, "XGetVisualInfo"},
{NULL, NULL}
};
@ -3156,6 +3159,7 @@ static void GLVID_Shutdown(void)
#ifdef USE_EGL
case PSL_EGL:
EGL_Shutdown();
EGL_UnloadLibrary();
GL_ForgetPointers();
break;
#endif
@ -3244,7 +3248,7 @@ static struct
Cursor (*ImageLoadCursor) (Display *dpy, const XcursorImage *image);
void (*ImageDestroy) (XcursorImage *image);
} xcursor;
static void *X11VID_CreateCursorRGBA(const qbyte *rgbacursor, size_t w, size_t h, float hotx, float hoty)
static void *X11VID_CreateCursorRGBA(const qbyte *rgbacursor, uploadfmt_t format, size_t w, size_t h, float hotx, float hoty)
{
Cursor *cursor;
size_t x, y;
@ -3256,9 +3260,27 @@ static void *X11VID_CreateCursorRGBA(const qbyte *rgbacursor, size_t w, size_t h
img->yhot = hoty;
dest = img->pixels;
for (y = 0; y < h; y++)
for (x = 0; x < w; x++, rgbacursor+=4)
*dest++ = (rgbacursor[3]<<24)|(rgbacursor[0]<<16)|(rgbacursor[1]<<8)|(rgbacursor[2]<<0); //0xARGB
switch (format)
{
case PTI_BGRA8:
case PTI_BGRX8:
for (y = 0; y < h; y++)
for (x = 0; x < w; x++, rgbacursor+=4)
*dest++ = (rgbacursor[3]<<24)|(rgbacursor[2]<<16)|(rgbacursor[1]<<8)|(rgbacursor[0]<<0); //0xARGB
break; //supported...
case PTI_RGBA8:
case PTI_RGBX8:
case PTI_LLLA8:
case PTI_LLLX8:
for (y = 0; y < h; y++)
for (x = 0; x < w; x++, rgbacursor+=4)
*dest++ = (rgbacursor[3]<<24)|(rgbacursor[0]<<16)|(rgbacursor[1]<<8)|(rgbacursor[2]<<0); //0xARGB
break;
default:
//panic... format wasn't supported. I hope we didn't spend ages resampling it...
xcursor.ImageDestroy(img);
return NULL;
}
cursor = Z_Malloc(sizeof(*cursor));
*cursor = xcursor.ImageLoadCursor(vid_dpy, img);
@ -3282,15 +3304,16 @@ static void *X11VID_CreateCursor(const qbyte *imagedata, int width, int height,
nh = height * scale;
if (nw <= 0 || nh <= 0 || nw > 128 || nh > 128) //don't go crazy.
return NULL;
nd = BZ_Malloc(nw*nh*4);
Image_ResampleTexture((unsigned int*)imagedata, width, height, (unsigned int*)nd, nw, nh);
nd = Image_ResampleTexture(format, imagedata, width, height, NULL, nw, nh);
if (!nd)
return NULL; //resampling of that format didn't work for some reason...
width = nw;
height = nh;
r = X11VID_CreateCursorRGBA(nd, width, height, hotx, hoty);
r = X11VID_CreateCursorRGBA(nd, format, width, height, hotx, hoty);
BZ_Free(nd);
}
else
r = X11VID_CreateCursorRGBA(imagedata, width, height, hotx, hoty);
r = X11VID_CreateCursorRGBA(imagedata, format, width, height, hotx, hoty);
return r;
}
@ -3777,6 +3800,9 @@ static qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int
int width = info->width; //can override these if vmode isn't available
int height = info->height;
int rate = info->rate;
#if defined(USE_EGL)
EGLConfig eglcfg = 0;
#endif
#if defined(USE_EGL) || defined(VKQUAKE)
XVisualInfo vinfodef;
#endif
@ -3903,10 +3929,21 @@ static qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int
#ifdef GLQUAKE
#ifdef USE_EGL
case PSL_EGL:
visinfo = &vinfodef;
if (!x11.pXMatchVisualInfo(vid_dpy, scrnum, info->bpp?info->bpp:DefaultDepth(vid_dpy, scrnum), TrueColor, visinfo))
if (!EGL_InitDisplay(info, EGL_PLATFORM_X11_KHR, vid_dpy, (EGLNativeDisplayType)vid_dpy, &eglcfg))
{
Sys_Error("Couldn't choose visual for EGL\n");
Con_Printf("X11VID_Init: Unable to find suitable EGL config\n");
GLVID_Shutdown();
return false;
}
{
int num_visuals;
EGLint id;
if (!qeglGetConfigAttrib(egldpy, eglcfg, EGL_NATIVE_VISUAL_ID, &id))
Sys_Error("Couldn't choose visual for EGL\n");
vinfodef.visualid = id;
visinfo = x11.pXGetVisualInfo(vid_dpy, VisualIDMask, &vinfodef, &num_visuals);
if (!visinfo)
Sys_Error("Couldn't get visual info for EGL\n");
}
break;
#endif
@ -4049,7 +4086,7 @@ static qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int
break;
#ifdef USE_EGL
case PSL_EGL:
if (!EGL_Init(info, palette, EGL_PLATFORM_X11_KHR, &vid_window, vid_dpy, (EGLNativeWindowType)vid_window, (EGLNativeDisplayType)vid_dpy))
if (!EGL_InitWindow(info, EGL_PLATFORM_X11_KHR, &vid_window, (EGLNativeWindowType)vid_window, eglcfg))
{
Con_Printf("Failed to create EGL context.\n");
GLVID_Shutdown();

File diff suppressed because it is too large Load diff

View file

@ -119,29 +119,49 @@ void R_DrawFastSky(batch_t *batch)
void R_RenderScene (void);
qboolean R_DrawSkyroom(shader_t *skyshader)
{
#ifdef GLQUAKE
float vmat[16];
refdef_t oldrefdef;
if (qrenderer != QR_OPENGL)
return false; //FIXME
if (r_viewcluster == -1)
return false; //don't draw the skyroom if the camera is outside.
if (r_fastsky.value)
return false; //skyrooms can be expensive.
if (!r_refdef.skyroom_enabled || r_refdef.recurse >= R_MAX_RECURSE-1)
return false;
oldrefdef = r_refdef;
r_refdef.recurse+=1;
r_refdef.externalview = true;
r_refdef.externalview = true; //an out-of-body experience...
r_refdef.skyroom_enabled = false;
r_refdef.forcevis = false;
r_refdef.flags |= RDF_DISABLEPARTICLES;
r_refdef.flags &= ~RDF_SKIPSKY;
r_refdef.forcedvis = NULL;
r_refdef.areabitsknown = false; //recalculate areas clientside.
/*work out where the camera should be (use the same angles)*/
VectorCopy(r_refdef.skyroom_pos, r_refdef.vieworg);
VectorCopy(r_refdef.skyroom_pos, r_refdef.pvsorigin);
Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, vpn, vright, vup, r_refdef.vieworg);
if (developer.ival)
if (r_worldentity.model->funcs.PointContents(r_worldentity.model, NULL, r_refdef.skyroom_pos) & FTECONTENTS_SOLID)
Con_DPrintf("Skyroom position %.1f %.1f %.1f in solid\n", r_refdef.skyroom_pos[0], r_refdef.skyroom_pos[1], r_refdef.skyroom_pos[2]);
/*if (cl.skyrotate)
{
vec3_t axis[3];
float ang = cl.skyrotate * cl.time;
if (!cl.skyaxis[0]&&!cl.skyaxis[1]&&!cl.skyaxis[2])
VectorSet(cl.skyaxis, 0,0,1);
RotatePointAroundVector(axis[0], cl.skyaxis, vpn, ang);
RotatePointAroundVector(axis[1], cl.skyaxis, vright, ang);
RotatePointAroundVector(axis[2], cl.skyaxis, vup, ang);
Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, axis[0], axis[1], axis[2], r_refdef.vieworg);
}
else*/
Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, vpn, vright, vup, r_refdef.vieworg);
R_SetFrustum (r_refdef.m_projection_std, vmat);
//now determine the stuff the backend will use.
@ -159,16 +179,7 @@ qboolean R_DrawSkyroom(shader_t *skyshader)
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
VectorCopy (r_refdef.vieworg, r_origin);
GLBE_SelectEntity(&r_worldentity);
GL_ForceDepthWritable();
qglClear(GL_DEPTH_BUFFER_BIT);
currententity = NULL;
return true;
#else
return false;
#endif
}
/*
@ -208,7 +219,6 @@ qboolean R_DrawSkyChain (batch_t *batch)
if (skyshader->prog) //glsl is expected to do the whole skybox/warpsky thing itself, with no assistance from this legacy code.
{
//if the first pass is transparent in some form, then be prepared to give it a skyroom behind.
R_DrawSkyroom(skyshader);
return false; //draw as normal...
}
}
@ -218,7 +228,7 @@ qboolean R_DrawSkyChain (batch_t *batch)
else
skyboxtex = NULL;
if (R_DrawSkyroom(skyshader))
if (r_refdef.flags & RDF_SKIPSKY)
{ //don't obscure the skyroom if the sky shader is opaque.
qboolean opaque = false;
if (skyshader->numpasses)

View file

@ -82,7 +82,7 @@ static cvar_t pr_no_playerphysics = CVARFD("pr_no_playerphysics", "0", CVAR_LATC
static cvar_t pr_no_parsecommand = CVARFD("pr_no_parsecommand", "0", 0, "Provides a way around invalid mod usage of SV_ParseClientCommand, eg xonotic.");
extern cvar_t pr_sourcedir;
cvar_t pr_ssqc_progs = CVARAF("progs", "", "sv_progs", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_NOTFROMSERVER);
cvar_t pr_ssqc_progs = CVARAFD("sv_progs", "", "progs", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_NOTFROMSERVER, "Specifies the filename of the gamecode to use serverside. Empty means autodetect - typically loading either progs or qwprogs depending on gamedir priority, then based upon deathmatch settings.");
static cvar_t pr_nonetaccess = CVARD("pr_nonetaccess", "0", "Block all direct access to network buffers (the writebyte builtin and friends will ignore the call)."); //prevent write_... builtins from doing anything. This means we can run any mod, specific to any engine, on the condition that it also has a qw or nq crc.
static cvar_t pr_overridebuiltins = CVAR("pr_overridebuiltins", "1");
@ -99,6 +99,7 @@ static cvar_t sv_gameplayfix_setmodelrealbox = CVARD("sv_gameplayfix_setmodelrea
#endif
static cvar_t sv_gameplayfix_setmodelsize_qw = CVARD("sv_gameplayfix_setmodelsize_qw", "0", "The setmodel builtin will act as a setsize for QuakeWorld mods also.");
cvar_t dpcompat_nopreparse = CVARD("dpcompat_nopreparse", "0", "Xonotic uses svc_tempentity with unknowable lengths mixed with other data that needs to be translated. This cvar disables any attempt to translate or pre-parse network messages, including disabling nq/qw cross compatibility. NOTE: because preparsing will be disabled, messages might not get backbuffered correctly if too much reliable data is written.");
static cvar_t dpcompat_precachesoundhack = CVARD("dpcompat_precachesoundhack", "0", "Changes the behaviour of only the ssqc's precache_sound to return a precache index. precache_model and csqc's precaches are unchanged.");
//static cvar_t dpcompat_traceontouch = CVARD("dpcompat_traceontouch", "0", "Report trace plane etc when an entity touches another.");
extern cvar_t sv_listen_dp;
@ -1568,6 +1569,7 @@ void PR_Init(void)
Cvar_Register (&pr_ssqc_progs, cvargroup_progs);
Cvar_Register (&pr_compatabilitytest, cvargroup_progs);
Cvar_Register (&dpcompat_precachesoundhack, cvargroup_progs);
Cvar_Register (&dpcompat_nopreparse, cvargroup_progs);
Cvar_Register (&pr_nonetaccess, cvargroup_progs);
Cvar_Register (&pr_overridebuiltins, cvargroup_progs);
@ -4347,7 +4349,7 @@ static void QCBUILTIN PF_precache_file (pubprogfuncs_t *prinst, struct globalvar
FS_FLocateFile(s, FSLF_IFFOUND, NULL);
}
int PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s)
int PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s, qboolean queryonly)
{
int i;
@ -4362,6 +4364,8 @@ int PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s)
{
if (!sv.strings.sound_precache[i])
{
if (queryonly)
return 0;
#ifdef VM_Q1
if (svs.gametype == GT_Q1QVM)
sv.strings.sound_precache[i] = s;
@ -4389,18 +4393,30 @@ int PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s)
if (!strcmp(sv.strings.sound_precache[i], s))
return i;
}
PR_BIError (prinst, "PF_precache_sound: overflow");
if (!queryonly)
PR_BIError (prinst, "PF_precache_sound: overflow");
return 0;
}
static void QCBUILTIN PF_precache_sound (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *s;
int idx;
s = PR_GetStringOfs(prinst, OFS_PARM0);
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
idx = PF_precache_sound_Internal(prinst, s, false);
PF_precache_sound_Internal(prinst, s);
if (dpcompat_precachesoundhack.ival)
G_FLOAT(OFS_RETURN) = idx; //returns the index as a float.
else
G_INT(OFS_RETURN) = G_INT(OFS_PARM0); //returns the filename as a string.
}
static void QCBUILTIN PF_getsoundindex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *s = PR_GetStringOfs(prinst, OFS_PARM0);
qboolean queryonly = (svprogfuncs->callargc >= 2)?G_FLOAT(OFS_PARM1):false;
G_FLOAT(OFS_RETURN) = PF_precache_sound_Internal(prinst, s, queryonly);
}
int PF_precache_model_Internal (pubprogfuncs_t *prinst, const char *s, qboolean queryonly)
@ -4459,7 +4475,8 @@ int PF_precache_model_Internal (pubprogfuncs_t *prinst, const char *s, qboolean
return i;
}
}
PR_BIError (prinst, "PF_precache_model: overflow");
if (!queryonly)
PR_BIError (prinst, "PF_precache_model: overflow");
return 0;
}
static void QCBUILTIN PF_precache_model (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -7442,7 +7459,7 @@ static void QCBUILTIN PF_clientcommand (pubprogfuncs_t *prinst, struct globalvar
const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned int protocol, unsigned int pext1, unsigned int pext2, char *guid)
const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned int protocol, unsigned int pext1, unsigned int pext2, unsigned int ezpext1, char *guid)
{
char addrstr[256];
char clfeatures[4096], *bp;
@ -7532,6 +7549,19 @@ const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned
Info_SetValueForKey(clfeatures, "PEXT2_VOICECHAT", "1", sizeof(clfeatures));
if (pext2 & PEXT2_REPLACEMENTDELTAS)
Info_SetValueForKey(clfeatures, "PEXT2_REPLACEMENTDELTAS", "1", sizeof(clfeatures));
if (pext2 & PEXT2_MAXPLAYERS)
Info_SetValueForKey(clfeatures, "PEXT2_MAXPLAYERS", "1", sizeof(clfeatures));
if (pext2 & PEXT2_PREDINFO)
Info_SetValueForKey(clfeatures, "PEXT2_PREDINFO", "1", sizeof(clfeatures));
if (pext2 & PEXT2_NEWSIZEENCODING)
Info_SetValueForKey(clfeatures, "PEXT2_NEWSIZEENCODING", "1", sizeof(clfeatures));
if (pext2 & PEXT2_INFOBLOBS)
Info_SetValueForKey(clfeatures, "PEXT2_INFOBLOBS", "1", sizeof(clfeatures));
if (ezpext1 & EZPEXT1_FLOATENTCOORDS)
Info_SetValueForKey(clfeatures, "EZPEXT1_FLOATENTCOORDS", "1", sizeof(clfeatures));
if (ezpext1 & EZPEXT1_SETANGLEREASON)
Info_SetValueForKey(clfeatures, "EZPEXT1_SETANGLEREASON", "1", sizeof(clfeatures));
pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, sv.world.edicts);
G_INT(OFS_PARM0) = (int)PR_TempString(svprogfuncs, addrstr);
@ -10663,6 +10693,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
// {"findlist_radius", PF_FindListRadius, 0, 0, 0, 0, D("entity*(vector pos, float radius)", "Return a list of entities with the given string field set to the given value.")},
// {"traceboxptr", PF_TraceBox, 0, 0, 0, 0, D("typedef struct {\nfloat allsolid;\nfloat startsolid;\nfloat fraction;\nfloat truefraction;\nentity ent;\nvector endpos;\nvector plane_normal;\nfloat plane_dist;\nint surfaceflags;\nint contents;\n} trace_t;\nvoid(trace_t *trace, vector start, vector mins, vector maxs, vector end, float nomonsters, entity forent)", "Like regular tracebox, except doesn't doesn't use any evil globals.")},
{"getsoundindex", PF_getsoundindex, 0, 0, 0, 0, D("float(string soundname, float queryonly)", "Provides a way to query if a sound is already precached or not. The return value can also be checked for <=255 to see if it'll work over any network protocol. The sound index can also be used for writebyte hacks, but this is discouraged - use SOUNDFLAG_UNICAST instead.")},
{"getmodelindex", PF_getmodelindex, 0, 0, 0, 200, D("float(string modelname, optional float queryonly)", "Acts as an alternative to precache_model(foo);setmodel(bar, foo); return bar.modelindex;\nIf queryonly is set and the model was not previously precached, the builtin will return 0 without needlessly precaching the model.")},
{"externcall", PF_externcall, 0, 0, 0, 201, D("__variant(float prnum, string funcname, ...)", "Directly call a function in a different/same progs by its name.\nprnum=0 is the 'default' or 'main' progs.\nprnum=-1 means current progs.\nprnum=-2 will scan through the active progs and will use the first it finds.")},
{"addprogs", PF_addprogs, 0, 0, 0, 202, D("float(string progsname)", "Loads an additional .dat file into the current qcvm. The returned handle can be used with any of the externcall/externset/externvalue builtins.\nThere are cvars that allow progs to be loaded automatically.")},

View file

@ -109,28 +109,28 @@ typedef enum
G_GETINFOKEY,
G_MULTICAST, //35
G_DISABLEUPDATES,
G_WRITEBYTE,
G_WRITECHAR,
G_WRITESHORT,
G_WRITEBYTE,
G_WRITECHAR,
G_WRITESHORT,
G_WRITELONG, //40
G_WRITEANGLE,
G_WRITECOORD,
G_WRITESTRING,
G_WRITEANGLE,
G_WRITECOORD,
G_WRITESTRING,
G_WRITEENTITY,
G_FLUSHSIGNON, //45
g_memset,
g_memcpy,
g_strncpy,
g_sin,
g_memcpy,
g_strncpy,
g_sin,
g_cos, //50
g_atan2,
g_sqrt,
g_floor,
g_ceil,
g_atan2,
g_sqrt,
g_floor,
g_ceil,
g_acos, //55
G_CMD_ARGC,
G_CMD_ARGV,
G_TraceBox, //was G_TraceCapsule
G_TraceBox, //was G_TraceCapsule, which is a misnomer.
G_FS_OpenFile,
G_FS_CloseFile, //60
G_FS_ReadFile,
@ -214,7 +214,7 @@ typedef enum
typedef enum
{
F_INT,
F_INT,
F_FLOAT,
F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
// F_GSTRING, // string on disk, pointer in memory, TAG_GAME
@ -817,7 +817,7 @@ static qintptr_t QVM_Remove_Ent (void *offset, quintptr_t mask, const qintptr_t
static qintptr_t QVM_Precache_Sound (void *offset, quintptr_t mask, const qintptr_t *arg)
{
return PF_precache_sound_Internal(svprogfuncs, VM_POINTER(arg[0]));
return PF_precache_sound_Internal(svprogfuncs, VM_POINTER(arg[0]), false);
}
static qintptr_t QVM_Precache_Model (void *offset, quintptr_t mask, const qintptr_t *arg)
{
@ -1786,7 +1786,7 @@ static qintptr_t QVM_uri_query (void *offset, quintptr_t mask, const qintptr_t *
const char *data = VM_POINTER(arg[4]);
size_t datasize = VM_LONG(arg[5]);
extern cvar_t pr_enable_uriget;
if (!pr_enable_uriget.ival)
{
Con_Printf("QVM_uri_query(\"%s\"): %s disabled\n", url, pr_enable_uriget.name);
@ -1856,6 +1856,29 @@ static qintptr_t QVM_pointerstat (void *offset, quintptr_t mask, const qintptr_t
return 0;
}
static qintptr_t QVM_VisibleTo (void *offset, quintptr_t mask, const qintptr_t *arg)
{
unsigned int a0 = VM_LONG(arg[0]);
unsigned int a1 = VM_LONG(arg[1]);
if (a0 < sv.world.num_edicts || a1 < sv.world.num_edicts)
{
pvscache_t *viewer = &q1qvmprogfuncs.edicttable[a0]->pvsinfo;
pvscache_t *viewee = &q1qvmprogfuncs.edicttable[a1]->pvsinfo;
if (viewer->num_leafs && viewee->num_leafs)
{
unsigned int i;
for (i = 0; i < viewer->num_leafs; i++)
{
int areas[] = {2,viewer->areanum, viewer->areanum2};
qbyte *pvs = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, viewer->leafnums[i], NULL, PVM_FAST);
if (sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, viewee, pvs, areas))
return true; //viewer can see viewee
}
}
}
return 0;
}
static qintptr_t QVM_Map_Extension (void *offset, quintptr_t mask, const qintptr_t *arg);
typedef qintptr_t (*traps_t) (void *offset, quintptr_t mask, const qintptr_t *arg);
@ -1898,24 +1921,24 @@ traps_t bitraps[G_MAX] =
QVM_GetInfoKey,
QVM_Multicast, //35
QVM_DisableUpdates,
QVM_WriteByte,
QVM_WriteChar,
QVM_WriteShort,
QVM_WriteByte,
QVM_WriteChar,
QVM_WriteShort,
QVM_WriteLong, //40
QVM_WriteAngle,
QVM_WriteCoord,
QVM_WriteString,
QVM_WriteAngle,
QVM_WriteCoord,
QVM_WriteString,
QVM_WriteEntity,
QVM_FlushSignon, //45
QVM_memset,
QVM_memcpy,
QVM_strncpy,
QVM_sin,
QVM_memcpy,
QVM_strncpy,
QVM_sin,
QVM_cos, //50
QVM_atan2,
QVM_sqrt,
QVM_floor,
QVM_ceil,
QVM_atan2,
QVM_sqrt,
QVM_floor,
QVM_ceil,
QVM_acos, //55
QVM_Cmd_ArgC,
QVM_Cmd_ArgV,
@ -1975,6 +1998,7 @@ struct
{"pointparticles", QVM_pointparticles},
{"clientstat", QVM_clientstat}, //csqc extension
{"pointerstat", QVM_pointerstat}, //csqc extension
{"VisibleTo", QVM_VisibleTo}, //alternative to mvdsv's visclients hack
//sql?
//model querying?
@ -2072,7 +2096,7 @@ void Q1QVM_Shutdown(qboolean notifygame)
Q_strncpyz(svs.clients[i].namebuf, svs.clients[i].name, sizeof(svs.clients[i].namebuf));
svs.clients[i].name = svs.clients[i].namebuf;
}
if (notifygame)
if (notifygame && gvars)
VM_Call(q1qvm, GAME_SHUTDOWN, 0, 0, 0);
VM_Destroy(q1qvm);
q1qvm = NULL;
@ -2150,13 +2174,19 @@ qboolean PR_LoadQ1QVM(void)
qintptr_t limit;
extern cvar_t pr_maxedicts;
const char *fname = pr_ssqc_progs.string;
if (!*fname)
fname = "qwprogs";
Q1QVM_Shutdown(true);
q1qvm = VM_Create("qwprogs", com_nogamedirnativecode.ival?NULL:syscallnative, "qwprogs", syscallqvm);
q1qvm = VM_Create(fname, com_nogamedirnativecode.ival?NULL:syscallnative, fname, syscallqvm);
if (!q1qvm)
q1qvm = VM_Create("qwprogs", syscallnative, "qwprogs", NULL);
q1qvm = VM_Create(fname, syscallnative, fname, NULL);
if (!q1qvm)
{
if (com_nogamedirnativecode.ival && COM_FCheckExists(va("%s"ARCH_DL_POSTFIX, fname)))
Con_Printf(CON_WARNING"%s"ARCH_DL_POSTFIX" exists, but is blocked from loading due to known bugs in other engines. If this is from a safe source then either ^aset com_nogamedirnativecode 0^a or rename to eg %s%s_%s"ARCH_DL_POSTFIX"\n", fname, ((host_parms.binarydir && *host_parms.binarydir)?host_parms.binarydir:host_parms.basedir), fname, FS_GetGamedir(false));
if (svprogfuncs == &q1qvmprogfuncs)
sv.world.progs = svprogfuncs = NULL;
return false;
@ -2238,7 +2268,7 @@ qboolean PR_LoadQ1QVM(void)
gdn = (gameDataN_t*)((char*)VM_MemoryBase(q1qvm) + ret);
gd.APIversion = gdn->APIversion;
gd.sizeofent = gdn->sizeofent;
gd.ents = gdn->ents;
gd.global = gdn->global;
gd.fields = gdn->fields;
@ -2384,6 +2414,7 @@ qboolean PR_LoadQ1QVM(void)
{
const char *fname = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, field[i].name);
emufields
Con_DPrintf("Extension field %s is not supported\n", fname);
}
}
else
@ -2394,6 +2425,7 @@ qboolean PR_LoadQ1QVM(void)
{
const char *fname = Q1QVMPF_PointerToNative(&q1qvmprogfuncs, field[i].name);
emufields
Con_DPrintf("Extension field %s is not supported\n", fname);
}
}
#undef emufield
@ -2490,7 +2522,7 @@ qboolean Q1QVM_GameConsoleCommand(void)
//FIXME: if an rcon command from someone on the server, mvdsv sets self to match the ip of that player
//this is not required (broken by proxies anyway) but is a nice handy feature
pr_global_struct->time = sv.world.physicstime;
oldself = pr_global_struct->self; //these are usually useless
oldother = pr_global_struct->other; //but its possible that someone makes a mod that depends on the 'mod' command working via redirectcmd+co

View file

@ -1097,7 +1097,7 @@ extern vfsfile_t *sv_fraglogfile;
//===========================================================
void SV_AddDebugPolygons(void);
const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned int protocol, unsigned int pext1, unsigned int pext2, char *guid);
const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned int protocol, unsigned int pext1, unsigned int pext2, unsigned int ezpext1, char *guid);
//
//sv_ccmds.c
@ -1159,7 +1159,7 @@ typedef struct
#endif
unsigned int ftepext1;
unsigned int ftepext2;
// unsigned int ezpext1;
unsigned int ezpext1;
int qport; //part of the qw protocol to avoid issues with buggy routers that periodically renumber cl2sv ports.
#ifdef HUFFNETWORK
int huffcrc; //network compression stuff

View file

@ -379,6 +379,15 @@ static void SV_Give_f (void)
}
#endif
#if defined(HAVE_LEGACY) && defined(HAVE_SERVER)
static void SV_redundantcommand_f(void)
{
if (cl_warncmd.ival)
Con_Printf("%s is obsolete, redundant, or otherwise outdated.\n", Cmd_Argv(0));
}
#endif
static int QDECL ShowMapList (const char *name, qofs_t flags, time_t mtime, void *parm, searchpathfuncs_t *spath)
{
const char *levelshots[] =
@ -2337,6 +2346,7 @@ void SV_Serverinfo_f (void)
{
Con_TPrintf ("Server info settings:\n");
InfoBuf_Print (&svs.info, "");
Con_Printf("[%u]\n", (unsigned int)svs.info.totalsize);
return;
}
@ -2426,6 +2436,7 @@ static void SV_Localinfo_f (void)
{
Con_TPrintf ("Local info settings:\n");
InfoBuf_Print (&svs.localinfo, "");
Con_Printf("[%u]\n", (unsigned int)svs.localinfo.totalsize);
return;
}
@ -3197,6 +3208,16 @@ void SV_InitOperatorCommands (void)
Cmd_AddCommand ("listmaps", SV_MapList_f);
Cmd_AddCommand ("maplist", SV_MapList_f);
Cmd_AddCommand ("maps", SV_MapList_f);
#if defined(HAVE_LEGACY) && defined(HAVE_SERVER)
Cmd_AddCommandD ("check_maps", SV_redundantcommand_f, "Obsolete, specific to ktpro. Modern mods should use search_begin instead.");
Cmd_AddCommandD ("sys_select_timeout", SV_redundantcommand_f, "Redundant - server will throttle according to tick rates instead.");
Cmd_AddCommandD ("sv_downloadchunksperframe", SV_redundantcommand_f, "Flawed - downloads instead proceed at the client's drate (or rate) setting instead of ignoring it entirely.");
Cmd_AddCommandD ("sv_speedcheck", SV_redundantcommand_f, "Obsolete - movetime is instead metered over time, instead of randomly kicking everyone due to dodgy timer hardware on the server.");
Cmd_AddCommandD ("sv_enableprofile", SV_redundantcommand_f, "Debug setting that is not implemented.");
Cmd_AddCommandD ("sv_progsname", SV_redundantcommand_f, "Use sv_progs instead.");
Cmd_AddCommandD ("download_map_url", SV_redundantcommand_f, "Redundant - individual maps will probably download faster than the user can open a browser at the given url.");
Cmd_AddCommandD ("sv_progtype", SV_redundantcommand_f, "Use sv_progs instead. Using to block .dll loading is insufficient with buggy clients around.");
#endif
Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);

View file

@ -38,8 +38,6 @@ int sv_max_staticentities;
staticsound_state_t *sv_staticsounds;
int sv_max_staticsounds;
char localinfo[MAX_LOCALINFO_STRING+1]; // local game info
extern cvar_t skill;
extern cvar_t sv_cheats;
extern cvar_t sv_bigcoords;

View file

@ -118,6 +118,7 @@ cvar_t sv_listen_dp = CVARD("sv_listen_dp", "0", "Allows the server to respond
cvar_t sv_listen_q3 = CVAR("sv_listen_q3", "0");
#endif
cvar_t sv_reconnectlimit = CVARD("sv_reconnectlimit", "0", "Blocks dupe connection within the specified length of time .");
cvar_t sv_use_dns = CVARD("sv_use_dns", "", "Performs a reverse-dns lookup in order to report actual ip addresses of clients.");
extern cvar_t net_enable_dtls;
cvar_t sv_reportheartbeats = CVARD("sv_reportheartbeats", "2", "Print a notice each time a heartbeat is sent to a master server. When set to 2, the message will be displayed once.");
cvar_t sv_heartbeat_interval = CVARD("sv_heartbeat_interval", "110", "Interval between heartbeats. Low values are abusive, high values may cause NAT/ghost issues.");
@ -160,7 +161,7 @@ cvar_t fraglimit = CVARF("fraglimit", "" , CVAR_SERVERINFO);
cvar_t timelimit = CVARF("timelimit", "" , CVAR_SERVERINFO);
cvar_t teamplay = CVARF("teamplay", "" , CVAR_SERVERINFO);
cvar_t samelevel = CVARF("samelevel", "" , CVAR_SERVERINFO);
cvar_t sv_playerslots = CVARAD("sv_playerslots", "",
cvar_t sv_playerslots = CVARAD("sv_playerslots", "",
"maxplayers", "Specify maximum number of player/spectator/bot slots, new value takes effect on the next map (this may result in players getting kicked). This should generally be set to maxclients+maxspectators. Leave blank for a default value.\nMaximum value of "STRINGIFY(MAX_CLIENTS)". Values above 16 will result in issues with vanilla NQ clients. Effective values other than 32 will result in issues with vanilla QW clients.");
cvar_t maxclients = CVARAFD("maxclients", "8",
"sv_maxclients", CVAR_SERVERINFO, "Specify the maximum number of players allowed on the server at once. Can be changed mid-map.");
@ -275,6 +276,9 @@ void SV_Shutdown (void)
Plug_Shutdown(true);
#endif
Mod_Shutdown(true);
#ifdef PACKAGEMANAGER
PM_Shutdown();
#endif
COM_DestroyWorkerThread();
FS_Shutdown();
#ifdef PLUGINS
@ -282,11 +286,8 @@ void SV_Shutdown (void)
#endif
Cvar_Shutdown();
Cmd_Shutdown();
#ifdef PACKAGEMANAGER
PM_Shutdown();
#endif
InfoBuf_Clear(&svs.info, true);
InfoBuf_Clear(&svs.localinfo, true);
@ -353,7 +354,6 @@ void VARGS SV_Error (char *error, ...)
sv.spawned_observer_slots = 0;
SV_UnspawnServer();
#ifndef SERVERONLY
if (cls.state)
{
@ -367,12 +367,15 @@ void VARGS SV_Error (char *error, ...)
extern cvar_t cl_disconnectreason;
extern jmp_buf host_abort;
SCR_EndLoadingPlaque();
SV_UnspawnServer();
Cvar_Set(&cl_disconnectreason, va("SV_Error: %s", string));
inerror=false;
longjmp (host_abort, 1);
}
#endif
sys_nounload = true;
SV_UnspawnServer();
SV_Shutdown ();
Sys_Error ("SV_Error: %s\n",string);
@ -987,7 +990,7 @@ void SV_FullClientUpdate (client_t *client, client_t *to)
{
for (i = 0; i < sv.allocated_client_slots; i++)
{
SV_FullClientUpdate(client, &svs.clients[i]);
SV_FullClientUpdate(client, &svs.clients[i]);
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)
@ -1286,7 +1289,7 @@ static void SVC_GetInfo (char *challenge, int fullstatus)
Info_SetValueForKey(resp, "sv_maxclients", maxclients.string, sizeof(response) - (resp-response));
Info_SetValueForKey(resp, "mapname", InfoBuf_ValueForKey(&svs.info, "map"), sizeof(response) - (resp-response));
resp += strlen(resp);
//now include the full/regular serverinfo
//now include the full/regular serverinfo
resp += InfoBuf_ToString(&svs.info, resp, sizeof(response) - (resp-response), prioritykeys, ignorekeys, NULL, NULL, NULL);
*resp = 0;
//and any possibly-long qc status string
@ -2131,20 +2134,23 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
//void NET_AdrToStringResolve (netadr_t *adr, void (*resolved)(void *ctx, void *data, size_t a, size_t b), void *ctx, size_t a, size_t b);
/*static void SV_UserDNSResolved(void *ctx, void *data, size_t idx, size_t uid)
static void SV_UserDNSResolved(void *ctx, void *data, size_t idx, size_t uid)
{
if (idx < svs.allocated_client_slots)
{
if (svs.clients[idx].userid == uid)
client_t *cl = &svs.clients[idx];
if (cl->userid == uid)
{
Z_Free(svs.clients[idx].reversedns);
svs.clients[idx].reversedns = data;
Z_Free(cl->reversedns);
cl->reversedns = data;
SV_LogPlayer(cl, va("dns %s", cl->reversedns));
return;
}
}
//client ran away before the dns completed
Con_DPrintf("stale dns lookup result: %s\n", (char*)data);
Z_Free(data);
}*/
}
client_t *SV_AddSplit(client_t *controller, char *info, int id)
{
@ -2161,7 +2167,7 @@ client_t *SV_AddSplit(client_t *controller, char *info, int id)
SV_PrintToClient(controller, PRINT_HIGH, "Your client doesn't support splitscreen\n");
return NULL;
}
for (curclients = 0, prev = cl = controller; cl; cl = cl->controlled)
{
prev = cl;
@ -2705,7 +2711,7 @@ void SV_DoDirectConnect(svconnectinfo_t *fte_restrict info)
temp.edict = ent;
{
const char *reject = SV_CheckRejectConnection(&info->adr, info->userinfo, info->protocol, info->ftepext1, info->ftepext2, info->guid);
const char *reject = SV_CheckRejectConnection(&info->adr, info->userinfo, info->protocol, info->ftepext1, info->ftepext2, info->ezpext1, info->guid);
if (reject)
{
SV_RejectMessage(info->protocol, "%s", reject);
@ -2764,8 +2770,6 @@ void SV_DoDirectConnect(svconnectinfo_t *fte_restrict info)
newcl->userinfo.ChangeCTX = &svs.clients[i].userinfo;
InfoBuf_FromString(&newcl->userinfo, info->userinfo, false);
// NET_AdrToStringResolve(&adr, SV_UserDNSResolved, NULL, newcl-svs.clients, newcl->userid);
newcl->challenge = info->challenge;
newcl->zquake_extensions = atoi(InfoBuf_ValueForKey(&newcl->userinfo, "*z_ext"));
InfoBuf_SetStarKey(&newcl->userinfo, "*z_ext", "");
@ -3051,6 +3055,10 @@ void SV_DoDirectConnect(svconnectinfo_t *fte_restrict info)
#ifdef NQPROT
newcl->netchan.incoming_reliable_sequence = info->expectedreliablesequence;
#endif
if (sv_use_dns.ival)
NET_AdrToStringResolve(&info->adr, SV_UserDNSResolved, NULL, newcl-svs.clients, newcl->userid);
}
/*
@ -3085,6 +3093,7 @@ void SVC_DirectConnect(int expectedreliablesequence)
info.mtu = 0;
info.ftepext1 = 0;
info.ftepext2 = 0;
info.ezpext1 = 0;
*info.guid = 0;
if (*Cmd_Argv(1) == '\\')
@ -3232,7 +3241,7 @@ void SVC_DirectConnect(int expectedreliablesequence)
else
{
//fte: connectN is no longer supported (multiple userinfos packed into a single packet was a bad idea when userinfos can be so large
if (atoi(Cmd_Argv(0)+7))
/*if (atoi(Cmd_Argv(0)+7))
{
int numssclients = atoi(Cmd_Argv(0)+7);
if (numssclients!=1)
@ -3241,7 +3250,7 @@ void SVC_DirectConnect(int expectedreliablesequence)
Con_TPrintf ("* rejected connect from old client\n");
return;
}
}
}*/
version = atoi(Cmd_Argv(1));
if (version >= 31 && version <= 34)
@ -3375,6 +3384,13 @@ void SVC_DirectConnect(int expectedreliablesequence)
Con_DPrintf("Client supports 0x%x fte2 extensions\n", info.ftepext2);
}
break;
case PROTOCOL_VERSION_EZQUAKE1:
if (info.protocol == SCP_QUAKEWORLD)
{
info.ezpext1 = Q_atoi(Cmd_Argv(1));
Con_DPrintf("Client supports 0x%x ez1 extensions\n", info.ezpext1);
}
break;
case PROTOCOL_VERSION_HUFFMAN:
#ifdef HUFFNETWORK
info.huffcrc = Q_atoi(Cmd_Argv(1));
@ -4938,6 +4954,8 @@ float SV_Frame (void)
svs.framenum = 0;
delay = sv_maxtic.value;
if (isDedicated && sv.spawned_client_slots == 0 && sv.spawned_observer_slots == 0)
delay = max(delay, 1); //when idle, don't keep waking up for no reason
// keep the random time dependent
rand ();
@ -4953,7 +4971,7 @@ float SV_Frame (void)
}
#endif
#ifndef SERVERONLY
#ifdef HAVE_CLIENT
isidle = !isDedicated && sv.allocated_client_slots == 1 && Key_Dest_Has(~kdm_game) && cls.state == ca_active;
/*server is effectively paused in SP/coop if there are no clients/spectators*/
if (sv.spawned_client_slots == 0 && sv.spawned_observer_slots == 0 && !deathmatch.ival)
@ -5337,6 +5355,7 @@ void SV_InitLocal (void)
#endif
sv_listen_qw.restriction = RESTRICT_MAX; //no disabling this over rcon.
Cvar_Register (&sv_reconnectlimit, cvargroup_servercontrol);
Cvar_Register (&sv_use_dns, cvargroup_servercontrol);
Cvar_Register (&fraglog_public, cvargroup_servercontrol);
SVNET_RegisterCvars();

View file

@ -2596,6 +2596,8 @@ qboolean SV_Physics (void)
}
maxtics = sv_limittics.ival;
if (sv.spawned_observer_slots==0&&sv.spawned_client_slots==0)
maxtics = 1; //no players on the server. let timings slide
// don't bother running a frame if sys_ticrate seconds haven't passed
while (1)

View file

@ -1107,10 +1107,10 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const
return Sys_EnumerateFiles2(truepath, strlen(gpath)+1, match, func, parm, spath);
}
void Sys_CloseLibrary(dllhandle_t *lib)
{
if (sys_nounload)
return;
dlclose((void*)lib);
}
dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs)

View file

@ -36,12 +36,12 @@ usercmd_t cmd;
void QDECL SV_NQPhysicsUpdate(cvar_t *var, char *oldvalue)
{
if (!strcmp(var->string, "auto"))
if (!strcmp(var->string, "auto") || !strcmp(var->string, ""))
{ //prediction requires nq physics, so use it by default in multiplayer.
if (progstype == PROG_QW || (!isDedicated && sv.allocated_client_slots > 1))
var->ival = 1;
else
var->ival = 0;
else
var->ival = 1;
}
}
@ -76,7 +76,7 @@ cvar_t cmd_allowaccess = CVAR("cmd_allowaccess", "0"); //set to 1 to allow cmd t
cvar_t cmd_gamecodelevel = CVAR("cmd_gamecodelevel", STRINGIFY(RESTRICT_LOCAL)); //execution level which gamecode is told about (for unrecognised commands)
cvar_t sv_pure = CVARFD("sv_pure", "", CVAR_SERVERINFO, "The most evil cvar in the world, many clients will ignore this.\n0=standard quake rules.\n1=clients should prefer files within packages present on the server.\n2=clients should use *only* files within packages present on the server.\nDue to quake 1.01/1.06 differences, a setting of 2 only works in total conversions.");
cvar_t sv_nqplayerphysics = CVARAFCD("sv_nqplayerphysics", "0", "sv_nomsec", 0, SV_NQPhysicsUpdate, "Disable player prediction and run NQ-style player physics instead. This can be used for compatibility with mods that expect exact behaviour.");
cvar_t sv_nqplayerphysics = CVARAFCD("sv_nqplayerphysics", "auto", "sv_nomsec", 0, SV_NQPhysicsUpdate, "Disable player prediction and run NQ-style player physics instead. This can be used for compatibility with mods that expect exact behaviour.");
#ifdef HAVE_LEGACY
cvar_t sv_brokenmovetypes = CVARD("sv_brokenmovetypes", "0", "Emulate vanilla quakeworld by forcing MOVETYPE_WALK on all players. Shouldn't be used for any games other than QuakeWorld.");

View file

@ -8,6 +8,8 @@
//FIXME: instead of switching rendertargets and back, we should be using an alternative queue.
#define PERMUTATION_BEM_FP16 (1u<<12)
#define PERMUTATION_BEM_MULTISAMPLE (1u<<13)
#define PERMUTATION_BEM_DEPTHONLY (1u<<14)
#define PERMUTATION_BEM_WIREFRAME (1u<<15)
@ -41,7 +43,7 @@ extern cvar_t r_polygonoffset_shadowmap_offset, r_polygonoffset_shadowmap_factor
extern cvar_t r_wireframe;
extern cvar_t vk_stagingbuffers;
unsigned int vk_usedynamicstaging;
static unsigned int vk_usedynamicstaging;
#ifdef RTLIGHTS
static void VK_TerminateShadowMap(void);
@ -53,11 +55,31 @@ static void R_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist
#define MAX_TMUS 32
extern texid_t r_whiteimage, missing_texture_gloss, missing_texture_normal;
texid_t r_blackimage;
extern texid_t r_blackimage;
static void BE_RotateForEntity (const entity_t *e, const model_t *mod);
void VKBE_SetupLightCBuffer(dlight_t *l, vec3_t colour);
#ifdef VK_EXT_debug_utils
static void DebugSetName(VkObjectType objtype, uint64_t handle, const char *name)
{
if (vkSetDebugUtilsObjectNameEXT)
{
VkDebugUtilsObjectNameInfoEXT info =
{
VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
NULL,
objtype,
handle,
name?name:"UNNAMED"
};
vkSetDebugUtilsObjectNameEXT(vk.device, &info);
}
}
#else
#define DebugSetName(t,h,n)
#endif
/*========================================== tables for deforms =====================================*/
#define frand() (rand()*(1.0/RAND_MAX))
#define FTABLE_SIZE 1024
@ -1069,11 +1091,13 @@ qboolean VK_LoadBlob(program_t *prog, void *blobdata, const char *name)
info.codeSize = blob->vertlength;
info.pCode = (uint32_t*)((char*)blob+blob->vertoffset);
VkAssert(vkCreateShaderModule(vk.device, &info, vkallocationcb, &vert));
DebugSetName(VK_OBJECT_TYPE_SHADER_MODULE, (uint64_t)vert, name);
info.flags = 0;
info.codeSize = blob->fraglength;
info.pCode = (uint32_t*)((char*)blob+blob->fragoffset);
VkAssert(vkCreateShaderModule(vk.device, &info, vkallocationcb, &frag));
DebugSetName(VK_OBJECT_TYPE_SHADER_MODULE, (uint64_t)frag, name);
prog->vert = vert;
prog->frag = frag;
@ -1253,14 +1277,6 @@ void VKBE_Init(void)
FTable_Init();
{
unsigned char bibuf[4*4*4] = {0};
if (!qrenderer)
r_blackimage = r_nulltex;
else
r_blackimage = R_LoadTexture("$blackimage", 4, 4, TF_RGBA32, bibuf, IF_NOMIPMAP|IF_NOPICMIP|IF_NEAREST|IF_NOGAMMA);
}
shaderstate.depthonly = R_RegisterShader("depthonly", SUF_NONE,
"{\n"
"program depthonly\n"
@ -2828,7 +2844,10 @@ static void BE_CreatePipeline(program_t *p, unsigned int shaderflags, unsigned i
}
ms.pSampleMask = NULL;
ms.rasterizationSamples = vk.multisamplebits;
if (permu & PERMUTATION_BEM_MULTISAMPLE)
ms.rasterizationSamples = vk.multisamplebits;
else
ms.rasterizationSamples = 1;
// ms.sampleShadingEnable = VK_TRUE; //call the fragment shader multiple times, instead of just once per final pixel
// ms.minSampleShading = 0.25;
ds.depthTestEnable = (blendflags&SBITS_MISC_NODEPTHTEST)?VK_FALSE:VK_TRUE;
@ -3017,7 +3036,12 @@ static void BE_CreatePipeline(program_t *p, unsigned int shaderflags, unsigned i
pipeCreateInfo.pColorBlendState = &cb;
pipeCreateInfo.pDynamicState = &dyn;
pipeCreateInfo.layout = p->layout;
pipeCreateInfo.renderPass = (permu&PERMUTATION_BEM_DEPTHONLY)?vk.shadow_renderpass:vk.renderpass[0];
i = (permu&PERMUTATION_BEM_DEPTHONLY)?RP_DEPTHONLY:RP_FULLCLEAR;
if (permu&PERMUTATION_BEM_MULTISAMPLE)
i |= RP_MULTISAMPLE;
if (permu&PERMUTATION_BEM_FP16)
i |= RP_FP16;
pipeCreateInfo.renderPass = VK_GetRenderPass(i);
pipeCreateInfo.subpass = 0;
pipeCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
pipeCreateInfo.basePipelineIndex = -1; //used to create derivatives for pipelines created in the same call.
@ -3025,6 +3049,7 @@ static void BE_CreatePipeline(program_t *p, unsigned int shaderflags, unsigned i
// pipeCreateInfo.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
err = vkCreateGraphicsPipelines(vk.device, vk.pipelinecache, 1, &pipeCreateInfo, vkallocationcb, &pipe->pipeline);
DebugSetName(VK_OBJECT_TYPE_PIPELINE, (uint64_t)pipe->pipeline, p->name);
if (err)
{ //valid err values are VK_ERROR_OUT_OF_HOST_MEMORY, VK_ERROR_OUT_OF_DEVICE_MEMORY, VK_ERROR_INVALID_SHADER_NV
@ -3728,6 +3753,11 @@ void VKBE_SelectMode(backendmode_t mode)
shaderstate.mode = mode;
shaderstate.modepermutation = 0;
if (vk.rendertarg->rpassflags & RP_MULTISAMPLE)
shaderstate.modepermutation |= PERMUTATION_BEM_MULTISAMPLE;
if (vk.rendertarg->rpassflags & RP_FP16)
shaderstate.modepermutation |= PERMUTATION_BEM_FP16;
switch(mode)
{
default:
@ -4637,6 +4667,7 @@ struct vkbe_rtpurge
{
VkFramebuffer framebuffer;
vk_image_t colour;
vk_image_t mscolour;
vk_image_t depth;
};
static void VKBE_RT_Purge(void *ptr)
@ -4644,33 +4675,39 @@ static void VKBE_RT_Purge(void *ptr)
struct vkbe_rtpurge *ctx = ptr;
vkDestroyFramebuffer(vk.device, ctx->framebuffer, vkallocationcb);
VK_DestroyVkTexture(&ctx->depth);
VK_DestroyVkTexture(&ctx->mscolour);
VK_DestroyVkTexture(&ctx->colour);
}
void VKBE_RT_Gen(struct vk_rendertarg *targ, uint32_t width, uint32_t height, qboolean clear, unsigned int flags)
{
//sooooo much work...
VkImageCreateInfo colour_imginfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
VkImageCreateInfo mscolour_imginfo;
VkImageCreateInfo depth_imginfo;
struct vkbe_rtpurge *purge;
static VkClearValue clearvalues[2];
static VkClearValue clearvalues[3];
if (clear)
targ->restartinfo.renderPass = vk.renderpass[2];
else
targ->restartinfo.renderPass = vk.renderpass[1]; //don't care
targ->restartinfo.clearValueCount = 2;
targ->restartinfo.clearValueCount = 3;
targ->depthcleared = true; //will be once its activated.
if (targ->width == width && targ->height == height && targ->q_colour.flags == flags)
if (targ->width == width && targ->height == height && targ->q_colour.flags == flags && (!(targ->rpassflags&RP_MULTISAMPLE))==(targ->mscolour.image==NULL))
{
if (clear || targ->firstuse)
targ->restartinfo.renderPass = VK_GetRenderPass(RP_FULLCLEAR|targ->rpassflags);
else
targ->restartinfo.renderPass = VK_GetRenderPass(RP_DEPTHCLEAR|targ->rpassflags); //don't care
return; //no work to do.
}
if (targ->framebuffer)
{ //schedule the old one to be destroyed at the end of the current frame. DIE OLD ONE, DIE!
purge = VK_AtFrameEnd(VKBE_RT_Purge, NULL, sizeof(*purge));
purge->framebuffer = targ->framebuffer;
purge->colour = targ->colour;
purge->mscolour = targ->mscolour;
purge->depth = targ->depth;
memset(&targ->colour, 0, sizeof(targ->colour));
memset(&targ->mscolour, 0, sizeof(targ->mscolour));
memset(&targ->depth, 0, sizeof(targ->depth));
targ->framebuffer = VK_NULL_HANDLE;
}
@ -4686,9 +4723,14 @@ void VKBE_RT_Gen(struct vk_rendertarg *targ, uint32_t width, uint32_t height, qb
targ->height = height;
if (width == 0 && height == 0)
{
targ->restartinfo.renderPass = NULL;
return; //destroyed
}
targ->restartinfo.renderPass = VK_GetRenderPass(RP_FULLCLEAR|targ->rpassflags);
colour_imginfo.format = vk.backbufformat;
//colour buffer is always 1 sample. if multisampling then we have a hidden 'mscolour' image that is paired with the depth, resolvnig to the 'colour' image.
colour_imginfo.format = (targ->rpassflags&RP_FP16)?VK_FORMAT_R16G16B16A16_SFLOAT:vk.backbufformat;
colour_imginfo.flags = 0;
colour_imginfo.imageType = VK_IMAGE_TYPE_2D;
colour_imginfo.extent.width = width;
@ -4706,16 +4748,20 @@ void VKBE_RT_Gen(struct vk_rendertarg *targ, uint32_t width, uint32_t height, qb
VkAssert(vkCreateImage(vk.device, &colour_imginfo, vkallocationcb, &targ->colour.image));
depth_imginfo = colour_imginfo;
depth_imginfo.format = VK_FORMAT_D32_SFLOAT;
depth_imginfo.format = vk.depthformat;
depth_imginfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT|VK_IMAGE_USAGE_SAMPLED_BIT;
if (targ->rpassflags&RP_MULTISAMPLE)
{
mscolour_imginfo = colour_imginfo;
depth_imginfo.samples = mscolour_imginfo.samples = vk.multisamplebits;
VkAssert(vkCreateImage(vk.device, &mscolour_imginfo, vkallocationcb, &targ->mscolour.image));
VK_AllocateBindImageMemory(&targ->mscolour, true);
}
VkAssert(vkCreateImage(vk.device, &depth_imginfo, vkallocationcb, &targ->depth.image));
VK_AllocateBindImageMemory(&targ->colour, true);
VK_AllocateBindImageMemory(&targ->depth, true);
// set_image_layout(vk.frame->cbuf, targ->colour.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// set_image_layout(vk.frame->cbuf, targ->depth.image, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
{
VkImageViewCreateInfo ivci = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
ivci.components.r = VK_COMPONENT_SWIZZLE_R;
@ -4734,6 +4780,14 @@ void VKBE_RT_Gen(struct vk_rendertarg *targ, uint32_t width, uint32_t height, qb
ivci.image = targ->colour.image;
VkAssert(vkCreateImageView(vk.device, &ivci, vkallocationcb, &targ->colour.view));
if (targ->rpassflags&RP_MULTISAMPLE)
{
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
ivci.format = mscolour_imginfo.format;
ivci.image = targ->mscolour.image;
VkAssert(vkCreateImageView(vk.device, &ivci, vkallocationcb, &targ->mscolour.view));
}
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
ivci.format = depth_imginfo.format;
ivci.image = targ->depth.image;
@ -4771,8 +4825,8 @@ void VKBE_RT_Gen(struct vk_rendertarg *targ, uint32_t width, uint32_t height, qb
VkFramebufferCreateInfo fbinfo = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
VkImageView attachments[3] = {targ->colour.view, targ->depth.view, targ->mscolour.view};
fbinfo.flags = 0;
fbinfo.renderPass = vk.renderpass[2];
fbinfo.attachmentCount = (vk.multisamplebits!=VK_SAMPLE_COUNT_1_BIT)?3:2;
fbinfo.renderPass = targ->restartinfo.renderPass;
fbinfo.attachmentCount = (targ->rpassflags&RP_MULTISAMPLE)?3:2;
fbinfo.pAttachments = attachments;
fbinfo.width = width;
fbinfo.height = height;
@ -4826,9 +4880,9 @@ void VKBE_RT_Gen_Cube(struct vk_rendertarg_cube *targ, uint32_t size, qboolean c
for (f = 0; f < 6; f++)
{
if (clear)
targ->face[f].restartinfo.renderPass = vk.renderpass[2];
targ->face[f].restartinfo.renderPass = VK_GetRenderPass(RP_FULLCLEAR|targ->face[f].rpassflags);
else
targ->face[f].restartinfo.renderPass = vk.renderpass[1]; //don't care
targ->face[f].restartinfo.renderPass = VK_GetRenderPass(RP_DEPTHCLEAR|targ->face[f].rpassflags); //don't care
targ->face[f].restartinfo.clearValueCount = 2;
}
@ -4972,7 +5026,7 @@ void VKBE_RT_Gen_Cube(struct vk_rendertarg_cube *targ, uint32_t size, qboolean c
VkFramebufferCreateInfo fbinfo = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
VkImageView attachments[2] = {targ->face[f].colour.view, targ->face[f].depth.view};
fbinfo.flags = 0;
fbinfo.renderPass = vk.renderpass[2];
fbinfo.renderPass = VK_GetRenderPass(RP_FULLCLEAR|targ->face[f].rpassflags);
fbinfo.attachmentCount = countof(attachments);
fbinfo.pAttachments = attachments;
fbinfo.width = size;
@ -5033,12 +5087,14 @@ void VKBE_RT_Begin(struct vk_rendertarg *targ)
targ->prevtarg = vk.rendertarg;
vk.rendertarg = targ;
VKBE_SelectMode(shaderstate.mode);
vkCmdBeginRenderPass(vk.rendertarg->cbuf, &targ->restartinfo, VK_SUBPASS_CONTENTS_INLINE);
//future reuse shouldn't clear stuff
if (targ->restartinfo.clearValueCount)
{
targ->depthcleared = true;
targ->restartinfo.renderPass = vk.renderpass[0];
targ->restartinfo.renderPass = VK_GetRenderPass(RP_RESUME|targ->rpassflags);
targ->restartinfo.clearValueCount = 0;
}
@ -5080,6 +5136,8 @@ void VKBE_RT_End(struct vk_rendertarg *targ)
// VK_Submit_Work(VkCommandBuffer cmdbuf, VkSemaphore semwait, VkPipelineStageFlags semwaitstagemask, VkSemaphore semsignal, VkFence fencesignal, struct vkframe *presentframe, struct vk_fencework *fencedwork)
#endif
VKBE_SelectMode(shaderstate.mode);
}
static qboolean BE_GenerateRefraction(batch_t *batch, shader_t *bs)
@ -5094,8 +5152,6 @@ static qboolean BE_GenerateRefraction(batch_t *batch, shader_t *bs)
return false;
if (shaderstate.mode != BEM_STANDARD && shaderstate.mode != BEM_DEPTHDARK)
return false;
if (vk.multisamplebits != VK_SAMPLE_COUNT_1_BIT)
return false; //multisample rendering can't deal with this.
oldbem = shaderstate.mode;
oldil = shaderstate.identitylighting;
// targ = vk.rendertarg;
@ -5901,12 +5957,6 @@ static void VK_TerminateShadowMap(void)
struct shadowmaps_s *shad;
unsigned int sbuf, i;
if (vk.shadow_renderpass != VK_NULL_HANDLE)
{
vkDestroyRenderPass(vk.device, vk.shadow_renderpass, vkallocationcb);
vk.shadow_renderpass = VK_NULL_HANDLE;
}
for (sbuf = 0; sbuf < countof(shaderstate.shadow); sbuf++)
{
shad = &shaderstate.shadow[sbuf];
@ -5945,7 +5995,7 @@ qboolean VKBE_BeginShadowmap(qboolean isspot, uint32_t width, uint32_t height)
unsigned int i;
VkFramebufferCreateInfo fbinfo = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
VkImageCreateInfo imginfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
imginfo.format = VK_FORMAT_D32_SFLOAT;
imginfo.format = vk.depthformat;
imginfo.flags = 0;
imginfo.imageType = VK_IMAGE_TYPE_2D;
imginfo.extent.width = width;
@ -5974,48 +6024,8 @@ qboolean VKBE_BeginShadowmap(qboolean isspot, uint32_t width, uint32_t height)
VkAssert(vkBindImageMemory(vk.device, shad->image, shad->memory, 0));
}
if (vk.shadow_renderpass == VK_NULL_HANDLE)
{
VkAttachmentReference depth_reference;
VkAttachmentDescription attachments[1] = {{0}};
VkSubpassDescription subpass = {0};
VkRenderPassCreateInfo rp_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
depth_reference.attachment = 0;
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[depth_reference.attachment].format = imginfo.format;
attachments[depth_reference.attachment].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[depth_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[depth_reference.attachment].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[depth_reference.attachment].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[depth_reference.attachment].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[depth_reference.attachment].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
attachments[depth_reference.attachment].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.flags = 0;
subpass.inputAttachmentCount = 0;
subpass.pInputAttachments = NULL;
subpass.colorAttachmentCount = 0;
subpass.pColorAttachments = NULL;
subpass.pResolveAttachments = NULL;
subpass.pDepthStencilAttachment = &depth_reference;
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = NULL;
rp_info.attachmentCount = countof(attachments);
rp_info.pAttachments = attachments;
rp_info.subpassCount = 1;
rp_info.pSubpasses = &subpass;
rp_info.dependencyCount = 0;
rp_info.pDependencies = NULL;
VkAssert(vkCreateRenderPass(vk.device, &rp_info, vkallocationcb, &vk.shadow_renderpass));
}
fbinfo.flags = 0;
fbinfo.renderPass = vk.shadow_renderpass;
fbinfo.renderPass = VK_GetRenderPass(RP_DEPTHONLY);
fbinfo.attachmentCount = 1;
fbinfo.width = width;
fbinfo.height = height;
@ -6059,7 +6069,7 @@ qboolean VKBE_BeginShadowmap(qboolean isspot, uint32_t width, uint32_t height)
}
shad->buf[i].qimage.vkimage = &shad->buf[i].vimage;
shad->buf[i].vimage.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
shad->buf[i].vimage.layout = VK_IMAGE_LAYOUT_UNDEFINED;
fbinfo.pAttachments = &shad->buf[i].vimage.view;
VkAssert(vkCreateFramebuffer(vk.device, &fbinfo, vkallocationcb, &shad->buf[i].framebuffer));
@ -6086,7 +6096,7 @@ qboolean VKBE_BeginShadowmap(qboolean isspot, uint32_t width, uint32_t height)
imgbarrier.subresourceRange.layerCount = 1;
imgbarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imgbarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkCmdPipelineBarrier(vk.rendertarg->cbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &imgbarrier);
vkCmdPipelineBarrier(vk.rendertarg->cbuf, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT|VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imgbarrier);
}
{
@ -6094,7 +6104,7 @@ qboolean VKBE_BeginShadowmap(qboolean isspot, uint32_t width, uint32_t height)
VkRenderPassBeginInfo rpass = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
clearval.depthStencil.depth = 1;
clearval.depthStencil.stencil = 0;
rpass.renderPass = vk.shadow_renderpass;
rpass.renderPass = VK_GetRenderPass(RP_DEPTHONLY);
rpass.framebuffer = shad->buf[sbuf].framebuffer;
rpass.renderArea.offset.x = 0;
rpass.renderArea.offset.y = 0;
@ -6206,6 +6216,9 @@ void VKBE_BeginShadowmapFace(void)
wrekt.extent.width = viewport.width;
wrekt.extent.height = viewport.height;
vkCmdSetScissor(vk.rendertarg->cbuf, 0, 1, &wrekt);
//shadowmaps never multisample...
shaderstate.modepermutation &= ~(PERMUTATION_BEM_MULTISAMPLE|PERMUTATION_BEM_FP16);
}
#endif

View file

@ -74,8 +74,8 @@ static int VK_Submit_Thread(void *arg);
#endif
static void VK_Submit_DoWork(void);
static void VK_DestroyRenderPass(void);
static void VK_CreateRenderPass(void);
static void VK_DestroyRenderPasses(void);
VkRenderPass VK_GetRenderPass(int pass);
static void VK_Shutdown_PostProc(void);
struct vulkaninfo_s vk;
@ -140,6 +140,19 @@ char *VK_VKErrorToString(VkResult err)
case VK_ERROR_OUT_OF_POOL_MEMORY_KHR: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR";
case VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR: return "VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR";
#ifdef VK_EXT_image_drm_format_modifier
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR";
#endif
#ifdef VK_EXT_descriptor_indexing
case VK_ERROR_FRAGMENTATION_EXT: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR";
#endif
#ifdef VK_EXT_global_priority
case VK_ERROR_NOT_PERMITTED_EXT: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR";
#endif
#ifdef VK_EXT_buffer_device_address
case VK_ERROR_INVALID_DEVICE_ADDRESS_EXT: return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR";
#endif
//irrelevant parts of the enum
case VK_RESULT_RANGE_SIZE:
case VK_RESULT_MAX_ENUM:
@ -206,6 +219,9 @@ char *DebugAnnotObjectToString(VkObjectType t)
case VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX: return "VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX";
case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT: return "VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT";
case VK_OBJECT_TYPE_VALIDATION_CACHE_EXT: return "VK_OBJECT_TYPE_VALIDATION_CACHE_EXT";
#ifdef VK_NV_ray_tracing
case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV: return "VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV";
#endif
case VK_OBJECT_TYPE_RANGE_SIZE:
case VK_OBJECT_TYPE_MAX_ENUM:
break;
@ -489,6 +505,7 @@ static qboolean VK_CreateSwapChain(void)
VkImageView attachments[3];
VkFramebufferCreateInfo fb_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
VkSampleCountFlagBits oldms;
uint32_t rpassflags = 0;
VkFormat oldformat = vk.backbufformat;
VkFormat olddepthformat = vk.depthformat;
@ -790,7 +807,7 @@ static qboolean VK_CreateSwapChain(void)
if (vk.backbufformat != swapinfo.imageFormat)
{
VK_DestroyRenderPass();
VK_DestroyRenderPasses();
reloadshaders = true;
}
vk.backbufformat = swapinfo.imageFormat;
@ -865,25 +882,24 @@ static qboolean VK_CreateSwapChain(void)
oldms = vk.multisamplebits;
vk.multisamplebits = VK_SAMPLE_COUNT_1_BIT;
#ifdef _DEBUG
if (vid_multisample.ival>1)
{
VkSampleCountFlags fl = vk.limits.framebufferColorSampleCounts & vk.limits.framebufferDepthSampleCounts;
Con_Printf("Warning: vulkan multisample does not work with rtlights or render targets etc etc\n");
// Con_Printf("Warning: vulkan multisample does not work with rtlights or render targets etc etc\n");
for (i = 1; i < 30; i++)
if ((fl & (1<<i)) && (1<<i) <= vid_multisample.ival)
vk.multisamplebits = (1<<i);
}
#endif
rpassflags = RP_PRESENTABLE;
//destroy+recreate the renderpass if something changed that prevents them being compatible (this also requires rebuilding all the pipelines too, which sucks).
if (oldms != vk.multisamplebits || oldformat != vk.backbufformat || olddepthformat != vk.depthformat)
{
VK_DestroyRenderPass();
VK_DestroyRenderPasses();
reloadshaders = true;
}
VK_CreateRenderPass();
if (reloadshaders)
{
Shader_NeedReload(true);
@ -894,11 +910,14 @@ static qboolean VK_CreateSwapChain(void)
attachments[1] = VK_NULL_HANDLE; //depth
attachments[2] = VK_NULL_HANDLE; //mscolour
fb_info.renderPass = vk.renderpass[0];
if (vk.multisamplebits != VK_SAMPLE_COUNT_1_BIT)
if (rpassflags & RP_MULTISAMPLE)
fb_info.attachmentCount = 3;
else
{
rpassflags &= ~RP_PRESENTABLE;
fb_info.attachmentCount = 2;
}
fb_info.renderPass = VK_GetRenderPass(RP_FULLCLEAR|rpassflags);
fb_info.pAttachments = attachments;
fb_info.width = swapinfo.imageExtent.width;
fb_info.height = swapinfo.imageExtent.height;
@ -948,7 +967,7 @@ static qboolean VK_CreateSwapChain(void)
depthinfo.extent.depth = 1;
depthinfo.mipLevels = 1;
depthinfo.arrayLayers = 1;
depthinfo.samples = vk.multisamplebits;
depthinfo.samples = (rpassflags & RP_MULTISAMPLE)?vk.multisamplebits:VK_SAMPLE_COUNT_1_BIT;
depthinfo.tiling = VK_IMAGE_TILING_OPTIMAL;
depthinfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
depthinfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
@ -984,7 +1003,7 @@ static qboolean VK_CreateSwapChain(void)
}
//if we're using multisampling, create the intermediate multisample texture that we're actually going to render to.
if (vk.multisamplebits != VK_SAMPLE_COUNT_1_BIT)
if (rpassflags & RP_MULTISAMPLE)
{
//mscolour image
{
@ -1047,6 +1066,7 @@ static qboolean VK_CreateSwapChain(void)
vid.pixelwidth = swapinfo.imageExtent.width;
vid.pixelheight = swapinfo.imageExtent.height;
R2D_Console_Resize();
return true;
}
@ -1127,7 +1147,7 @@ void VK_UpdateFiltering(image_t *imagelist, int filtermip[3], int filterpic[3],
for (i = 0; i < countof(vk.mipcap); i++)
vk.mipcap[i] = mipcap[i];
vk.lodbias = lodbias;
vk.max_anistophy = bound(1.0, anis, vk.max_anistophy_limit);
vk.max_anistophy = bound(1.0, anis, vk.limits.maxSamplerAnisotropy);
while(imagelist)
{
@ -1562,6 +1582,7 @@ void *VK_FencedBegin(void (*passed)(void *work), size_t worksize)
cbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cbai.commandBufferCount = 1;
VkAssert(vkAllocateCommandBuffers(vk.device, &cbai, &w->cbuf));
DebugSetName(VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)w->cbuf, "VK_FencedBegin");
cmdinf.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
cmdinf.pInheritanceInfo = &cmdinh;
vkBeginCommandBuffer(w->cbuf, &cmdinf);
@ -1996,7 +2017,7 @@ void VK_Set2D(void)
VkClearValue clearvalues[1];
clearvalues[0].depthStencil.depth = 1.0;
clearvalues[0].depthStencil.stencil = 0;
rpiinfo.renderPass = vk.renderpass[1];
rpiinfo.renderPass = VK_GetRenderPass(RP_CLEARDEPTH);
rpiinfo.renderArea.offset.x = r_refdef.pxrect.x;
rpiinfo.renderArea.offset.y = r_refdef.pxrect.y;
rpiinfo.renderArea.extent.width = r_refdef.pxrect.width;
@ -2503,10 +2524,13 @@ void VK_R_RenderView (void)
if (R_CanBloom())
r_refdef.flags |= RDF_BLOOM;
if (vid_hardwaregamma.ival == 4 && (v_gamma.value!=1||v_contrast.value!=1||v_contrastboost.value!=1||v_brightness.value!=0))
r_refdef.flags |= RDF_SCENEGAMMA;
}
if (vk.multisamplebits != VK_SAMPLE_COUNT_1_BIT) //these are unsupported right now.
r_refdef.flags &= ~(RDF_CUSTOMPOSTPROC|RDF_ANTIALIAS|RDF_BLOOM);
// if (vk.multisamplebits != VK_SAMPLE_COUNT_1_BIT) //these are unsupported right now.
// r_refdef.flags &= ~(RDF_CUSTOMPOSTPROC|RDF_ANTIALIAS|RDF_BLOOM);
//
// figure out the viewport
@ -2534,7 +2558,7 @@ void VK_R_RenderView (void)
r_refdef.pxrect.maxheight = vid.pixelheight;
}
if (renderscale != 1.0)
if (renderscale != 1.0 || vk.multisamplebits != VK_SAMPLE_COUNT_1_BIT)
{
r_refdef.flags |= RDF_RENDERSCALE;
if (renderscale < 0)
@ -2551,11 +2575,16 @@ void VK_R_RenderView (void)
//FIXME: if we're meant to be using msaa, render the scene to an msaa target and then resolve.
postproc_buf = 0;
if (r_refdef.flags & (RDF_ALLPOSTPROC|RDF_RENDERSCALE))
if (r_refdef.flags & (RDF_ALLPOSTPROC|RDF_RENDERSCALE|RDF_SCENEGAMMA))
{
r_refdef.pxrect.x = 0;
r_refdef.pxrect.y = 0;
rt = &postproc[postproc_buf++%countof(postproc)];
rt->rpassflags = 0;
if (vk.multisamplebits!=VK_SAMPLE_COUNT_1_BIT)
rt->rpassflags |= RP_MULTISAMPLE;
if (r_refdef.flags&RDF_SCENEGAMMA) //if we're doing scenegamma here, use an fp16 target for extra precision
rt->rpassflags |= RP_FP16;
VKBE_RT_Gen(rt, r_refdef.pxrect.width, r_refdef.pxrect.height, false, (r_renderscale.value < 0)?RT_IMAGEFLAGS-IF_LINEAR+IF_NEAREST:RT_IMAGEFLAGS);
}
else
@ -2631,6 +2660,40 @@ void VK_R_RenderView (void)
if (!vk.scenepp_waterwarp)
VK_Init_PostProc();
//FIXME: chain renderpasses as required.
if (r_refdef.flags & RDF_SCENEGAMMA)
{
shader_t *s = R_RegisterShader("fte_scenegamma", 0,
"{\n"
"program defaultgammacb\n"
"affine\n"
"{\n"
"map $sourcecolour\n"
"nodepthtest\n"
"}\n"
"}\n"
);
r_refdef.flags &= ~RDF_SCENEGAMMA;
vk.sourcecolour = &rt->q_colour;
if (r_refdef.flags & RDF_ALLPOSTPROC)
{
rt = &postproc[postproc_buf++];
rt->rpassflags = 0;
VKBE_RT_Gen(rt, 320, 200, false, RT_IMAGEFLAGS);
}
else
rt = rtscreen;
if (rt != rtscreen)
VKBE_RT_Begin(rt);
R2D_ImageColours (v_gammainverted.ival?v_gamma.value:(1/v_gamma.value), v_contrast.value, v_brightness.value, v_contrastboost.value);
R2D_Image(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, 0, 0, 1, 1, s);
R2D_ImageColours (1, 1, 1, 1);
R2D_Flush();
if (rt != rtscreen)
VKBE_RT_End(rt);
}
if (r_refdef.flags & RDF_WATERWARP)
{
r_refdef.flags &= ~RDF_WATERWARP;
@ -2638,6 +2701,7 @@ void VK_R_RenderView (void)
if (r_refdef.flags & RDF_ALLPOSTPROC)
{
rt = &postproc[postproc_buf++];
rt->rpassflags = 0;
VKBE_RT_Gen(rt, 320, 200, false, RT_IMAGEFLAGS);
}
else
@ -2656,6 +2720,7 @@ void VK_R_RenderView (void)
if (r_refdef.flags & RDF_ALLPOSTPROC)
{
rt = &postproc[postproc_buf++];
rt->rpassflags = 0;
VKBE_RT_Gen(rt, 320, 200, false, RT_IMAGEFLAGS);
}
else
@ -2675,6 +2740,7 @@ void VK_R_RenderView (void)
if (r_refdef.flags & RDF_ALLPOSTPROC)
{
rt = &postproc[postproc_buf++];
rt->rpassflags = 0;
VKBE_RT_Gen(rt, 320, 200, false, RT_IMAGEFLAGS);
}
else
@ -3132,6 +3198,7 @@ VkCommandBuffer VK_AllocFrameCBuf(void)
cbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cbai.commandBufferCount = frame->maxcbufs - frame->numcbufs;
VkAssert(vkAllocateCommandBuffers(vk.device, &cbai, frame->cbufs+frame->numcbufs));
DebugSetName(VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)frame->cbufs[frame->numcbufs], "VK_AllocFrameCBuf");
}
return frame->cbufs[frame->numcbufs++];
}
@ -3192,11 +3259,23 @@ qboolean VK_SCR_GrabBackBuffer(void)
else
{
//friendly wait
VkResult err = vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX);
if (err)
int failures = 0;
for(;;)
{
if (err == VK_ERROR_DEVICE_LOST)
VkResult err = vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, 1000000000);
if (err == VK_SUCCESS)
break;
else if (err == VK_TIMEOUT)
{
if (++failures == 5)
Sys_Error("waiting for fence for over 5 seconds. Assuming bug.");
continue;
}
else if (err == VK_ERROR_DEVICE_LOST)
Sys_Error("Vulkan device lost");
else if (err != VK_ERROR_OUT_OF_HOST_MEMORY && err != VK_ERROR_OUT_OF_DEVICE_MEMORY)
Sys_Error("vkWaitForFences returned unspecified result: %s", VK_VKErrorToString(err));
return false;
}
}
@ -3250,7 +3329,7 @@ qboolean VK_SCR_GrabBackBuffer(void)
// vkCmdWriteTimestamp(vk.frame->cbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, querypool, vk.bufferidx*2+0);
if (vk.multisamplebits == VK_SAMPLE_COUNT_1_BIT)
if (!(vk.rendertarg->rpassflags & RP_PRESENTABLE))
{
VkImageMemoryBarrier imgbarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
imgbarrier.pNext = NULL;
@ -3271,7 +3350,6 @@ qboolean VK_SCR_GrabBackBuffer(void)
imgbarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imgbarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imgbarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vk.frame->backbuf->firstuse = false;
}
vk.rendertarg->colour.layout = imgbarrier.newLayout;
vkCmdPipelineBarrier(vk.rendertarg->cbuf, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &imgbarrier);
@ -3295,6 +3373,7 @@ qboolean VK_SCR_GrabBackBuffer(void)
}
{
int rp = vk.frame->backbuf->rpassflags;
VkClearValue clearvalues[3];
extern cvar_t r_clear;
VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
@ -3308,7 +3387,7 @@ qboolean VK_SCR_GrabBackBuffer(void)
clearvalues[1].depthStencil.depth = 1.0;
clearvalues[1].depthStencil.stencil = 0;
if (vk.multisamplebits != VK_SAMPLE_COUNT_1_BIT)
if (rp & RP_MULTISAMPLE)
{
clearvalues[2].color.float32[0] = !!(r_clear.ival & 1);
clearvalues[2].color.float32[1] = !!(r_clear.ival & 2);
@ -3319,10 +3398,10 @@ qboolean VK_SCR_GrabBackBuffer(void)
else
rpbi.clearValueCount = 2;
if (r_clear.ival)
rpbi.renderPass = vk.renderpass[2];
if (r_clear.ival || vk.frame->backbuf->firstuse)
rpbi.renderPass = VK_GetRenderPass(RP_FULLCLEAR|rp);
else
rpbi.renderPass = vk.renderpass[1]; //may still clear
rpbi.renderPass = VK_GetRenderPass(RP_DEPTHCLEAR|rp);
rpbi.framebuffer = vk.frame->backbuf->framebuffer;
rpbi.renderArea.offset.x = 0;
rpbi.renderArea.offset.y = 0;
@ -3336,10 +3415,11 @@ qboolean VK_SCR_GrabBackBuffer(void)
rpbi.clearValueCount = 0;
rpbi.pClearValues = NULL;
rpbi.renderPass = vk.renderpass[0];
rpbi.renderPass = VK_GetRenderPass(RP_RESUME|rp);
vk.rendertarg->restartinfo = rpbi;
vk.rendertarg->depthcleared = true;
}
vk.frame->backbuf->firstuse = false;
return true;
}
@ -3495,7 +3575,7 @@ qboolean VK_SCR_UpdateScreen (void)
vkCmdCopyImageToBuffer(vk.frame->cbuf, vk.frame->backbuf->colour.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1, &region);
}*/
if (vk.multisamplebits == VK_SAMPLE_COUNT_1_BIT)
if (!(vk.frame->backbuf->rpassflags & RP_PRESENTABLE))
{
VkImageMemoryBarrier imgbarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
imgbarrier.pNext = NULL;
@ -3553,7 +3633,7 @@ void VKBE_RenderToTextureUpdate2d(qboolean destchanged)
{
}
static void VK_DestroyRenderPass(void)
static void VK_DestroyRenderPasses(void)
{
int i;
for (i = 0; i < countof(vk.renderpass); i++)
@ -3565,112 +3645,127 @@ static void VK_DestroyRenderPass(void)
}
}
}
static void VK_CreateRenderPass(void)
VkRenderPass VK_GetRenderPass(int pass)
{
int pass;
int numattachments;
static VkAttachmentReference color_reference;
static VkAttachmentReference depth_reference;
static VkAttachmentReference resolve_reference;
static VkAttachmentDescription attachments[3] = {{0}};
static VkSubpassDescription subpass = {0};
static VkRenderPassCreateInfo rp_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
static VkAttachmentReference color_reference;
static VkAttachmentReference depth_reference;
static VkAttachmentReference resolve_reference;
static VkAttachmentDescription attachments[3] = {{0}};
static VkSubpassDescription subpass = {0};
static VkRenderPassCreateInfo rp_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
//two render passes are compatible for piplines when they match exactly except for:
//initial and final layouts in attachment descriptions.
//load and store operations in attachment descriptions.
//image layouts in attachment references.
if (vk.multisamplebits == VK_SAMPLE_COUNT_1_BIT)
pass &= ~RP_MULTISAMPLE; //no difference
for (pass = 0; pass < 3; pass++)
if (vk.renderpass[pass] != VK_NULL_HANDLE)
return vk.renderpass[pass]; //already built
numattachments = 0;
if ((pass&3)==RP_DEPTHONLY)
color_reference.attachment = ~(uint32_t)0; //no colour buffer...
else
color_reference.attachment = numattachments++;
depth_reference.attachment = numattachments++;
resolve_reference.attachment = ~(uint32_t)0;
if ((pass & RP_MULTISAMPLE) && color_reference.attachment != ~(uint32_t)0)
{ //if we're using multisample, then render to a third texture, with a resolve to the original colour texture.
resolve_reference.attachment = color_reference.attachment;
color_reference.attachment = numattachments++;
}
color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
resolve_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
if (color_reference.attachment != ~(uint32_t)0)
{
if (vk.renderpass[pass] != VK_NULL_HANDLE)
continue;
numattachments = 0;
if (vk.multisamplebits != VK_SAMPLE_COUNT_1_BIT)
{
resolve_reference.attachment = numattachments++;
depth_reference.attachment = numattachments++;
color_reference.attachment = numattachments++;
}
else
{
color_reference.attachment = numattachments++;
depth_reference.attachment = numattachments++;
resolve_reference.attachment = ~(uint32_t)0;
}
color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
resolve_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[color_reference.attachment].format = vk.backbufformat;
attachments[color_reference.attachment].samples = vk.multisamplebits;
attachments[color_reference.attachment].format = (pass&RP_FP16)?VK_FORMAT_R16G16B16A16_SFLOAT:vk.backbufformat;
attachments[color_reference.attachment].samples = (pass & RP_MULTISAMPLE)?vk.multisamplebits:VK_SAMPLE_COUNT_1_BIT;
// attachments[color_reference.attachment].loadOp = pass?VK_ATTACHMENT_LOAD_OP_LOAD:VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[color_reference.attachment].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[color_reference.attachment].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[color_reference.attachment].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[color_reference.attachment].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[color_reference.attachment].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
if (depth_reference.attachment != ~(uint32_t)0)
{
attachments[depth_reference.attachment].format = vk.depthformat;
attachments[depth_reference.attachment].samples = vk.multisamplebits;
attachments[depth_reference.attachment].samples = (pass & RP_MULTISAMPLE)?vk.multisamplebits:VK_SAMPLE_COUNT_1_BIT;
// attachments[depth_reference.attachment].loadOp = pass?VK_ATTACHMENT_LOAD_OP_LOAD:VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[depth_reference.attachment].storeOp = VK_ATTACHMENT_STORE_OP_STORE;//VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[depth_reference.attachment].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[depth_reference.attachment].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[depth_reference.attachment].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[depth_reference.attachment].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
if (resolve_reference.attachment != ~(uint32_t)0)
{
attachments[resolve_reference.attachment].format = vk.backbufformat;
attachments[resolve_reference.attachment].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[resolve_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[resolve_reference.attachment].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[resolve_reference.attachment].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[resolve_reference.attachment].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[resolve_reference.attachment].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[resolve_reference.attachment].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
}
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.flags = 0;
subpass.inputAttachmentCount = 0;
subpass.pInputAttachments = NULL;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_reference;
subpass.pResolveAttachments = (resolve_reference.attachment != ~(uint32_t)0)?&resolve_reference:NULL;
subpass.pDepthStencilAttachment = &depth_reference;
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = NULL;
rp_info.attachmentCount = numattachments;
rp_info.pAttachments = attachments;
rp_info.subpassCount = 1;
rp_info.pSubpasses = &subpass;
rp_info.dependencyCount = 0;
rp_info.pDependencies = NULL;
if (pass == 0)
{ //nothing cleared, both are just re-loaded.
attachments[color_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[depth_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
}
else if (pass == 1)
{ //depth cleared, colour is whatever.
attachments[color_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[depth_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
}
else
{ //both cleared
attachments[color_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[depth_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
}
VkAssert(vkCreateRenderPass(vk.device, &rp_info, vkallocationcb, &vk.renderpass[pass]));
}
if (resolve_reference.attachment != ~(uint32_t)0)
{
attachments[resolve_reference.attachment].format = vk.backbufformat;
attachments[resolve_reference.attachment].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[resolve_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[resolve_reference.attachment].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[resolve_reference.attachment].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[resolve_reference.attachment].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[resolve_reference.attachment].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[resolve_reference.attachment].finalLayout = (pass&RP_PRESENTABLE)?VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.flags = 0;
subpass.inputAttachmentCount = 0;
subpass.pInputAttachments = NULL;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_reference;
subpass.pResolveAttachments = (resolve_reference.attachment != ~(uint32_t)0)?&resolve_reference:NULL;
subpass.pDepthStencilAttachment = &depth_reference;
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = NULL;
rp_info.attachmentCount = numattachments;
rp_info.pAttachments = attachments;
rp_info.subpassCount = 1;
rp_info.pSubpasses = &subpass;
rp_info.dependencyCount = 0;
rp_info.pDependencies = NULL;
switch(pass&3)
{
case RP_RESUME:
//nothing cleared, both are just re-loaded.
attachments[color_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[depth_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
break;
case RP_DEPTHCLEAR:
//depth cleared, colour is whatever.
attachments[depth_reference.attachment].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[color_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[depth_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
break;
case RP_FULLCLEAR:
//both cleared
attachments[color_reference.attachment].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[depth_reference.attachment].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[color_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[depth_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
break;
case RP_DEPTHONLY:
attachments[depth_reference.attachment].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
// attachments[color_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[depth_reference.attachment].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
}
VkAssert(vkCreateRenderPass(vk.device, &rp_info, vkallocationcb, &vk.renderpass[pass]));
DebugSetName(VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)vk.renderpass[pass], va("RP%i", pass));
return vk.renderpass[pass];
}
void VK_DoPresent(struct vkframe *theframe)
@ -4031,7 +4126,6 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
vk.triplebuffer = info->triplebuffer;
vk.vsync = info->wait;
vk.dopresent = dopresent?dopresent:VK_DoPresent;
vk.max_anistophy_limit = 1.0;
memset(&sh_config, 0, sizeof(sh_config));
@ -4063,6 +4157,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
vkEnumerateInstanceExtensionProperties(NULL, &count, ext);
for (i = 0; i < count && extensions_count < countof(extensions); i++)
{
Con_DLPrintf(2, " vki: %s\n", ext[i].extensionName);
#ifdef VK_EXT_debug_utils
if (!strcmp(ext[i].extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME))
havedebugutils = true;
@ -4424,11 +4519,13 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
}
{
uint32_t extcount = 0;
uint32_t extcount = 0, i;
VkExtensionProperties *ext;
vkEnumerateDeviceExtensionProperties(vk.gpu, NULL, &extcount, NULL);
ext = malloc(sizeof(*ext)*extcount);
vkEnumerateDeviceExtensionProperties(vk.gpu, NULL, &extcount, ext);
for (i = 0; i < extcount; i++)
Con_DLPrintf(2, " vkd: %s\n", ext[i].extensionName);
while (extcount --> 0)
{
for (e = 0; e < countof(knowndevexts); e++)
@ -4694,7 +4791,7 @@ void VK_Shutdown(void)
if (vk.cmdpool)
vkDestroyCommandPool(vk.device, vk.cmdpool, vkallocationcb);
VK_DestroyRenderPass();
VK_DestroyRenderPasses();
if (vk.pipelinecache)
{

View file

@ -246,7 +246,7 @@ struct vk_rendertarg
uint32_t width;
uint32_t height;
qboolean multisample;
uint32_t rpassflags;
qboolean depthcleared; //starting a new gameview needs cleared depth relative to other views, but the first probably won't.
VkRenderPassBeginInfo restartinfo;
@ -315,8 +315,7 @@ extern struct vulkaninfo_s
int filterpic[3];
int mipcap[2];
float lodbias;
float max_anistophy;
float max_anistophy_limit;
float max_anistophy; //limits.maxSamplerAnistrophy
struct vk_mempool_s
{
@ -375,8 +374,14 @@ extern struct vulkaninfo_s
struct vk_frameend *frameendjobs;
uint32_t backbuf_count;
VkRenderPass shadow_renderpass; //clears depth etc.
VkRenderPass renderpass[3]; //reload-both(resume prior renderpass), clear-depth-dontcare-colour(gl_clear==0), clear-both(cl_clear!=0)
#define RP_RESUME 0
#define RP_DEPTHCLEAR 1 //
#define RP_FULLCLEAR 2
#define RP_DEPTHONLY 3 //shadowmaps (clears depth)
#define RP_MULTISAMPLE (1u<<2)
#define RP_PRESENTABLE (1u<<3)
#define RP_FP16 (1u<<4)
VkRenderPass renderpass[1u<<5];
VkSwapchainKHR swapchain;
uint32_t bufferidx;
@ -525,6 +530,7 @@ char *VKVID_GetRGBInfo (int *bytestride, int *truevidwidth, int *truevidheight
qboolean VK_SCR_UpdateScreen (void);
void VKBE_RenderToTextureUpdate2d(qboolean destchanged);
VkRenderPass VK_GetRenderPass(int pass);
//improved rgb get that calls the callback when the data is actually available. used for video capture.
void VKVID_QueueGetRGBData (void (*gotrgbdata) (void *rgbdata, qintptr_t bytestride, size_t width, size_t height, enum uploadfmt fmt));

View file

@ -682,6 +682,8 @@ qintptr_t Plug_Init(qintptr_t *args)
Plug_Export("ConExecuteCommand", QI_ConExecuteCommand) &&
Plug_Export("ConsoleLink", QI_ConsoleLink))
{
if (!BUILTINISVALID(MapLog_Query))
Con_Printf("QI: Engine does not support map times\n");
pCmd_AddCommand("qi");
pCmd_AddCommand("quaddicted");
return true;