Fix potentially serious vulkan performance issue.

Stripped obsolete vk_nv_dedicated_allocation extension.
Misc fixes for warnings.
Linux now defaults to using ~/.local/share/fte instead of ~/.fte for greater consistency.
Other misc linux tweaks.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5267 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2018-06-18 16:44:29 +00:00
parent 6766b8af55
commit b7784f41d9
51 changed files with 736 additions and 596 deletions

View File

@ -890,8 +890,12 @@ GLB_DIR=gl_$(FTE_FULLTARGET)
GLCL_DIR=glcl_$(FTE_FULLTARGET)
SV_DIR?=sv_$(FTE_FULLTARGET)
VKCL_OBJS=$(VKQUAKE_OBJS) $(BOTLIB_OBJS) snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o snd_directx.o $(D3DGL_OBJS) $(LTO_END)
VKCL_OBJS=$(VKQUAKE_OBJS) $(D3DGL_OBJS) gl_bloom.o $(BOTLIB_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o
VK_CFLAGS=-DFTE_SDL $(VKCFLAGS) `$(SDLCONFIG) --cflags`
VKB_DIR=vk_$(FTE_FULLTARGET)
VKCL_DIR=vk_$(FTE_FULLTARGET)
VK_EXE_NAME=../$(EXE_NAME)-vk$(FTE_FULLTARGET)
VKCL_EXE_NAME=../$(EXE_NAME)-vkcl$(FTE_FULLTARGET)
SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(SERVERONLY_OBJS) $(BOTLIB_OBJS)
SV_EXE_NAME=../$(EXE_NAME)-sv$(FTE_FULLTARGET)

View File

@ -1863,10 +1863,9 @@ void CL_SendCmd (double frametime, qboolean mainloop)
#ifndef CLIENTONLY
if (sv.state && cls.state != ca_active)
{
fullsend = -1;
{ //HACK: if we're also the server, spam like a crazy person until we're on the server, for faster apparent load times.
fullsend = -1; //send no movement command.
msecstouse = usetime = msecs;
msecs = 0;
}
else
#endif

View File

@ -1619,7 +1619,7 @@ void CL_ClearState (void)
#ifdef Q2CLIENT
for (i = 0; i < countof(cl.configstring_general); i++)
{
if (cl.configstring_general)
if (cl.configstring_general[i])
Z_Free(cl.configstring_general[i]);
}
#endif

View File

@ -4242,7 +4242,7 @@ static void CLQ2_ParseConfigString (void)
return;
}
if (i < 0 || i >= Q2MAX_CONFIGSTRINGS)
if ((unsigned int)i >= Q2MAX_CONFIGSTRINGS)
Host_EndGame ("configstring > Q2MAX_CONFIGSTRINGS");
// strncpy (olds, cl.configstrings[i], sizeof(olds));
@ -7937,7 +7937,7 @@ void CLNQ_ParseServerMessage (void)
break;
case svcdp_updatestatbyte:
//case svcneh_fog:
if (CPNQ_IS_BJP || cls.protocol_nq == PROTOCOL_VERSION_NEHD)
if (CPNQ_IS_BJP || cls.protocol_nq == CPNQ_NEHAHRA)
{
CL_ResetFog(0);
if (MSG_ReadByte())

View File

@ -1085,9 +1085,9 @@ static void CLQ2_DeltaEntity (q2frame_t *frame, int newnum, entity_state_t *old,
|| state->modelindex2 != ent->current.modelindex2
|| state->u.q2.modelindex3 != ent->current.u.q2.modelindex3
|| state->u.q2.modelindex4 != ent->current.u.q2.modelindex4
|| abs(state->origin[0] - ent->current.origin[0]) > 512
|| abs(state->origin[1] - ent->current.origin[1]) > 512
|| abs(state->origin[2] - ent->current.origin[2]) > 512
|| fabs(state->origin[0] - ent->current.origin[0]) > 512
|| fabs(state->origin[1] - ent->current.origin[1]) > 512
|| fabs(state->origin[2] - ent->current.origin[2]) > 512
|| state->u.q2.event == Q2EV_PLAYER_TELEPORT
|| state->u.q2.event == Q2EV_OTHER_TELEPORT
)
@ -2442,7 +2442,7 @@ void CLQ2_CalcViewValues (int seat)
ops = &oldframe->playerstate[seat];
// see if the player entity was teleported this frame
if ( fabs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8
if ( abs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8
|| abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256*8
|| abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256*8)
ops = ps; // don't interpolate

View File

@ -2197,7 +2197,8 @@ static qbyte *ReadRawBMPFile(qbyte *buf, int length, int *width, int *height, si
data32[i] = pal[buf[x]];
i++;
}
buf += h.Width;
//BMP rows are 32-bit aligned.
buf += (h.Width+3)&~3;
}
if (!OffsetofBMPBits)

View File

@ -3128,7 +3128,7 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor
info->maxplayers = bound(0, ping, 255);
ping = atoi(Info_ValueForKey(msg, "timelimit"));
info->tl = bound(-327678, ping, 32767);
info->tl = bound(-32768, ping, 32767);
ping = atoi(Info_ValueForKey(msg, "fraglimit"));
info->fl = bound(-32768, ping, 32767);

View File

@ -1188,7 +1188,8 @@ int menuentsize;
// cvars
#define MENUPROGSGROUP "Menu progs control"
cvar_t forceqmenu = CVAR("forceqmenu", "0");
cvar_t pr_menuqc_coreonerror = CVAR("pr_menuqc_coreonerror", "1");
cvar_t pr_menu_coreonerror = CVAR("pr_menu_coreonerror", "1");
cvar_t pr_menu_memsize = CVAR("pr_menu_memsize", "64m");
//new generic functions.
@ -2447,7 +2448,7 @@ void VARGS Menu_Abort (char *format, ...)
Con_Printf("Menu_Abort: %s\nShutting down menu.dat\n", string);
if (pr_menuqc_coreonerror.value)
if (pr_menu_coreonerror.value)
{
char *buffer;
size_t size = 1024*1024*8;
@ -2585,7 +2586,7 @@ qboolean MP_Init (void)
int mprogs;
Con_DPrintf("Initializing menu.dat\n");
menu_world.progs = InitProgs(&menuprogparms);
PR_Configure(menu_world.progs, 64*1024*1024, 1, pr_enable_profiling.ival);
PR_Configure(menu_world.progs, PR_ReadBytesString(pr_menu_memsize.string), 1, pr_enable_profiling.ival);
mprogs = PR_LoadProgs(menu_world.progs, "menu.dat");
if (mprogs < 0) //no per-progs builtins.
{
@ -2746,7 +2747,8 @@ void MP_RegisterCvarsAndCmds(void)
Cvar_Register(&forceqmenu, MENUPROGSGROUP);
Cvar_Register(&pr_menuqc_coreonerror, MENUPROGSGROUP);
Cvar_Register(&pr_menu_coreonerror, MENUPROGSGROUP);
Cvar_Register(&pr_menu_memsize, MENUPROGSGROUP);
if (COM_CheckParm("-qmenu"))
Cvar_Set(&forceqmenu, "1");

View File

@ -463,15 +463,16 @@ cvar_t gl_screenangle = CVAR("gl_screenangle", "0");
#ifdef VKQUAKE
cvar_t vk_stagingbuffers = CVARD ("vk_stagingbuffers", "", "Configures which dynamic buffers are copied into gpu memory for rendering, instead of reading from shared memory. Empty for default settings.\nAccepted chars are u, e, v, 0.");
cvar_t vk_submissionthread = CVARD ("vk_submissionthread", "", "Execute submits+presents on a thread dedicated to executing them. This may be a significant speedup on certain drivers.");
cvar_t vk_debug = CVARD ("vk_debug", "0", "Register a debug handler to display driver/layer messages. 2 enables the standard validation layers.");
cvar_t vk_dualqueue = CVARD ("vk_dualqueue", "", "Attempt to use a separate queue for presentation. Blank for default.");
cvar_t vk_debug = CVARFD("vk_debug", "0", CVAR_VIDEOLATCH, "Register a debug handler to display driver/layer messages. 2 enables the standard validation layers.");
cvar_t vk_dualqueue = CVARFD("vk_dualqueue", "", CVAR_VIDEOLATCH, "Attempt to use a separate queue for presentation. Blank for default.");
cvar_t vk_busywait = CVARD ("vk_busywait", "", "Force busy waiting until the GPU finishes doing its thing.");
cvar_t vk_waitfence = CVARD ("vk_waitfence", "", "Waits on fences, instead of semaphores. This is more likely to result in gpu stalls while the cpu waits.");
cvar_t vk_nv_glsl_shader = CVARD ("vk_loadglsl", "", "Enable direct loading of glsl, where supported by drivers. Do not use in combination with vk_debug 2 (vk_debug should be 1 if you want to see any glsl compile errors). Don't forget to do a vid_restart after.");
cvar_t vk_nv_dedicated_allocation = CVARD ("vk_nv_dedicated_allocation", "", "Flag vulkan memory allocations as dedicated, where applicable.");
cvar_t vk_khr_dedicated_allocation = CVARD ("vk_khr_dedicated_allocation", "", "Flag vulkan memory allocations as dedicated, where applicable.");
cvar_t vk_khr_push_descriptor = CVARD ("vk_khr_push_descriptor", "", "Enables better descriptor streaming.");
cvar_t vk_amd_rasterization_order = CVARD ("vk_amd_rasterization_order", "", "Enables the use of relaxed rasterization ordering, for a small speedup at the minor risk of a little zfighting.");
cvar_t vk_usememorypools = CVARFD("vk_usememorypools", "", CVAR_VIDEOLATCH, "Allocates memory pools for sub allocations. Vulkan has a limit to the number of memory allocations allowed so this should always be enabled, however at this time FTE is unable to reclaim pool memory, and would require periodic vid_restarts to flush them.");
cvar_t vk_nv_glsl_shader = CVARFD("vk_loadglsl", "", CVAR_VIDEOLATCH, "Enable direct loading of glsl, where supported by drivers. Do not use in combination with vk_debug 2 (vk_debug should be 1 if you want to see any glsl compile errors). Don't forget to do a vid_restart after.");
cvar_t vk_khr_get_memory_requirements2 = CVARFD("vk_khr_get_memory_requirements2", "", CVAR_VIDEOLATCH, "Enable extended memory info querires");
cvar_t vk_khr_dedicated_allocation = CVARFD("vk_khr_dedicated_allocation", "", CVAR_VIDEOLATCH, "Flag vulkan memory allocations as dedicated, where applicable.");
cvar_t vk_khr_push_descriptor = CVARFD("vk_khr_push_descriptor", "", CVAR_VIDEOLATCH, "Enables better descriptor streaming.");
cvar_t vk_amd_rasterization_order = CVARFD("vk_amd_rasterization_order", "", CVAR_VIDEOLATCH, "Enables the use of relaxed rasterization ordering, for a small speedup at the minor risk of a little zfighting.");
#endif
#ifdef D3D9QUAKE
@ -1011,9 +1012,10 @@ void Renderer_Init(void)
Cvar_Register (&vk_dualqueue, VKRENDEREROPTIONS);
Cvar_Register (&vk_busywait, VKRENDEREROPTIONS);
Cvar_Register (&vk_waitfence, VKRENDEREROPTIONS);
Cvar_Register (&vk_usememorypools, VKRENDEREROPTIONS);
Cvar_Register (&vk_nv_glsl_shader, VKRENDEREROPTIONS);
Cvar_Register (&vk_nv_dedicated_allocation, VKRENDEREROPTIONS);
Cvar_Register (&vk_khr_get_memory_requirements2,VKRENDEREROPTIONS);
Cvar_Register (&vk_khr_dedicated_allocation,VKRENDEREROPTIONS);
Cvar_Register (&vk_khr_push_descriptor, VKRENDEREROPTIONS);
Cvar_Register (&vk_amd_rasterization_order, VKRENDEREROPTIONS);
@ -1944,6 +1946,7 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring)
}
else
{
int bestpri = -2, pri;
for (i = 0; i < sizeof(rendererinfo)/sizeof(rendererinfo[0]); i++)
{
if (!rendererinfo[i] || !rendererinfo[i]->description)
@ -1954,8 +1957,21 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring)
continue;
if (!stricmp(rendererinfo[i]->name[j], com_token))
{
newr->renderer = rendererinfo[i];
break;
if (rendererinfo[i]->VID_GetPriority)
pri = rendererinfo[i]->VID_GetPriority();
else if (rendererinfo[i]->rtype == QR_HEADLESS)
pri = -1; //headless renderers are a really poor choice, and will make the user think it buggy.
else if (rendererinfo[i]->rtype == QR_NONE)
pri = 0; //dedicated servers are possible, but we really don't want to use them unless we have no other choice.
else
pri = 1;
if (pri > bestpri)
{
bestpri = pri;
newr->renderer = rendererinfo[i];
}
break; //try the next renderer now.
}
}
}

View File

@ -236,7 +236,7 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime)
{ //hit eof, loop it or stop it
if (s->loopstart != -1) /*some wavs contain a loop offset directly in the sound file, such samples loop even if a non-looping builtin was used*/
{
ch->pos &= ~((-1)<<PITCHSHIFT); /*clear out all but the subsample offset*/
ch->pos &= ~((~0u)<<PITCHSHIFT); /*clear out all but the subsample offset*/
ch->pos += s->loopstart<<PITCHSHIFT; //ignore the offset if its off the end of the file
}
else if (ch->flags & CF_FORCELOOP) /*(static)channels which are explicitly looping always loop from the start*/

View File

@ -452,7 +452,7 @@ int Sys_FileTime (char *path)
void Sys_mkdir (const char *path)
{
mkdir (path, 0777);
mkdir (path, 0760);
}
qboolean Sys_rmdir (const char *path)
{
@ -464,7 +464,10 @@ qboolean Sys_rmdir (const char *path)
}
qboolean Sys_remove (const char *path)
{
return system(va("rm \"%s\"", path));
//remove is part of c89.
if (remove(path) == -1)
return false;
return true;
}
qboolean Sys_Rename (const char *oldfname, const char *newfname)
{
@ -1003,7 +1006,8 @@ int main (int c, const char **v)
sleeptime = Host_Frame(time);
oldtime = newtime;
Sys_Sleep(sleeptime);
if (sleeptime)
Sys_Sleep(sleeptime);
}
}

View File

@ -373,42 +373,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef WAYLANDQUAKE
#endif
#ifdef NO_MULTITHREAD
#undef MULTITHREAD
#endif
#ifdef NO_LIBRARIES //catch-all...
#define NO_DIRECTX
#define NO_PNG
#define NO_JPEG
#define NO_ZLIB
#define NO_OGG
#define NO_FREETYPE
#endif
#ifdef NO_OPENAL
#undef AVAIL_OPENAL
#endif
#ifdef NO_PNG
#undef AVAIL_PNGLIB
#endif
#ifdef NO_JPEG
#undef AVAIL_JPEGLIB
#endif
#ifdef NO_OGG
#undef AVAIL_OGGVORBIS
#endif
#ifdef NO_FREETYPE
#undef AVAIL_FREETYPE
#endif
#ifdef NO_ZLIB
#undef AVAIL_ZLIB
#undef AVAIL_PNGLIB
#undef AVAIL_XZDEC
#undef AVAIL_GZDEC
#endif
#if (defined(_MSC_VER) && (_MSC_VER < 1500)) || defined(FTE_SDL)
#undef AVAIL_WASAPI //wasapi is available in the vista sdk, while that's compatible with earlier versions, its not really expected until 2008
#endif
//include a file to update the various configurations for game-specific configs (hopefully just names)
#ifdef BRANDING_INC
#include STRINGIFY(BRANDING_INC)
@ -580,6 +544,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifdef ANDROID
#define GLESONLY //should reduce the conditions a little
// #undef HEADLESSQUAKE
#define NO_FREETYPE
#define NO_OPENAL
#endif
#if defined(NACL)
//stuff is sandboxed.
@ -599,12 +565,47 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef HEADLESSQUAKE
#define NO_FREETYPE
#endif
#if (defined(_MSC_VER) && (_MSC_VER < 1500)) || defined(FTE_SDL)
#undef AVAIL_WASAPI //wasapi is available in the vista sdk, while that's compatible with earlier versions, its not really expected until 2008
#endif
#ifdef NO_MULTITHREAD
#undef MULTITHREAD
#endif
#ifndef MULTITHREAD
//database code requires threads to do stuff async.
#undef USE_SQLITE
#undef USE_MYSQL
#endif
#ifdef NO_LIBRARIES //catch-all...
#define NO_DIRECTX
#define NO_PNG
#define NO_JPEG
#define NO_ZLIB
#define NO_OGG
#define NO_FREETYPE
#endif
#ifdef NO_OPENAL
#undef AVAIL_OPENAL
#endif
#ifdef NO_PNG
#undef AVAIL_PNGLIB
#endif
#ifdef NO_JPEG
#undef AVAIL_JPEGLIB
#endif
#ifdef NO_OGG
#undef AVAIL_OGGVORBIS
#endif
#ifdef NO_FREETYPE
#undef AVAIL_FREETYPE
#endif
#ifdef NO_ZLIB
#undef AVAIL_ZLIB
#undef AVAIL_PNGLIB
#undef AVAIL_XZDEC
#undef AVAIL_GZDEC
#endif
#if defined(HAVE_WINSSPI) || defined(HAVE_GNUTLS)
#define HAVE_SSL

View File

@ -6052,9 +6052,9 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
group[j].boneofs = animmatrix + 12*num_boneinfo*frameinfo[j].firstpose;
group[j].numposes = frameinfo[j].posecount;
if (*frameinfo[j].name)
snprintf(group[j].name, sizeof(group[j].name), "%s", frameinfo[j].name);
Q_snprintfz(group[j].name, sizeof(group[j].name), "%s", frameinfo[j].name);
else
snprintf(group[j].name, sizeof(group[j].name), "frame_%i", j);
Q_snprintfz(group[j].name, sizeof(group[j].name), "frame_%i", j);
group[j].loop = frameinfo[j].loop;
group[j].rate = frameinfo[j].fps;
group[j].skeltype = SKEL_RELATIVE;
@ -6077,7 +6077,7 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
{
group[iframe].boneofs = animmatrix + 12*num_boneinfo*(animinfo[j].firstframe+i);
group[iframe].numposes = 1;
snprintf(group[iframe].name, sizeof(group[iframe].name), "%s_%i", animinfo[j].name, i);
Q_snprintfz(group[iframe].name, sizeof(group[iframe].name), "%s_%i", animinfo[j].name, i);
group[iframe].loop = true;
group[iframe].rate = animinfo[j].fps;
group[iframe].skeltype = SKEL_RELATIVE;

View File

@ -3119,8 +3119,8 @@ const gamemode_info_t gamemode_info[] = {
#ifndef NOLEGACY
//cmdline switch exename protocol name(dpmaster) identifying file exec dir1 dir2 dir3 dir(fte) full name
//two quakes - one without extra game dirs which should avoid fuckups from nquake's configs (which screw over cvars that every nq progs.dat depends upon but which the ezquake id1-only less-compatible gamecode ignores).
{"-quake", "qw", "FTE-Quake DarkPlaces-Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1", "qw", "*fte"}, "Quake", "https://fte.triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
{"-netquake", "q1", "FTE-Quake DarkPlaces-Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1"}, "Quake", "https://fte.triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
{"-quake", "q1", "FTE-Quake DarkPlaces-Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1", "qw", "*fte"}, "Quake", "https://fte.triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
{"-netquake", "nq", "FTE-Quake DarkPlaces-Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1"}, "Quake", "https://fte.triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
//quake's mission packs should not be favoured over the base game nor autodetected
//third part mods also tend to depend upon the mission packs for their huds, even if they don't use any other content.
//and q2 also has a rogue/pak0.pak file that we don't want to find and cause quake2 to look like dissolution of eternity
@ -6177,14 +6177,54 @@ void COM_InitFilesystem (void)
#endif
}
#else
//yay for unix!.
ev = getenv("HOME");
//on unix, we use environment settings.
//if $HOME/.fte/ exists then we use that because of legacy reasons.
//but if it doesn't exist then we use $XDG_DATA_HOME/.fte instead
//we used to use $HOME/.#HOMESUBDIR/ but this is now only used if it actually exists AND the new path doesn't.
//new installs use $XDG_DATA_HOME/#HOMESUBDIR/ instead
ev = getenv("FTEHOME");
if (ev && *ev)
{
if (ev[strlen(ev)-1] == '/')
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s.fte/", ev);
Q_strncpyz(com_homepath, ev, sizeof(com_homepath));
else
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/.fte/", ev);
Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/", ev);
usehome = true; // always use home on unix unless told not to
ev = NULL;
}
else
ev = getenv("HOME");
if (ev && *ev)
{
const char *xdghome;
char oldhome[MAX_OSPATH];
char newhome[MAX_OSPATH];
struct stat s;
#ifdef GAME_SHORTNAME
#define HOMESUBDIR GAME_SHORTNAME
#else
#define HOMESUBDIR "fte" //FIXME: this should come from the manifest, as fte_GAME or something
#endif
if (ev[strlen(ev)-1] == '/')
Q_snprintfz(oldhome, sizeof(oldhome), "%s."HOMESUBDIR"/", ev);
else
Q_snprintfz(oldhome, sizeof(oldhome), "%s/."HOMESUBDIR"/", ev);
xdghome = getenv("XDG_DATA_HOME");
if (!xdghome || !*xdghome)
xdghome = va("%s/.local/share", ev);
if (xdghome[strlen(xdghome)-1] == '/')
Q_snprintfz(newhome, sizeof(newhome), "%s"HOMESUBDIR"/", xdghome);
else
Q_snprintfz(newhome, sizeof(newhome), "%s/"HOMESUBDIR"/", xdghome);
if (stat(newhome, &s) == -1 && stat(oldhome, &s) != -1)
Q_strncpyz(com_homepath, oldhome, sizeof(com_homepath));
else
Q_strncpyz(com_homepath, newhome, sizeof(com_homepath));
usehome = true; // always use home on unix unless told not to
}
#endif

View File

@ -373,7 +373,7 @@ qboolean NET_CompareAdr (netadr_t *a, netadr_t *b)
Con_Printf("NET_CompareAdr: Bad address type\n");
return false;
}
/*
===================
NET_CompareBaseAdr
@ -524,7 +524,7 @@ char *NET_AdrToString (char *s, int len, netadr_t *a)
char *rs = s;
char *prot = "";
#ifdef IPPROTO_IPV6
qboolean doneblank;
int doneblank;
#endif
switch(a->prot)
@ -590,7 +590,7 @@ char *NET_AdrToString (char *s, int len, netadr_t *a)
{
char *p;
int i;
if (!*(int*)&a->address.ip6[0] &&
if (!*(int*)&a->address.ip6[0] &&
!*(int*)&a->address.ip6[4] &&
!*(short*)&a->address.ip6[8] &&
*(short*)&a->address.ip6[10] == (short)0xffff)
@ -756,7 +756,7 @@ char *NET_BaseAdrToString (char *s, int len, netadr_t *a)
{
char *p;
int i, doneblank;
if (!*(int*)&a->address.ip6[0] &&
if (!*(int*)&a->address.ip6[0] &&
!*(int*)&a->address.ip6[4] &&
!*(short*)&a->address.ip6[8] &&
*(short*)&a->address.ip6[10] == (short)0xffff)
@ -996,7 +996,7 @@ size_t NET_StringToSockaddr2 (const char *s, int defaultport, struct sockaddr_qs
{
if (addrfamily)
addrfamily[i] = ((struct sockaddr*)sadr)->sa_family;
if (((struct sockaddr*)&sadr[i])->sa_family == AF_INET)
{
if (!((struct sockaddr_in *)&sadr[i])->sin_port)
@ -2108,7 +2108,7 @@ static void FTENET_NATPMP_Refresh(pmpcon_t *pmp, short oldport, ftenet_connectio
{
int i, m;
netadr_t adr;
netadr_t addr[64];
struct ftenet_generic_connection_s *con[sizeof(addr)/sizeof(addr[0])];
int flags[sizeof(addr)/sizeof(addr[0])];
@ -2145,7 +2145,7 @@ static void FTENET_NATPMP_Refresh(pmpcon_t *pmp, short oldport, ftenet_connectio
!*(int*)&adr.address.ip6[0] &&
!*(int*)&adr.address.ip6[4] &&
!*(short*)&adr.address.ip6[8] &&
*(short*)&adr.address.ip6[10]==(short)0xffff &&
*(short*)&adr.address.ip6[10]==(short)0xffff &&
!*(int*)&adr.address.ip6[12])
{
*(int*)adr.address.ip = *(int*)&adr.address.ip6[12];
@ -2228,7 +2228,7 @@ qboolean FTENET_NATPMP_GetPacket(struct ftenet_generic_connection_s *con)
}
neterr_t FTENET_NATPMP_SendPacket(struct ftenet_generic_connection_s *con, int length, const void *data, netadr_t *to)
{
return false;
return NETERR_NOROUTE;
}
void FTENET_NATPMP_Close(struct ftenet_generic_connection_s *con)
{
@ -2786,7 +2786,7 @@ int FTENET_Generic_GetLocalAddresses(struct ftenet_generic_connection_s *con, un
!*(int*)&adr.address.ip6[0] &&
!*(int*)&adr.address.ip6[4] &&
!*(short*)&adr.address.ip6[8] &&
*(short*)&adr.address.ip6[10]==(short)0xffff &&
*(short*)&adr.address.ip6[10]==(short)0xffff &&
!*(int*)&adr.address.ip6[12])
{
//ipv6 socket bound to the ipv4-any address is a bit weird, but oh well.
@ -3105,7 +3105,7 @@ ftenet_generic_connection_t *FTENET_Datagram_EstablishConnection(qboolean isserv
protocol = 0;
break;
}
if (adr.type == NA_INVALID)
{
@ -4050,7 +4050,7 @@ qboolean FTENET_TCP_ParseHTTPRequest(ftenet_tcpconnect_connection_t *con, ftenet
}
else if (j+4 <= i && !strncmp(&st->inbuffer[j], "gzip", 4) && (j+4==i || st->inbuffer[j+4] == ';' || st->inbuffer[j+4] == ','))
acceptsgzip = true;
while (j < i && st->inbuffer[j] != ',')
j++;
if (j < i && st->inbuffer[j] == ',')
@ -4585,7 +4585,7 @@ closesvstream:
if (ctrl & 0x7000)
{
Con_Printf ("%s: reserved bits set\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream;
goto closesvstream;
}
if ((ctrl & 0x7f) == 127)
{
@ -4594,13 +4594,13 @@ closesvstream:
if (sizeof(ullpaylen) < 8)
{
Con_Printf ("%s: payload frame too large\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream;
goto closesvstream;
}
else
{
if (payoffs + 8 > st->inlen)
break;
ullpaylen =
ullpaylen =
(quint64_t)((unsigned char*)st->inbuffer)[payoffs+0]<<56u |
(quint64_t)((unsigned char*)st->inbuffer)[payoffs+1]<<48u |
(quint64_t)((unsigned char*)st->inbuffer)[payoffs+2]<<40u |
@ -4612,12 +4612,12 @@ closesvstream:
if (ullpaylen < 0x10000)
{
Con_Printf ("%s: payload size (%"PRIu64") encoded badly\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), ullpaylen);
goto closesvstream;
goto closesvstream;
}
if (ullpaylen > 0x40000)
{
Con_Printf ("%s: payload size (%"PRIu64") is abusive\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), ullpaylen);
goto closesvstream;
goto closesvstream;
}
paylen = ullpaylen;
payoffs += 8;
@ -4627,13 +4627,13 @@ closesvstream:
{
if (payoffs + 2 > st->inlen)
break;
paylen =
paylen =
((unsigned char*)st->inbuffer)[payoffs+0]<<8 |
((unsigned char*)st->inbuffer)[payoffs+1]<<0;
if (paylen < 126)
{
Con_Printf ("%s: payload size encoded badly\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream;
goto closesvstream;
}
payoffs += 2;
}
@ -5783,7 +5783,7 @@ typedef struct
int datasock; //only if we're a client
size_t numclients;
struct
struct
{
netadr_t remoteadr;
int datasock;
@ -6413,7 +6413,7 @@ qboolean NET_UpdateRates(ftenet_connections_t *collection, qboolean inbound, siz
int ctime;
if (!collection)
return false;
if (inbound)
{
cls.sockets->bytesin += size;

View File

@ -1073,7 +1073,7 @@ qintptr_t VARGS Plug_Net_SetTLSClient(void *offset, quintptr_t mask, const qintp
{
pluginstream_t *stream;
unsigned int handle = VM_LONG(arg[0]);
if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug)
if (handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug)
{
Con_Printf("Plug_Net_SetTLSClient: socket does not belong to you (or is invalid)\n");
return -2;
@ -1106,7 +1106,7 @@ qintptr_t VARGS Plug_Net_GetTLSBinding(void *offset, quintptr_t mask, const qint
return -2;
if (VM_OOB(arg[1], *bindsize))
return -2;
if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug)
if ((size_t)handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug)
{
Con_Printf("Plug_Net_GetTLSBinding: socket does not belong to you (or is invalid)\n");
return -2;

View File

@ -100,14 +100,15 @@ void PF_Common_RegisterCvars(void)
qofs_t PR_ReadBytesString(char *str)
{
size_t u = strtoul(str, &str, 0);
//use doubles, so we can cope with eg "5.3mb" or much larger values
double d = strtod(str, &str);
if (*str == 'g')
u *= 1024*1024*1024;
d *= 1024*1024*1024;
if (*str == 'm')
u *= 1024*1024;
d *= 1024*1024;
if (*str == 'k')
u *= 1024;
return u;
d *= 1024;
return d;
}
//just prints out a warning with stack trace. so I can throttle spammy stack traces.

View File

@ -76,8 +76,8 @@ typedef unsigned int FT_Pixel_Mode; //for consistency even without freetype supp
#ifndef FT_PIXEL_MODE_BGRA
#define FT_PIXEL_MODE_BGRA 7 //added in FT 2.5
#endif
#define FT_PIXEL_MODE_RGBA_SA (~(FT_Pixel_Mode)0) //RGBA, straight alpha. not in freetype.
#define FT_PIXEL_MODE_RGBA (~(FT_Pixel_Mode)1) //RGBA, premultiplied alpha. not in freetype.
#define FT_PIXEL_MODE_RGBA_SA (100) //RGBA, straight alpha. not in freetype.
#define FT_PIXEL_MODE_RGBA (101) //RGBA, premultiplied alpha. not in freetype.
static const char *imgs[] =
{
@ -672,7 +672,7 @@ static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, FT
out += PLANEWIDTH*4;
}
}
else if (pixelmode == FT_PIXEL_MODE_RGBA_SA)
else if ((unsigned int)pixelmode == FT_PIXEL_MODE_RGBA_SA)
{ //rgba font
for (y = -pad; y < 0; y++)
{
@ -739,7 +739,7 @@ static struct charcache_s *Font_LoadGlyphData(font_t *f, CHARIDXTYPE charidx, FT
out += PLANEWIDTH*4;
}
}
else if (pixelmode == FT_PIXEL_MODE_RGBA)
else if ((unsigned int)pixelmode == FT_PIXEL_MODE_RGBA)
{ //bgra srgb font, already premultiplied
for (y = -pad; y < 0; y++)
{

View File

@ -6577,7 +6577,7 @@ static void *validateqcpointer(pubprogfuncs_t *prinst, size_t qcptr, size_t elem
PR_BIError(prinst, "brush: elementcount %u is too large\n", (unsigned int)elementcount);
return NULL;
}
if (qcptr < 0 || qcptr+(elementsize*elementcount) > prinst->stringtablesize)
if (qcptr+(elementsize*elementcount) > (size_t)prinst->stringtablesize)
{
PR_BIError(prinst, "brush: invalid qc pointer\n");
return NULL;
@ -6803,7 +6803,7 @@ void QCBUILTIN PF_brush_selected(pubprogfuncs_t *prinst, struct globalvars_s *pr
heightmap_t *hm = mod?mod->terrain:NULL;
unsigned int brushid = G_INT(OFS_PARM1);
// unsigned int faceid = G_INT(OFS_PARM2);
unsigned int state = G_FLOAT(OFS_PARM3);
int state = G_FLOAT(OFS_PARM3);
unsigned int i;
brushes_t *br;
@ -6842,17 +6842,17 @@ void QCBUILTIN PF_brush_selected(pubprogfuncs_t *prinst, struct globalvars_s *pr
// {"brush_calcfacepoints",PF_brush_calcfacepoints,0,0, 0, 0, D("int(int faceid, brushface_t *in_faces, int numfaces, vector *points, int maxpoints)", "Determines the points of the specified face, if the specified brush were to actually be created.")},
void QCBUILTIN PF_brush_calcfacepoints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
unsigned int faceid = G_INT(OFS_PARM0);
unsigned int numfaces = G_INT(OFS_PARM2);
size_t faceid = G_INT(OFS_PARM0);
size_t numfaces = G_INT(OFS_PARM2);
qcbrushface_t *in_faces = validateqcpointer(prinst, G_INT(OFS_PARM1), sizeof(*in_faces), numfaces, false);
unsigned int maxpoints = G_INT(OFS_PARM4);
size_t maxpoints = G_INT(OFS_PARM4);
vec3_t *out_verts = validateqcpointer(prinst, G_INT(OFS_PARM3), sizeof(*out_verts), maxpoints, false);
vecV_t facepoints[256];
vec4_t planes[256];
unsigned int j, numpoints;
faceid--;
if (faceid < 0 || faceid >= numfaces)
if ((size_t)faceid >= numfaces)
{
G_INT(OFS_RETURN) = 0;
return;

View File

@ -3153,7 +3153,7 @@ qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int psl)
#ifdef VKQUAKE
case PSL_VULKAN:
visinfo = &vinfodef;
if (!x11.pXMatchVisualInfo(vid_dpy, scrnum, info->bpp?info->bpp:DefaultDepth(vid_dpy, scrnum), TrueColor, visinfo))
if (!x11.pXMatchVisualInfo(vid_dpy, scrnum, min(24,info->bpp?info->bpp:DefaultDepth(vid_dpy, scrnum)), TrueColor, visinfo))
{
Sys_Error("Couldn't choose visual for vulkan\n");
}

View File

@ -221,7 +221,7 @@ static qboolean SDLVID_Init (rendererstate_t *info, unsigned char *palette, r_qr
sdlwindow = SDL_CreateWindow(FULLENGINENAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, info->width, info->height, flags);
if (!sdlwindow)
{
Con_Printf("Couldn't set video mode: %s\n", SDL_GetError());
Con_Printf("SDL_CreateWindow failed: %s\n", SDL_GetError());
return false;
}
CL_UpdateWindowTitle();
@ -379,7 +379,9 @@ void GLVID_DeInit (void)
#endif
SDL_QuitSubSystem(SDL_INIT_VIDEO);
#ifdef OPENGL_SDL
GL_ForgetPointers();
#endif
}

View File

@ -700,7 +700,20 @@ static void WL_SetCaption(const char *text)
static int WL_GetPriority(void)
{
char *dpyname = getenv("WAYLAND_DISPLAY");
//2 = above x11, 0 = below x11.
char *stype = getenv("XDG_SESSION_TYPE");
char *dpyname;
if (!strcmp(stype, "wayland"))
return 2;
if (!strcmp(stype, "x11"))
return 0;
if (!strcmp(stype, "tty")) //FIXME: support this!
return 0;
//otherwise if both WAYLAND_DISPLAY and DISPLAY are defined, then we assume that we were started from xwayland wrapper thing, and that the native/preferred windowing system is wayland.
//(lets just hope our wayland support is comparable)
dpyname = getenv("WAYLAND_DISPLAY");
if (dpyname && *dpyname)
return 2; //something above X11.
return 0; //default.

View File

@ -1448,7 +1448,7 @@ qboolean DL_CreateThread(struct dl_download *dl, vfsfile_t *file, void (*NotifyF
dl->threadenable = true;
#if defined(LOADERTHREAD) && !defined(NPFTE)
if (dlthreads < 0)
if (dlthreads < 4)
#endif
{
dl->threadctx = Sys_CreateThread("download", DL_Thread_Work, dl, THREADP_NORMAL, 0);

View File

@ -205,7 +205,7 @@ static void PR_memvalidate (progfuncs_t *progfuncs)
l = 0;
while (b)
{
if (b < 0 || b >= prinst.addressableused)
if ((size_t)b >= (size_t)prinst.addressableused)
{
printf("PF_memalloc: memory corruption\n");
PR_StackTrace(&progfuncs->funcs, false);

View File

@ -310,7 +310,11 @@ typedef union QCC_eval_s
{
QCC_string_t string;
float _float;
float vector[1];
#ifdef __GNUC__
float vector[0]; //gnuc extension. I'm using it to mute clang warnings.
#else
float vector[1]; //should be 3, except that then eval_t would be too big.
#endif
func_t function;
int _int;
// union QCC_eval_s *ptr;

View File

@ -7360,7 +7360,7 @@ vectorarrayindex:
i = tmp.sym->symboldata[tmp.ofs]._float;
else
i = -1;
if (i < 0 || i >= 3)
if ((unsigned)i >= 3u)
QCC_PR_ParseErrorPrintSRef(0, r->base, "(vector) array index out of bounds");
}
else if (QCC_OPCodeValid(&pr_opcodes[OP_BOUNDCHECK]) && flag_boundchecks)
@ -7382,7 +7382,7 @@ vectorarrayindex:
i = tmp.sym->symboldata[tmp.ofs]._float;
else
i = -1;
if (i < 0 || i >= 3)
if ((unsigned)i >= 3u)
QCC_PR_ParseErrorPrintSRef(0, r->base, "(vector) array index out of bounds");
}
else if (QCC_OPCodeValid(&pr_opcodes[OP_BOUNDCHECK]) && flag_boundchecks)
@ -7405,7 +7405,7 @@ vectorarrayindex:
i = tmp.sym->symboldata[tmp.ofs]._float;
else
i = -1;
if (i < 0 || i >= arraysize)
if ((unsigned)i >= (unsigned)arraysize)
QCC_PR_ParseErrorPrintSRef(0, r->base, "(constant) array index out of bounds (0 <= %i < %i)", i, arraysize);
}
else

View File

@ -351,7 +351,7 @@ compiler_flag_t compiler_flag[] = {
{&keyword_accumulate, nondefaultkeyword,"accumulate", "Keyword: accumulate", "Disables the 'accumulate' keyword."},
//options
{&flag_acc, 0, "acc", "Reacc support", "Reacc is a pascall like compiler. It was released before the Quake source was released. This flag has a few effects. It sorts all qc files in the current directory into alphabetical order to compile them. It also allows Reacc global/field distinctions, as well as allows ¦ as EOF. Whilst case insensitivity and lax type checking are supported by reacc, they are seperate compiler flags in fteqcc."}, //reacc like behaviour of src files.
{&flag_acc, 0, "acc", "Reacc support", "Reacc is a pascall like compiler. It was released before the Quake source was released. This flag has a few effects. It sorts all qc files in the current directory into alphabetical order to compile them. It also allows Reacc global/field distinctions, as well as allows | for linebreaks. Whilst case insensitivity and lax type checking are supported by reacc, they are seperate compiler flags in fteqcc."}, //reacc like behaviour of src files.
{&flag_qccx, FLAG_MIDCOMPILE,"qccx", "QCCX syntax", "WARNING: This syntax makes mods inherantly engine specific.\nDo NOT use unless you know what you're doing.This is provided for compatibility only\nAny entity hacks will be unsupported in FTEQW, DP, and others, resulting in engine crashes if the code in question is executed."},
{&keywords_coexist, FLAG_ASDEFAULT, "kce", "Keywords Coexist", "If you want keywords to NOT be disabled when they a variable by the same name is defined, check here."},
{&output_parms, 0, "parms", "Define offset parms", "if PARM0 PARM1 etc should be defined by the compiler. These are useful if you make use of the asm keyword for function calls, or you wish to create your own variable arguments. This is an easy way to break decompilers."}, //controls weather to define PARMx for the parms (note - this can screw over some decompilers)
@ -2050,18 +2050,9 @@ strofs = (strofs+3)&~3;
qtst[i].line = statements[i].linenum;
qtst[i].op = PRLittleShort((unsigned short)statements[i].op);
if (a < 0)
qtst[i].a = PRLittleShort((short)a);
else
qtst[i].a = (unsigned short)PRLittleShort((unsigned short)a);
if (b < 0)
qtst[i].b = PRLittleShort((short)b);
else
qtst[i].b = (unsigned short)PRLittleShort((unsigned short)b);
if (c < 0)
qtst[i].c = PRLittleShort((short)c);
else
qtst[i].c = (unsigned short)PRLittleShort((unsigned short)c);
qtst[i].a = (unsigned short)PRLittleShort((unsigned short)a);
qtst[i].b = (unsigned short)PRLittleShort((unsigned short)b);
qtst[i].c = (unsigned short)PRLittleShort((unsigned short)c);
}
// no compression
@ -2106,18 +2097,10 @@ strofs = (strofs+3)&~3;
if (((signed)a >= (signed)numpr_globals && statements[i].a.sym) || ((signed)b >= (signed)numpr_globals && statements[i].b.sym) || ((signed)c >= (signed)numpr_globals && statements[i].c.sym))
printf("invalid offset on %s instruction\n", pr_opcodes[statements[i].op].opname);
#endif
if (a < 0)
statements16[i].a = PRLittleShort(a);
else
statements16[i].a = (unsigned short)PRLittleShort(a);
if (b < 0)
statements16[i].b = PRLittleShort((short)b);
else
statements16[i].b = (unsigned short)PRLittleShort((unsigned short)b);
if (c < 0)
statements16[i].c = PRLittleShort((short)c);
else
statements16[i].c = (unsigned short)PRLittleShort((unsigned short)c);
//truncate to 16bit. should probably warn if the high bits are not 0x0000 or 0xffff
statements16[i].a = (unsigned short)PRLittleShort((unsigned short)a);
statements16[i].b = (unsigned short)PRLittleShort((unsigned short)b);
statements16[i].c = (unsigned short)PRLittleShort((unsigned short)c);
}
if (progs.blockscompressed&1)

View File

@ -2265,7 +2265,7 @@ qboolean PR_LoadQ1QVM(void)
q1qvmprogfuncs.edicttable_length = sv.world.max_edicts;
limit = VM_MemoryMask(q1qvm);
if (gd.sizeofent < 0 || gd.sizeofent > 0xffffffff / gd.maxedicts)
if (gd.sizeofent > 0xffffffff / gd.maxedicts)
gd.sizeofent = 0xffffffff / gd.maxedicts;
if ((quintptr_t)gd.ents+(gd.sizeofent*gd.maxedicts) < (quintptr_t)gd.ents || (quintptr_t)gd.ents > (quintptr_t)limit)
gd.ents = 0;

View File

@ -104,6 +104,7 @@ cvar_t sv_listen_dp = CVARD("sv_listen_dp", "0", "Allows the server to respond
#ifdef QWOVERQ3
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 .");
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_highchars = CVAR("sv_highchars", "1");
@ -2782,6 +2783,12 @@ client_t *SVC_DirectConnect(void)
if (NET_CompareBaseAdr (&adr, &cl->netchan.remote_address)
&& ((protocol == SCP_QUAKEWORLD && cl->netchan.qport == qport) || adr.port == cl->netchan.remote_address.port ))
{
if (realtime - cl->connection_started < sv_reconnectlimit.value)
{
Con_Printf ("%s:reconnect rejected: too soon\n", NET_AdrToString (adrbuf, sizeof(adrbuf), &adr));
return NULL;
}
if (cl->state == cs_connected)
{
if (cl->protocol != protocol)
@ -5141,6 +5148,7 @@ void SV_InitLocal (void)
Cvar_Register (&sv_listen_q3, cvargroup_servercontrol);
#endif
sv_listen_qw.restriction = RESTRICT_MAX; //no disabling this over rcon.
Cvar_Register (&sv_reconnectlimit, cvargroup_servercontrol);
Cvar_Register (&fraglog_public, cvargroup_servercontrol);
SVNET_RegisterCvars();

View File

@ -1208,7 +1208,7 @@ void SQL_ServerCycle (void)
qreq->results = qres;
if (developer.ival)
if (qres->error)
if (*qres->error)
Con_Printf("%s\n", qres->error);
if (qreq->state == SR_ABORTED)
{

View File

@ -775,6 +775,22 @@ static int Sys_CheckChRoot(void)
//SSL_InitGlobal(true); //make sure we load our public cert from outside the sandbox. an exploit might still be able to find it in memory though. FIXME: disabled in case this reads from somewhere bad - we're still root.
#endif
{ //this protects against stray setuid programs like su reading passwords from /etc/passwd et al
//there shouldn't be anyway so really this is pure paranoia.
//(the length thing is to avoid overflows inside va giving false negatives.)
struct stat s;
if (strlen(newroot) > 4096 || lstat(va("%s/etc/", newroot), &s) != -1)
{
printf("refusing to chroot to %s - contains an /etc directory\n", newroot);
return -1;
}
if (strlen(newroot) > 4096 || lstat(va("%s/proc/", newroot), &s) != -1)
{
printf("refusing to chroot to %s - contains a /proc directory\n", newroot);
return -1;
}
}
printf("Changing root dir to \"%s\"\n", newroot);
if (chroot(newroot))
{
@ -783,10 +799,16 @@ static int Sys_CheckChRoot(void)
}
chdir("/"); //chroot does NOT change the working directory, so we need to make sure that happens otherwise still a way out.
//signal to the fs.c code to use an explicit base home dir.
if (newhome)
setenv("HOME", va("/user/%s", newhome), true);
setenv("FTEHOME", va("/user/%s", newhome), true);
else
setenv("HOME", va("/user/%i", ruid), true);
setenv("FTEHOME", va("/user/%i", ruid), true);
//these paths are no longer valid.
setenv("HOME", "", true);
setenv("XDG_DATA_HOME", "", true);
setenv("PWD", "/", true);
ret = true;

View File

@ -802,14 +802,7 @@ void SVQ2_ConfigStrings_f (void)
return;
}
start = atoi(Cmd_Argv(2));
if (start < 0)
{
Con_Printf ("SV_Configstrings_f: %s tried crashing us\n", host_client->name);
host_client->drop = true;
return;
}
start = strtoul(Cmd_Argv(2), NULL, 0);
// write a packet full of data
@ -820,7 +813,7 @@ void SVQ2_ConfigStrings_f (void)
if (str && *str)
{
MSG_WriteByte (&host_client->netchan.message, svcq2_configstring);
MSG_WriteShort (&host_client->netchan.message, start);
MSG_WriteShort (&host_client->netchan.message, (unsigned short)start);
MSG_WriteString (&host_client->netchan.message, str);
}
start++;
@ -7898,7 +7891,7 @@ void SV_ExecuteClientMessage (client_t *cl)
#ifdef Q2SERVER
void SVQ2_ExecuteClientMessage (client_t *cl)
{
enum clcq2_ops_e c;
int c;
char *s;
usercmd_t oldest, oldcmd, newcmd;
q2client_frame_t *frame;
@ -7978,7 +7971,7 @@ void SVQ2_ExecuteClientMessage (client_t *cl)
if (c == -1)
break;
switch (c)
switch ((enum clcq2_ops_e)c)
{
default:
Con_Printf ("SVQ2_ReadClientMessage: unknown command char %i\n", c);

View File

@ -1,4 +1,8 @@
CC=i686-pc-mingw32-gcc
#NOTE: if you're on windows, you might want to use CC=i686-pc-mingw32-gcc
CC ?= gcc
VKSDKPATH ?= ~/VulkanSDK/1.1.73.0/x86_64/bin/
all:
@ -22,12 +26,12 @@ makevulkanblob: makevulkanblob.c
$(CC) $< -o $@
vulkanblobs/%.fvb: vulkan/%.glsl makevulkanblob vulkan/sys/defs.h vulkan/sys/fog.h vulkan/sys/offsetmapping.h vulkan/sys/skeletal.h
./makevulkanblob $< $@
@echo Making $<
@PATH=$(PATH):$(VKSDKPATH) ./makevulkanblob $< $@
#vulkanblobs/%.fvb: glsl/%.glsl makevulkanblob vulkan/sys/defs.h vulkan/sys/fog.h vulkan/sys/offsetmapping.h vulkan/sys/skeletal.h
# ./makevulkanblob $< $@
all: generatebuiltinsl $(ALLNAMES)
which glslangValidator
./generatebuiltinsl
./generatebuiltinsl

View File

@ -108,8 +108,13 @@ int generatevulkanblobs(struct blobheader *blob, size_t maxblobsize, const char
FILE *glsl = fopen(glslname, "rt");
if (!glsl)
{
printf("Unable to read %s\n", glslname);
return 0;
}
FILE *temp = fopen(tempname, "wt");
if (!temp)
printf("Unable to write %s\n", tempname);
while(fgets(command, sizeof(command), glsl))
{
if (inheader && !strncmp(command, "!!", 2))
@ -130,14 +135,14 @@ int generatevulkanblobs(struct blobheader *blob, size_t maxblobsize, const char
{
type = command[5] == 'i' || command[5] == 'f' || command[5] == 'b';
size = type?1:(command[5]-'0');
arg = strtok(command+7, " ,=\n");
arg = strtok(command+7, " ,=\r\n");
type = command[6-type] - 'a' + 'A';
}
else
{
type = command[6] == 'i' || command[6] == 'f' || command[6] == 'b';
size = type?1:(command[6]-'0');
arg = strtok(command+8, " ,=\n");
arg = strtok(command+8, " ,=\r\n");
type = command[7-type];
}
@ -154,8 +159,13 @@ int generatevulkanblobs(struct blobheader *blob, size_t maxblobsize, const char
{
if (arg)
{
arg = strtok(NULL, " ,=\n");
if (type == 'f' || type == 'F')
arg = strtok(NULL, " ,=\r\n");
if (!arg)
{
printf("%s has no default value. Assuming 0\n", cb+4);
u[i].u = 0; //0 either way.
}
else if (type == 'f' || type == 'F')
u[i].f = atof(arg);
else
u[i].u = atoi(arg);
@ -172,7 +182,7 @@ int generatevulkanblobs(struct blobheader *blob, size_t maxblobsize, const char
}
else if (!strncmp(command, "!!permu", 7))
{
char *arg = strtok(command+7, " ,\n");
char *arg = strtok(command+7, " ,\r\n");
for (i = 0; permutationnames[i]; i++)
{
if (!strcmp(arg, permutationnames[i]))
@ -191,7 +201,7 @@ int generatevulkanblobs(struct blobheader *blob, size_t maxblobsize, const char
}
else if (!strncmp(command, "!!samps", 7))
{
char *arg = strtok(command+7, " ,\n");
char *arg = strtok(command+7, " ,\r\n");
do
{
//light
@ -235,7 +245,7 @@ int generatevulkanblobs(struct blobheader *blob, size_t maxblobsize, const char
blob->numtextures = atoi(arg);
else
printf("Unknown texture: \"%s\"\n", arg);
} while((arg = strtok(NULL, " ,\n")));
} while((arg = strtok(NULL, " ,\r\n")));
}
continue;
}
@ -397,26 +407,34 @@ int generatevulkanblobs(struct blobheader *blob, size_t maxblobsize, const char
snprintf(command, sizeof(command),
/*preprocess the vertex shader*/
#ifdef _WIN32
"echo #version 450 core > %s && "
#else
"echo \"#version 450 core\" > %s && "
#endif
"cpp %s -DVULKAN -DVERTEX_SHADER -P >> %s && "
/*preprocess the fragment shader*/
#ifdef _WIN32
"echo #version 450 core > %s && "
#else
"echo \"#version 450 core\" > %s && "
#endif
"cpp %s -DVULKAN -DFRAGMENT_SHADER -P >> %s && "
/*convert to spir-v (annoyingly we have no control over the output file names*/
"glslangValidator -V -l -d %s %s"
/*strip stuff out, so drivers don't glitch out from stuff that we don't use*/
" && spirv-remap -i vert.spv frag.spv -o vulkan/remap"
// " && spirv-remap -i vert.spv frag.spv -o vulkan/remap"
,tempvert, tempname, tempvert, tempfrag, tempname, tempfrag, tempvert, tempfrag);
system(command);
unlink(tempname);
unlink(tempvert);
unlink(tempfrag);
remove(tempname);
remove(tempvert);
remove(tempfrag);
return 1;
}
@ -451,12 +469,20 @@ int main(int argc, const char **argv)
fclose(o);
r = 0;
}
else
printf("Unable to write blob %s\n", blobname);
}
}
fclose(f);
fclose(v);
unlink("vert.spv");
unlink("frag.spv");
if (f)
fclose(f);
else
printf("Unable to read frag.spv\n");
if (v)
fclose(v);
else
printf("Unable to read vert.spv\n");
remove("vert.spv");
remove("frag.spv");
return r;
}
}

View File

@ -2,7 +2,7 @@
#include "sys/defs.h"
//apply gaussian filter
varying vec2 tc;
layout(location=0) varying vec2 tc;
#ifdef VERTEX_SHADER
void main ()
@ -20,4 +20,4 @@ void main ()
0.375 * texture2D(s_t0, tc) +
0.3125 * texture2D(s_t0, tc + e_glowmod.st);
}
#endif
#endif

View File

@ -4,7 +4,7 @@
//the bloom filter
//filter out any texels which are not to bloom
varying vec2 tc;
layout(location=0) varying vec2 tc;
#ifdef VERTEX_SHADER
void main ()
@ -18,4 +18,4 @@ void main ()
{
gl_FragColor.rgb = (texture2D(s_t0, tc).rgb - cvar_r_bloom_filter)/(1.0-cvar_r_bloom_filter);
}
#endif
#endif

View File

@ -5,7 +5,7 @@
//add them together
//optionally apply tonemapping
varying vec2 tc;
layout(location=0) varying vec2 tc;
#ifdef VERTEX_SHADER
void main ()

View File

@ -1,8 +1,8 @@
#include "sys/defs.h"
#ifdef VERTEX_SHADER
varying vec4 vc;
layout(location=0) varying vec4 vc;
#ifdef VERTEX_SHADER
void main ()
{
vc = v_colour;
@ -11,9 +11,8 @@ void main ()
#endif
#ifdef FRAGMENT_SHADER
varying vec4 vc;
void main ()
{
gl_FragColor = vc;
}
#endif
#endif

View File

@ -8,8 +8,9 @@
//regular sky shader for scrolling q1 skies
//the sky surfaces are thrown through this as-is.
layout(location=0) varying vec3 pos;
#ifdef VERTEX_SHADER
varying vec3 pos;
void main ()
{
pos = v_position.xyz;
@ -17,7 +18,6 @@ void main ()
}
#endif
#ifdef FRAGMENT_SHADER
varying vec3 pos;
void main ()
{
vec2 tccoord;

View File

@ -6,7 +6,7 @@
//simple shader for simple skyboxes.
varying vec3 pos;
layout(location=0) varying vec3 pos;
#ifdef VERTEX_SHADER
void main ()
{

View File

@ -8,9 +8,11 @@
#include "sys/defs.h"
#include "sys/fog.h"
layout(location=0) varying vec2 tc;
layout(location=1) varying vec4 vc;
#ifdef VERTEX_SHADER
varying vec2 tc;
varying vec4 vc;
void main ()
{
tc = v_texcoord;
@ -19,8 +21,6 @@ void main ()
}
#endif
#ifdef FRAGMENT_SHADER
varying vec2 tc;
varying vec4 vc;
void main ()
{
vec4 col = texture2D(s_t0, tc);

View File

@ -10,7 +10,8 @@
//this is expected to be moderately fast.
#include "sys/fog.h"
varying vec2 tc;
layout(location=0) varying vec2 tc;
#ifdef VERTEX_SHADER
void main ()
{

View File

@ -1,6 +1,6 @@
!!permu FOG
!!cvar3f r_floorcolor
!!cvar3f r_wallcolor
!!cvar3f r_floorcolor=0.5,0.5,0.5
!!cvar3f r_wallcolor=0.25,0.25,0.5
!!cvarb r_fog_exp2=true
!!samps 1
#include "sys/defs.h"
@ -8,14 +8,10 @@
//this is for the '286' preset walls, and just draws lightmaps coloured based upon surface normals.
#include "sys/fog.h"
varying vec4 col;
layout(location=0) varying vec4 col;
layout(location=1) varying vec2 lm;
#ifdef VERTEX_SHADER
//attribute vec3 v_normal;
//attribute vec2 v_lmcoord;
varying vec2 lm;
//uniform vec3 cvar_r_wallcolor;
//uniform vec3 cvar_r_floorcolor;
//uniform vec4 e_lmscale;
void main ()
{
col = vec4(e_lmscale.rgb/255.0 * ((v_normal.z < 0.73)?cvar_r_wallcolor:cvar_r_floorcolor), e_lmscale.a);
@ -24,8 +20,6 @@ void main ()
}
#endif
#ifdef FRAGMENT_SHADER
//uniform sampler2D s_t0;
varying vec2 lm;
void main ()
{
gl_FragColor = fog4(col * texture2D(s_t0, lm));

View File

@ -4,8 +4,8 @@
//This shader implements super-sampled anti-aliasing.
//
varying vec2 texcoord;
varying vec2 e_sourcesize;
layout(location=0) varying vec2 texcoord;
layout(location=1) varying vec2 e_sourcesize;
#ifdef VERTEX_SHADER
void main()

View File

@ -5,8 +5,8 @@
//fisheye view rendering, for silly fovs that are still playable.
layout(location=0) varying vec2 texcoord;
#ifdef VERTEX_SHADER
varying vec2 texcoord;
void main()
{
texcoord = v_texcoord.xy;
@ -14,8 +14,6 @@ void main()
}
#endif
#ifdef FRAGMENT_SHADER
varying vec2 texcoord;
//uniform float cvar_ffov;
void main()
{
vec3 tc;

View File

@ -4,8 +4,8 @@
//panoramic view rendering, for promo map shots or whatever.
layout(location=0) varying vec2 texcoord;
#ifdef VERTEX_SHADER
varying vec2 texcoord;
void main()
{
texcoord = v_texcoord.xy;
@ -13,7 +13,6 @@ void main()
}
#endif
#ifdef FRAGMENT_SHADER
varying vec2 texcoord;
void main()
{
vec3 tc;

View File

@ -4,8 +4,8 @@
//stereographic view rendering, for high fovs that are still playable.
layout(location=0) varying vec2 texcoord;
#ifdef VERTEX_SHADER
varying vec2 texcoord;
//uniform float cvar_ffov;
void main()
{
@ -18,7 +18,6 @@ void main()
}
#endif
#ifdef FRAGMENT_SHADER
varying vec2 texcoord;
void main()
{
vec3 tc;

View File

@ -6,9 +6,9 @@
//this is a post processing shader that is drawn fullscreen whenever the view is underwater.
//its generally expected to warp the view a little.
varying vec2 v_stc;
varying vec2 v_warp;
varying vec2 v_edge;
layout(location=0) varying vec2 v_stc;
layout(location=1) varying vec2 v_warp;
layout(location=2) varying vec2 v_edge;
#ifdef VERTEX_SHADER
void main ()

View File

@ -247,7 +247,7 @@ typedef struct
vec4_t lightinfo; //org+radius
VkBuffer staticbuf; //holds fallback vertex info so we don't crash from it
VkDeviceMemory staticbufmem;
vk_poolmem_t staticbufmem;
texid_t tex_currentrender;
@ -1647,7 +1647,7 @@ void VKBE_Shutdown(void)
shaderstate.wbatches = NULL;
vkDestroyBuffer(vk.device, shaderstate.staticbuf, vkallocationcb);
vkFreeMemory(vk.device, shaderstate.staticbufmem, vkallocationcb);
VK_ReleasePoolMemory(&shaderstate.staticbufmem);
}
static texid_t SelectPassTexture(const shaderpass_t *pass)
@ -2849,7 +2849,7 @@ static void BE_CreatePipeline(program_t *p, unsigned int shaderflags, unsigned i
((blendflags&SBITS_MASK_BLUE)?0:VK_COLOR_COMPONENT_B_BIT) |
((blendflags&SBITS_MASK_ALPHA)?0:VK_COLOR_COMPONENT_A_BIT);
if (blendflags & SBITS_BLEND_BITS)
if ((blendflags & SBITS_BLEND_BITS) && (blendflags & SBITS_BLEND_BITS)!=(SBITS_SRCBLEND_ONE|SBITS_DSTBLEND_ZERO))
{
switch(blendflags & SBITS_SRCBLEND_BITS)
{
@ -3017,7 +3017,7 @@ static void BE_CreatePipeline(program_t *p, unsigned int shaderflags, unsigned i
pipeCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
pipeCreateInfo.basePipelineIndex = -1; //used to create derivatives for pipelines created in the same call.
// pipeCreateInfo.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
// pipeCreateInfo.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
err = vkCreateGraphicsPipelines(vk.device, vk.pipelinecache, 1, &pipeCreateInfo, vkallocationcb, &pipe->pipeline);
@ -3776,7 +3776,7 @@ void VKBE_SelectEntity(entity_t *ent)
BE_RotateForEntity(ent, ent->model);
}
//fixme: create allocations within larger buffers, use separate staging.
//fixme: create allocations within larger ring buffers, use separate staging.
void *VKBE_CreateStagingBuffer(struct stagingbuf *n, size_t size, VkBufferUsageFlags usage)
{
void *ptr;
@ -3784,6 +3784,8 @@ void *VKBE_CreateStagingBuffer(struct stagingbuf *n, size_t size, VkBufferUsageF
VkMemoryRequirements mem_reqs;
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
memset(&n->mem, 0, sizeof(n->mem));
n->retbuf = VK_NULL_HANDLE;
n->usage = usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
bufinf.flags = 0;
@ -3801,9 +3803,9 @@ void *VKBE_CreateStagingBuffer(struct stagingbuf *n, size_t size, VkBufferUsageF
if (memAllocInfo.memoryTypeIndex == ~0)
Sys_Error("Unable to allocate buffer memory");
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &n->memory));
VkAssert(vkBindBufferMemory(vk.device, n->buf, n->memory, 0));
VkAssert(vkMapMemory(vk.device, n->memory, 0, n->size, 0, &ptr));
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &n->mem.memory));
VkAssert(vkBindBufferMemory(vk.device, n->buf, n->mem.memory, n->mem.offset));
VkAssert(vkMapMemory(vk.device, n->mem.memory, 0, n->size, 0, &ptr));
return ptr;
}
@ -3813,21 +3815,21 @@ struct fencedbufferwork
struct vk_fencework fw;
VkBuffer buf;
VkDeviceMemory mem;
vk_poolmem_t mem;
};
static void VKBE_DoneBufferStaging(void *staging)
{
struct fencedbufferwork *n = staging;
vkDestroyBuffer(vk.device, n->buf, vkallocationcb);
vkFreeMemory(vk.device, n->mem, vkallocationcb);
VK_ReleasePoolMemory(&n->mem);
}
VkBuffer VKBE_FinishStaging(struct stagingbuf *n, VkDeviceMemory *memptr)
VkBuffer VKBE_FinishStaging(struct stagingbuf *n, vk_poolmem_t *mem)
{
struct fencedbufferwork *fence;
VkBuffer retbuf;
//caller filled the staging buffer, and now wants to copy stuff to the gpu.
vkUnmapMemory(vk.device, n->memory);
vkUnmapMemory(vk.device, n->mem.memory);
//create the hardware buffer
if (n->retbuf)
@ -3848,20 +3850,38 @@ VkBuffer VKBE_FinishStaging(struct stagingbuf *n, VkDeviceMemory *memptr)
//sort out its memory
{
VkMemoryRequirements mem_reqs;
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
vkGetBufferMemoryRequirements(vk.device, retbuf, &mem_reqs);
memAllocInfo.allocationSize = mem_reqs.size;
memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
if (memAllocInfo.memoryTypeIndex == ~0)
Sys_Error("Unable to allocate buffer memory");
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, memptr));
VkAssert(vkBindBufferMemory(vk.device, retbuf, *memptr, 0));
if (!VK_AllocatePoolMemory(vk_find_memory_require(mem_reqs.memoryTypeBits, 0), mem_reqs.size, mem_reqs.alignment, mem))
{
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
VkMemoryDedicatedAllocateInfoKHR khr_mdai = {VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR};
//shouldn't really happen, but just in case...
mem_reqs.size = max(1,mem_reqs.size);
memAllocInfo.allocationSize = mem_reqs.size;
memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0);
if (vk.khr_dedicated_allocation)
{
khr_mdai.buffer = retbuf;
khr_mdai.pNext = memAllocInfo.pNext;
memAllocInfo.pNext = &khr_mdai;
}
mem->pool = NULL;
mem->offset = 0;
mem->size = mem_reqs.size;
mem->memory = VK_NULL_HANDLE;
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &mem->memory));
}
VkAssert(vkBindBufferMemory(vk.device, retbuf, mem->memory, mem->offset));
}
fence = VK_FencedBegin(VKBE_DoneBufferStaging, sizeof(*fence));
fence->buf = n->buf;
fence->mem = n->memory;
fence->mem = n->mem;
//FIXME: barrier?
@ -3893,7 +3913,7 @@ void VKBE_GenBatchVBOs(vbo_t **vbochain, batch_t *firstbatch, batch_t *stopbatch
index_t *vboedata;
qbyte *vbovdatastart, *vbovdata;
struct stagingbuf vbuf, ebuf;
VkDeviceMemory *retarded;
vk_poolmem_t *poolmem;
vbo = Z_Malloc(sizeof(*vbo));
@ -3960,17 +3980,17 @@ void VKBE_GenBatchVBOs(vbo_t **vbochain, batch_t *firstbatch, batch_t *stopbatch
}
}
vbo->vbomem = retarded = Z_Malloc(sizeof(*retarded));
vbo->vbomem = poolmem = Z_Malloc(sizeof(*poolmem));
vbo->coord.vk.buff =
vbo->texcoord.vk.buff =
vbo->lmcoord[0].vk.buff =
vbo->normals.vk.buff =
vbo->svector.vk.buff =
vbo->tvector.vk.buff =
vbo->colours[0].vk.buff = VKBE_FinishStaging(&vbuf, retarded);
vbo->colours[0].vk.buff = VKBE_FinishStaging(&vbuf, poolmem);
vbo->ebomem = retarded = Z_Malloc(sizeof(*retarded));
vbo->indicies.vk.buff = VKBE_FinishStaging(&ebuf, retarded);
vbo->ebomem = poolmem = Z_Malloc(sizeof(*poolmem));
vbo->indicies.vk.buff = VKBE_FinishStaging(&ebuf, poolmem);
vbo->indicies.vk.offs = 0;
vbo->indexcount = maxvboelements;
@ -4022,22 +4042,19 @@ struct vkbe_clearvbo
static void VKBE_SafeClearVBO(void *vboptr)
{
vbo_t *vbo = *(vbo_t**)vboptr;
VkDeviceMemory *retarded;
if (vbo->indicies.vk.buff)
{
vkDestroyBuffer(vk.device, vbo->indicies.vk.buff, vkallocationcb);
retarded = vbo->ebomem;
vkFreeMemory(vk.device, *retarded, vkallocationcb);
BZ_Free(retarded);
VK_ReleasePoolMemory(vbo->ebomem);
BZ_Free(vbo->ebomem);
}
if (vbo->coord.vk.buff)
{
vkDestroyBuffer(vk.device, vbo->coord.vk.buff, vkallocationcb);
retarded = vbo->vbomem;
vkFreeMemory(vk.device, *retarded, vkallocationcb);
BZ_Free(retarded);
VK_ReleasePoolMemory(vbo->vbomem);
BZ_Free(vbo->vbomem);
}
BZ_Free(vbo);
@ -4678,26 +4695,8 @@ void VKBE_RT_Gen(struct vk_rendertarg *targ, uint32_t width, uint32_t height, qb
depth_imginfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT|VK_IMAGE_USAGE_SAMPLED_BIT;
VkAssert(vkCreateImage(vk.device, &depth_imginfo, vkallocationcb, &targ->depth.image));
{
VkMemoryRequirements mem_reqs;
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
vkGetImageMemoryRequirements(vk.device, targ->colour.image, &mem_reqs);
memAllocInfo.allocationSize = mem_reqs.size;
memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0);
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &targ->colour.memory));
VkAssert(vkBindImageMemory(vk.device, targ->colour.image, targ->colour.memory, 0));
}
{
VkMemoryRequirements mem_reqs;
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
vkGetImageMemoryRequirements(vk.device, targ->depth.image, &mem_reqs);
memAllocInfo.allocationSize = mem_reqs.size;
memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0);
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &targ->depth.memory));
VkAssert(vkBindImageMemory(vk.device, targ->depth.image, targ->depth.memory, 0));
}
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);
@ -4867,26 +4866,8 @@ void VKBE_RT_Gen_Cube(struct vk_rendertarg_cube *targ, uint32_t size, qboolean c
depth_imginfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT|VK_IMAGE_USAGE_SAMPLED_BIT;
VkAssert(vkCreateImage(vk.device, &depth_imginfo, vkallocationcb, &targ->depth.image));
{
VkMemoryRequirements mem_reqs;
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
vkGetImageMemoryRequirements(vk.device, targ->colour.image, &mem_reqs);
memAllocInfo.allocationSize = mem_reqs.size;
memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0);
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &targ->colour.memory));
VkAssert(vkBindImageMemory(vk.device, targ->colour.image, targ->colour.memory, 0));
}
{
VkMemoryRequirements mem_reqs;
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
vkGetImageMemoryRequirements(vk.device, targ->depth.image, &mem_reqs);
memAllocInfo.allocationSize = mem_reqs.size;
memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0);
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &targ->depth.memory));
VkAssert(vkBindImageMemory(vk.device, targ->depth.image, targ->depth.memory, 0));
}
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);
@ -5809,12 +5790,12 @@ struct vk_shadowbuffer
VkBuffer vbuffer;
VkDeviceSize voffset;
VkDeviceMemory vmemory;
vk_poolmem_t vmemory;
unsigned int numverts;
VkBuffer ibuffer;
VkDeviceSize ioffset;
VkDeviceMemory imemory;
vk_poolmem_t imemory;
unsigned int numindicies;
};
//FIXME: needs context for threading
@ -5830,12 +5811,10 @@ struct vk_shadowbuffer *VKBE_GenerateShadowBuffer(vecV_t *verts, int numverts, i
map = VKBE_AllocateBufferSpace(DB_VBO, sizeof(*verts)*numverts, &buf->vbuffer, &buf->voffset);
memcpy(map, verts, sizeof(*verts)*numverts);
buf->vmemory = VK_NULL_HANDLE;
buf->numverts = numverts;
map = VKBE_AllocateBufferSpace(DB_EBO, sizeof(*indicies)*numindicies, &buf->ibuffer, &buf->ioffset);
memcpy(map, indicies, sizeof(*indicies)*numindicies);
buf->imemory = VK_NULL_HANDLE;
buf->numindicies = numindicies;
return buf;
}
@ -5866,8 +5845,8 @@ static void VKBE_DestroyShadowBuffer_Delayed(void *ctx)
struct vk_shadowbuffer *buf = ctx;
vkDestroyBuffer(vk.device, buf->vbuffer, vkallocationcb);
vkDestroyBuffer(vk.device, buf->ibuffer, vkallocationcb);
vkFreeMemory(vk.device, buf->vmemory, vkallocationcb);
vkFreeMemory(vk.device, buf->imemory, vkallocationcb);
VK_ReleasePoolMemory(&buf->vmemory);
VK_ReleasePoolMemory(&buf->imemory);
}
void VKBE_DestroyShadowBuffer(struct vk_shadowbuffer *buf)
{
@ -6359,33 +6338,33 @@ void VKBE_VBO_Finish(vbobctx_t *ctx, void *edata, size_t esize, vboarray_t *earr
{
struct stagingbuf *n;
struct stagingbuf ebo;
VkDeviceMemory *retarded;
vk_poolmem_t *poolmem;
index_t *map = VKBE_CreateStagingBuffer(&ebo, esize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
memcpy(map, edata, esize);
*ebomem = retarded = Z_Malloc(sizeof(*retarded));
earray->vk.buff = VKBE_FinishStaging(&ebo, retarded);
*ebomem = poolmem = Z_Malloc(sizeof(*poolmem));
earray->vk.buff = VKBE_FinishStaging(&ebo, poolmem);
earray->vk.offs = 0;
if (ctx)
{
n = ctx->vboptr[0];
*vbomem = retarded = Z_Malloc(sizeof(*retarded));
VKBE_FinishStaging(n, retarded);
*vbomem = poolmem = Z_Malloc(sizeof(*poolmem));
/*buffer was pre-created*/VKBE_FinishStaging(n, poolmem);
Z_Free(n);
}
}
void VKBE_VBO_Destroy(vboarray_t *vearray, void *mem)
{
VkDeviceMemory *retarded = mem;
vk_poolmem_t *poolmem = mem;
struct fencedbufferwork *fence;
if (!vearray->vk.buff)
return; //not actually allocated...
fence = VK_AtFrameEnd(VKBE_DoneBufferStaging, NULL, sizeof(*fence));
fence->buf = vearray->vk.buff;
fence->mem = *retarded;
fence->mem = *poolmem;
Z_Free(retarded);
Z_Free(poolmem);
}
void VKBE_Scissor(srect_t *rect)

View File

@ -12,10 +12,11 @@ extern cvar_t vk_dualqueue;
extern cvar_t vk_busywait;
extern cvar_t vk_waitfence;
extern cvar_t vk_nv_glsl_shader;
extern cvar_t vk_nv_dedicated_allocation;
extern cvar_t vk_khr_get_memory_requirements2;
extern cvar_t vk_khr_dedicated_allocation;
extern cvar_t vk_khr_push_descriptor;
extern cvar_t vk_amd_rasterization_order;
extern cvar_t vk_usememorypools;
extern cvar_t vid_srgb, vid_vsync, vid_triplebuffer, r_stereo_method, vid_multisample, vid_bpp;
void R2D_Console_Resize(void);
@ -182,8 +183,7 @@ void VK_DestroyVkTexture(vk_image_t *img)
vkDestroyImageView(vk.device, img->view, vkallocationcb);
if (img->image)
vkDestroyImage(vk.device, img->image, vkallocationcb);
if (img->memory)
vkFreeMemory(vk.device, img->memory, vkallocationcb);
VK_ReleasePoolMemory(&img->mem);
}
static void VK_DestroyVkTexture_Delayed(void *w)
{
@ -303,7 +303,7 @@ static qboolean VK_CreateSwapChain(void)
VkPresentModeKHR *presentmode;
VkSurfaceCapabilitiesKHR surfcaps;
VkSwapchainCreateInfoKHR swapinfo = {VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
uint32_t i, curpri;
uint32_t i, curpri, preaquirecount;
VkSwapchainKHR newvkswapchain;
VkImage *images;
VkDeviceMemory *memories;
@ -369,9 +369,7 @@ static qboolean VK_CreateSwapChain(void)
VkMemoryRequirements mem_reqs;
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
VkMemoryDedicatedAllocateInfoKHR khr_mdai = {VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR};
VkDedicatedAllocationMemoryAllocateInfoNV nv_damai = {VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV};
VkImageCreateInfo ici = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
VkDedicatedAllocationImageCreateInfoNV nv_daici = {VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV};
ici.flags = 0;
ici.imageType = VK_IMAGE_TYPE_2D;
@ -389,13 +387,6 @@ static qboolean VK_CreateSwapChain(void)
ici.pQueueFamilyIndices = NULL;
ici.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
if (vk.nv_dedicated_allocation)
{ //render targets should always have dedicated allocations, supposedly. and we're doing it anyway.
nv_daici.dedicatedAllocation = true;
nv_daici.pNext = ici.pNext;
ici.pNext = &nv_daici;
}
VkAssert(vkCreateImage(vk.device, &ici, vkallocationcb, &images[i]));
vkGetImageMemoryRequirements(vk.device, images[i], &mem_reqs);
@ -409,12 +400,6 @@ static qboolean VK_CreateSwapChain(void)
if (memAllocInfo.memoryTypeIndex == ~0)
memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0);
if (vk.nv_dedicated_allocation)
{ //annoying, but hey.
nv_damai.pNext = memAllocInfo.pNext;
nv_damai.image = images[i];
memAllocInfo.pNext = &nv_damai;
}
if (vk.khr_dedicated_allocation)
{
khr_mdai.pNext = memAllocInfo.pNext;
@ -478,11 +463,20 @@ static qboolean VK_CreateSwapChain(void)
if (surfcaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
swapinfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
else if (surfcaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
{
swapinfo.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
Con_Printf(CON_WARNING"Vulkan swapchain using composite alpha premultiplied\n");
}
else if (surfcaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
{
swapinfo.compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
Con_Printf(CON_WARNING"Vulkan swapchain using composite alpha postmultiplied\n");
}
else
{
swapinfo.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; //erk?
Con_Printf(CON_WARNING"composite alpha inherit\n");
}
swapinfo.imageArrayLayers = /*(r_stereo_method.ival==1)?2:*/1;
swapinfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapinfo.queueFamilyIndexCount = 0;
@ -663,7 +657,7 @@ static qboolean VK_CreateSwapChain(void)
vk.aquirelast = vk.aquirenext = 0;
for (i = 0; i < ACQUIRELIMIT; i++)
{
if (vk_waitfence.ival)
if (vk_waitfence.ival || !*vk_waitfence.string)
{
VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
VkAssert(vkCreateFence(vk.device,&fci,vkallocationcb,&vk.acquirefences[i]));
@ -676,8 +670,12 @@ static qboolean VK_CreateSwapChain(void)
vk.acquirefences[i] = VK_NULL_HANDLE;
}
}
if (!vk_submissionthread.value && *vk_submissionthread.string)
preaquirecount = 1;
else
preaquirecount = vk.backbuf_count;
/*-1 to hide any weird thread issues*/
while (vk.aquirelast < ACQUIRELIMIT-1 && vk.aquirelast < vk.backbuf_count && vk.aquirelast <= vk.backbuf_count-surfcaps.minImageCount)
while (vk.aquirelast < ACQUIRELIMIT-1 && vk.aquirelast < preaquirecount && vk.aquirelast <= vk.backbuf_count-surfcaps.minImageCount)
{
VkAssert(vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, vk.acquiresemaphores[vk.aquirelast%ACQUIRELIMIT], vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT]));
vk.aquirelast++;
@ -733,10 +731,10 @@ static qboolean VK_CreateSwapChain(void)
{
VkImageViewCreateInfo ivci = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
ivci.format = vk.backbufformat;
ivci.components.r = VK_COMPONENT_SWIZZLE_R;
ivci.components.g = VK_COMPONENT_SWIZZLE_G;
ivci.components.b = VK_COMPONENT_SWIZZLE_B;
ivci.components.a = VK_COMPONENT_SWIZZLE_A;
// ivci.components.r = VK_COMPONENT_SWIZZLE_R;
// ivci.components.g = VK_COMPONENT_SWIZZLE_G;
// ivci.components.b = VK_COMPONENT_SWIZZLE_B;
// ivci.components.a = VK_COMPONENT_SWIZZLE_A;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
ivci.subresourceRange.baseMipLevel = 0;
ivci.subresourceRange.levelCount = 1;
@ -747,7 +745,7 @@ static qboolean VK_CreateSwapChain(void)
ivci.image = images[i];
vk.backbufs[i].colour.image = images[i];
if (memories)
vk.backbufs[i].colour.memory = memories[i];
vk.backbufs[i].colour.mem.memory = memories[i];
vk.backbufs[i].colour.width = swapinfo.imageExtent.width;
vk.backbufs[i].colour.height = swapinfo.imageExtent.height;
VkAssert(vkCreateImageView(vk.device, &ivci, vkallocationcb, &vk.backbufs[i].colour.view));
@ -759,7 +757,6 @@ static qboolean VK_CreateSwapChain(void)
//depth image
{
VkImageCreateInfo depthinfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
VkDedicatedAllocationImageCreateInfoNV nv_daici = {VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV};
depthinfo.flags = 0;
depthinfo.imageType = VK_IMAGE_TYPE_2D;
depthinfo.format = vk.depthformat;
@ -775,39 +772,11 @@ static qboolean VK_CreateSwapChain(void)
depthinfo.queueFamilyIndexCount = 0;
depthinfo.pQueueFamilyIndices = NULL;
depthinfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
if (vk.nv_dedicated_allocation)
{
nv_daici.dedicatedAllocation = true;
nv_daici.pNext = depthinfo.pNext;
depthinfo.pNext = &nv_daici;
}
VkAssert(vkCreateImage(vk.device, &depthinfo, vkallocationcb, &vk.backbufs[i].depth.image));
}
//depth memory
{
VkMemoryRequirements mem_reqs;
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
VkMemoryDedicatedAllocateInfoKHR khr_mdai = {VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR};
VkDedicatedAllocationMemoryAllocateInfoNV nv_damai = {VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV};
vkGetImageMemoryRequirements(vk.device, vk.backbufs[i].depth.image, &mem_reqs);
memAllocInfo.allocationSize = mem_reqs.size;
memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0);
if (vk.nv_dedicated_allocation)
{
nv_damai.image = vk.backbufs[i].depth.image;
nv_damai.pNext = memAllocInfo.pNext;
memAllocInfo.pNext = &nv_damai;
}
if (vk.khr_dedicated_allocation)
{
khr_mdai.image = vk.backbufs[i].depth.image;
khr_mdai.pNext = memAllocInfo.pNext;
memAllocInfo.pNext = &khr_mdai;
}
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &vk.backbufs[i].depth.memory));
VkAssert(vkBindImageMemory(vk.device, vk.backbufs[i].depth.image, vk.backbufs[i].depth.memory, 0));
}
VK_AllocateBindImageMemory(&vk.backbufs[i].depth, true);
//depth view
{
@ -836,7 +805,6 @@ static qboolean VK_CreateSwapChain(void)
//mscolour image
{
VkImageCreateInfo mscolourinfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
VkDedicatedAllocationImageCreateInfoNV nv_daici = {VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV};
mscolourinfo.flags = 0;
mscolourinfo.imageType = VK_IMAGE_TYPE_2D;
mscolourinfo.format = vk.backbufformat;
@ -852,40 +820,11 @@ static qboolean VK_CreateSwapChain(void)
mscolourinfo.queueFamilyIndexCount = 0;
mscolourinfo.pQueueFamilyIndices = NULL;
mscolourinfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
if (vk.nv_dedicated_allocation)
{
nv_daici.dedicatedAllocation = true;
nv_daici.pNext = mscolourinfo.pNext;
mscolourinfo.pNext = &nv_daici;
}
VkAssert(vkCreateImage(vk.device, &mscolourinfo, vkallocationcb, &vk.backbufs[i].mscolour.image));
}
//mscolour memory
{
VkMemoryRequirements mem_reqs;
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
VkMemoryDedicatedAllocateInfoKHR khr_mdai = {VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR};
VkDedicatedAllocationMemoryAllocateInfoNV nv_damai = {VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV};
vkGetImageMemoryRequirements(vk.device, vk.backbufs[i].mscolour.image, &mem_reqs);
memAllocInfo.allocationSize = mem_reqs.size;
memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0);
if (vk.nv_dedicated_allocation)
{
nv_damai.image = vk.backbufs[i].mscolour.image;
nv_damai.pNext = memAllocInfo.pNext;
memAllocInfo.pNext = &nv_damai;
}
if (vk.khr_dedicated_allocation)
{
khr_mdai.image = vk.backbufs[i].mscolour.image;
khr_mdai.pNext = memAllocInfo.pNext;
memAllocInfo.pNext = &khr_mdai;
}
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &vk.backbufs[i].mscolour.memory));
VkAssert(vkBindImageMemory(vk.device, vk.backbufs[i].mscolour.image, vk.backbufs[i].mscolour.memory, 0));
}
VK_AllocateBindImageMemory(&vk.backbufs[i].mscolour, true);
//mscolour view
{
@ -1020,21 +959,133 @@ void VK_UpdateFiltering(image_t *imagelist, int filtermip[3], int filterpic[3],
}
}
qboolean VK_AllocatePoolMemory(uint32_t pooltype, VkDeviceSize memsize, VkDeviceSize poolalignment, vk_poolmem_t *mem)
{
struct vk_mempool_s *p;
VkDeviceSize pad;
if (!vk_usememorypools.ival)
return false;
if (memsize > 1024*1024*4)
return false;
for (p = vk.mempools; p; p = p->next)
{
if (p->memtype == pooltype)
{
if (p->memoryoffset + poolalignment + memsize < p->memorysize)
break;
}
}
if (!p)
{
VkMemoryAllocateInfo poolai = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
p = Z_Malloc(sizeof(*p));
p->memorysize = poolai.allocationSize = 512*1024*1024; //lets just allocate big...
p->memtype = poolai.memoryTypeIndex = pooltype;
if (VK_SUCCESS != vkAllocateMemory(vk.device, &poolai, vkallocationcb, &p->memory))
{ //out of memory? oh well, a smaller dedicated allocation might still work.
Z_Free(p);
return false;
}
p->next = vk.mempools;
vk.mempools = p;
}
pad = ((p->memoryoffset+poolalignment-1)&~(poolalignment-1)) - p->memoryoffset;
p->memoryoffset = (p->memoryoffset+poolalignment-1)&~(poolalignment-1);
p->gaps += pad;
mem->offset = p->memoryoffset;
mem->size = memsize; //FIXME: we have no way to deal with gaps due to alignment
mem->memory = p->memory;
mem->pool = p;
p->memoryoffset += memsize;
return true;
}
void VK_ReleasePoolMemory(vk_poolmem_t *mem)
{
if (mem->pool)
{
//FIXME: track power-of-two holes?
mem->pool->gaps += mem->size;
mem->pool = NULL;
mem->memory = VK_NULL_HANDLE;
}
else if (mem->memory)
{
vkFreeMemory(vk.device, mem->memory, vkallocationcb);
mem->memory = VK_NULL_HANDLE;
}
}
//does NOT bind.
//image memory is NOT expected to be host-visible. you'll get what vulkan gives you.
qboolean VK_AllocateImageMemory(VkImage image, qboolean dedicated, vk_poolmem_t *mem)
{
uint32_t pooltype;
VkMemoryRequirements2KHR mem_reqs2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR};
if (!dedicated && vk.khr_get_memory_requirements2)
{
VkImageMemoryRequirementsInfo2KHR imri = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR};
VkMemoryDedicatedRequirementsKHR mdr = {VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR};
imri.image = image;
if (vk.khr_dedicated_allocation)
mem_reqs2.pNext = &mdr; //chain the result struct
vkGetImageMemoryRequirements2KHR(vk.device, &imri, &mem_reqs2);
//and now we know if it should be dedicated or not.
dedicated |= mdr.prefersDedicatedAllocation || mdr.requiresDedicatedAllocation;
}
else
vkGetImageMemoryRequirements(vk.device, image, &mem_reqs2.memoryRequirements);
pooltype = vk_find_memory_try(mem_reqs2.memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
if (pooltype == ~0)
pooltype = vk_find_memory_require(mem_reqs2.memoryRequirements.memoryTypeBits, 0);
if (!dedicated && VK_AllocatePoolMemory(pooltype, mem_reqs2.memoryRequirements.size, mem_reqs2.memoryRequirements.alignment, mem))
return true; //got a shared allocation.
else
{ //make it dedicated one way or another.
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
VkMemoryDedicatedAllocateInfoKHR khr_mdai = {VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR};
//shouldn't really happen, but just in case...
mem_reqs2.memoryRequirements.size = max(1,mem_reqs2.memoryRequirements.size);
memAllocInfo.allocationSize = mem_reqs2.memoryRequirements.size;
memAllocInfo.memoryTypeIndex = pooltype;
if (vk.khr_dedicated_allocation)
{
khr_mdai.image = image;
khr_mdai.pNext = memAllocInfo.pNext;
memAllocInfo.pNext = &khr_mdai;
}
mem->pool = NULL;
mem->offset = 0;
mem->size = mem_reqs2.memoryRequirements.size;
mem->memory = VK_NULL_HANDLE;
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &mem->memory));
return true;
}
}
void VK_AllocateBindImageMemory(vk_image_t *image, qboolean dedicated)
{
if (VK_AllocateImageMemory(image->image, dedicated, &image->mem))
VkAssert(vkBindImageMemory(vk.device, image->image, image->mem.memory, image->mem.offset));
}
vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t layers, uint32_t mips, uploadfmt_t encoding, unsigned int type, qboolean rendertarget)
{
vk_image_t ret;
#ifdef USE_STAGING_BUFFERS
qboolean staging = layers == 0;
#else
const qboolean staging = false;
#endif
VkMemoryRequirements mem_reqs;
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
VkMemoryDedicatedAllocateInfoKHR khr_mdai = {VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR};
VkDedicatedAllocationMemoryAllocateInfoNV nv_damai = {VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV};
VkImageViewCreateInfo viewInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
VkImageCreateInfo ici = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
VkDedicatedAllocationImageCreateInfoNV nv_daici = {VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV};
VkFormat format = VK_FORMAT_UNDEFINED;;
ret.width = width;
@ -1043,7 +1094,7 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay
ret.mipcount = mips;
ret.encoding = encoding;
ret.type = type;
ret.layout = staging?VK_IMAGE_LAYOUT_PREINITIALIZED:VK_IMAGE_LAYOUT_UNDEFINED;
ret.layout = VK_IMAGE_LAYOUT_UNDEFINED;
//vulkan expresses packed formats in terms of native endian (if big-endian, then everything makes sense), non-packed formats are expressed in byte order (consistent with big-endian).
//PTI formats are less well-defined...
@ -1165,102 +1216,67 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay
ici.extent.height = height;
ici.extent.depth = 1;
ici.mipLevels = mips;
ici.arrayLayers = staging?1:layers;
ici.arrayLayers = layers;
ici.samples = VK_SAMPLE_COUNT_1_BIT;
ici.tiling = staging?VK_IMAGE_TILING_LINEAR:VK_IMAGE_TILING_OPTIMAL;
ici.usage = staging?VK_IMAGE_USAGE_TRANSFER_SRC_BIT:(VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT);
ici.tiling = VK_IMAGE_TILING_OPTIMAL;
ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT|(rendertarget?0:VK_IMAGE_USAGE_TRANSFER_DST_BIT);
ici.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
ici.queueFamilyIndexCount = 0;
ici.pQueueFamilyIndices = NULL;
ici.initialLayout = ret.layout;
if (vk.nv_dedicated_allocation/* && (size > foo || rendertarget)*/) //FIXME: should only really be used for rendertargets or large images, other stuff should be merged. however, as we don't support any memory suballocations, we're going to just flag everything for now.
{
nv_daici.dedicatedAllocation = true;
nv_daici.pNext = ici.pNext;
ici.pNext = &nv_daici;
}
VkAssert(vkCreateImage(vk.device, &ici, vkallocationcb, &ret.image));
vkGetImageMemoryRequirements(vk.device, ret.image, &mem_reqs);
memAllocInfo.allocationSize = mem_reqs.size;
if (staging)
memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
else
{
memAllocInfo.memoryTypeIndex = vk_find_memory_try(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
if (memAllocInfo.memoryTypeIndex == ~0)
memAllocInfo.memoryTypeIndex = vk_find_memory_try(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
if (memAllocInfo.memoryTypeIndex == ~0)
memAllocInfo.memoryTypeIndex = vk_find_memory_try(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
if (memAllocInfo.memoryTypeIndex == ~0)
memAllocInfo.memoryTypeIndex = vk_find_memory_require(mem_reqs.memoryTypeBits, 0);
}
if (nv_daici.dedicatedAllocation)
{
nv_damai.image = ret.image;
nv_damai.pNext = memAllocInfo.pNext;
memAllocInfo.pNext = &nv_damai;
}
if (vk.khr_dedicated_allocation)
{
khr_mdai.image = ret.image;
khr_mdai.pNext = memAllocInfo.pNext;
memAllocInfo.pNext = &khr_mdai;
}
VkAssert(vkAllocateMemory(vk.device, &memAllocInfo, vkallocationcb, &ret.memory));
VkAssert(vkBindImageMemory(vk.device, ret.image, ret.memory, 0));
VK_AllocateBindImageMemory(&ret, false);
ret.view = VK_NULL_HANDLE;
ret.sampler = VK_NULL_HANDLE;
if (!staging)
viewInfo.flags = 0;
viewInfo.image = ret.image;
viewInfo.viewType = (ret.type==PTI_CUBEMAP)?VK_IMAGE_VIEW_TYPE_CUBE:VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = format;
switch(encoding)
{
VkImageViewCreateInfo viewInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
viewInfo.flags = 0;
viewInfo.image = ret.image;
viewInfo.viewType = (ret.type==PTI_CUBEMAP)?VK_IMAGE_VIEW_TYPE_CUBE:VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = format;
switch(encoding)
{
//formats that explicitly drop the alpha
case PTI_BC1_RGB:
case PTI_BC1_RGB_SRGB:
case PTI_RGBX8:
case PTI_RGBX8_SRGB:
case PTI_BGRX8:
case PTI_BGRX8_SRGB:
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_ONE;
break;
case PTI_L8: //must be an R8 texture
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_ONE;
break;
case PTI_L8A8: //must be an RG8 texture
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_G;
break;
default:
viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
break;
}
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = mips;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = layers;
VkAssert(vkCreateImageView(vk.device, &viewInfo, NULL, &ret.view));
//formats that explicitly drop the alpha
case PTI_BC1_RGB:
case PTI_BC1_RGB_SRGB:
case PTI_RGBX8:
case PTI_RGBX8_SRGB:
case PTI_BGRX8:
case PTI_BGRX8_SRGB:
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_ONE;
break;
case PTI_L8: //must be an R8 texture
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_ONE;
break;
case PTI_L8A8: //must be an RG8 texture
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_G;
break;
default:
viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
break;
}
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = mips;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = layers;
VkAssert(vkCreateImageView(vk.device, &viewInfo, NULL, &ret.view));
return ret;
}
void set_image_layout(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask,
@ -1366,6 +1382,7 @@ void VK_FencedSubmit(void *work)
//check if we can release anything yet.
VK_FencedCheck();
//FIXME: this seems to be an excessively expensive function.
vkCreateFence(vk.device, &fenceinfo, vkallocationcb, &w->fence);
VK_Submit_Work(w->cbuf, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, w->fence, NULL, w);
@ -1423,45 +1440,26 @@ void *VK_AtFrameEnd(void (*frameended)(void *work), void *workdata, size_t works
return w+1;
}
#define USE_STAGING_BUFFERS
struct texturefence
{
struct vk_fencework w;
int mips;
#ifdef USE_STAGING_BUFFERS
VkBuffer stagingbuffer;
VkDeviceMemory stagingmemory;
#else
vk_image_t staging[32];
#endif
};
static void VK_TextureLoaded(void *ctx)
{
struct texturefence *w = ctx;
#ifdef USE_STAGING_BUFFERS
vkDestroyBuffer(vk.device, w->stagingbuffer, vkallocationcb);
vkFreeMemory(vk.device, w->stagingmemory, vkallocationcb);
#else
unsigned int i;
for (i = 0; i < w->mips; i++)
if (w->staging[i].image != VK_NULL_HANDLE)
{
vkDestroyImage(vk.device, w->staging[i].image, vkallocationcb);
vkFreeMemory(vk.device, w->staging[i].memory, vkallocationcb);
}
#endif
}
qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips)
{
#ifdef USE_STAGING_BUFFERS
VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
VkMemoryRequirements mem_reqs;
VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
void *mapdata;
#else
uint32_t y;
#endif
struct texturefence *fence;
VkCommandBuffer vkloadcmd;
@ -1571,7 +1569,6 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips)
}
}
#ifdef USE_STAGING_BUFFERS
//figure out how big our staging buffer needs to be
bci.size = 0;
for (i = 0; i < mipcount; i++)
@ -1636,63 +1633,6 @@ qboolean VK_LoadTextureMips (texid_t tex, const struct pendingtextureinfo *mips)
bci.size += blockswidth*blocksheight*blockbytes;
}
vkUnmapMemory(vk.device, fence->stagingmemory);
#else
//create the staging images and fill them
for (i = 0; i < mipcount; i++)
{
VkImageSubresource subres = {0};
VkSubresourceLayout layout;
void *mapdata;
//figure out the number of 'blocks' in the image.
//for non-compressed formats this is just the width directly.
//for compressed formats (ie: s3tc/dxt) we need to round up to deal with npot.
uint32_t blockswidth = (mips->mip[i].width+blockwidth-1) / blockwidth;
uint32_t blocksheight = (mips->mip[i].height+blockheight-1) / blockheight;
fence->staging[i] = VK_CreateTexture2DArray(mips->mip[i].width, mips->mip[i].height, 0, 1, mips->encoding, PTI_2D);
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subres.mipLevel = 0;
subres.arrayLayer = 0;
vkGetImageSubresourceLayout(vk.device, fence->staging[i].image, &subres, &layout);
VkAssert(vkMapMemory(vk.device, fence->staging[i].memory, 0, layout.size, 0, &mapdata));
if (mapdata)
{
for (y = 0; y < blockheight; y++)
memcpy((char*)mapdata + layout.offset + y*layout.rowPitch, (char*)mips->mip[i].data + y*blockswidth*blockbytes, blockswidth*blockbytes);
}
else
Sys_Error("Unable to map staging image\n");
vkUnmapMemory(vk.device, fence->staging[i].memory);
//queue up an image copy for this mip
{
VkImageCopy region;
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.srcSubresource.mipLevel = 0;
region.srcSubresource.baseArrayLayer = 0;
region.srcSubresource.layerCount = 1;
region.srcOffset.x = 0;
region.srcOffset.y = 0;
region.srcOffset.z = 0;
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.dstSubresource.mipLevel = i%(mipcount/layers);
region.dstSubresource.baseArrayLayer = i/(mipcount/layers);
region.dstSubresource.layerCount = 1;
region.dstOffset.x = 0;
region.dstOffset.y = 0;
region.dstOffset.z = 0;
region.extent.width = mips->mip[i].width;
region.extent.height = mips->mip[i].height;
region.extent.depth = 1;
set_image_layout(vkloadcmd, fence->staging[i].image, VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_PREINITIALIZED, VK_ACCESS_HOST_WRITE_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT);
vkCmdCopyImage(vkloadcmd, fence->staging[i].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, target.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
}
}
#endif
//layouts are annoying. and weird.
{
@ -3079,7 +3019,7 @@ qboolean VK_SCR_GrabBackBuffer(void)
imgbarrier.pNext = NULL;
imgbarrier.srcAccessMask = 0;//VK_ACCESS_MEMORY_READ_BIT;
imgbarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imgbarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;//vk.rendertarg->colour.layout; //'Alternately, oldLayout can be VK_IMAGE_LAYOUT_UNDEFINED, if the images contents need not be preserved.'
imgbarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;//vk.rendertarg->colour.layout; //'Alternately, oldLayout can be VK_IMAGE_LAYOUT_UNDEFINED, if the image's contents need not be preserved.'
imgbarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imgbarrier.image = vk.frame->backbuf->colour.image;
imgbarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@ -3216,7 +3156,7 @@ void VK_DebugFramerate(void)
qboolean VK_SCR_UpdateScreen (void)
{
uint32_t fblayout;
VkImageLayout fblayout;
VK_FencedCheck();
@ -3519,7 +3459,12 @@ void VK_DoPresent(struct vkframe *theframe)
RSpeedMark();
if (err)
{
Con_Printf("ERROR: vkQueuePresentKHR: %x\n", err);
if (err == VK_SUBOPTIMAL_KHR)
Con_DPrintf("vkQueuePresentKHR: VK_SUBOPTIMAL_KHR\n");
else if (err == VK_ERROR_OUT_OF_DATE_KHR)
Con_DPrintf("vkQueuePresentKHR: VK_ERROR_OUT_OF_DATE_KHR\n");
else
Con_Printf("ERROR: vkQueuePresentKHR: %i\n", err);
vk.neednewswapchain = true;
}
else
@ -3527,7 +3472,7 @@ void VK_DoPresent(struct vkframe *theframe)
err = vkAcquireNextImageKHR(vk.device, vk.swapchain, 0, vk.acquiresemaphores[vk.aquirelast%ACQUIRELIMIT], vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT]);
if (err)
{
Con_Printf("ERROR: vkAcquireNextImageKHR: %x\n", err);
Con_Printf("ERROR: vkAcquireNextImageKHR: %i\n", err);
vk.neednewswapchain = true;
vk.devicelost |= (err == VK_ERROR_DEVICE_LOST);
}
@ -3657,7 +3602,12 @@ void VK_Submit_Work(VkCommandBuffer cmdbuf, VkSemaphore semwait, VkPipelineStage
*link = work;
#ifdef MULTITHREAD
if (vk.submitthread && !vk.neednewswapchain)
if (vk.neednewswapchain && vk.submitthread)
{ //if we're trying to kill the submission thread, don't post work to it - instead wait for it to die cleanly then do it ourselves.
Sys_WaitOnThread(vk.submitthread);
vk.submitthread = NULL;
}
if (vk.submitthread)
Sys_ConditionSignal(vk.submitcondition);
else
#endif
@ -3796,6 +3746,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
VkResult err;
VkApplicationInfo app;
VkInstanceCreateInfo inst_info;
int gpuidx;
const char *extensions[8];
uint32_t extensions_count = 0;
@ -3812,12 +3763,12 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
qboolean supported;
} knowndevexts[] =
{
{&vk.khr_swapchain, VK_KHR_SWAPCHAIN_EXTENSION_NAME, NULL, true, NULL, " Nothing will be drawn!"},
{&vk.nv_glsl_shader, VK_NV_GLSL_SHADER_EXTENSION_NAME, &vk_nv_glsl_shader, false, NULL, " Direct use of glsl is not supported."},
{&vk.nv_dedicated_allocation, VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME, &vk_nv_dedicated_allocation, true, &vk.khr_dedicated_allocation, NULL},
{&vk.khr_dedicated_allocation, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, &vk_khr_dedicated_allocation, true, NULL, NULL},
{&vk.khr_push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, &vk_khr_push_descriptor, true, NULL, NULL},
{&vk.amd_rasterization_order, VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME, &vk_amd_rasterization_order, false, NULL, NULL},
{&vk.khr_swapchain, VK_KHR_SWAPCHAIN_EXTENSION_NAME, NULL, true, NULL, " Nothing will be drawn!"},
{&vk.nv_glsl_shader, VK_NV_GLSL_SHADER_EXTENSION_NAME, &vk_nv_glsl_shader, false, NULL, " Direct use of glsl is not supported."},
{&vk.khr_get_memory_requirements2, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,&vk_khr_get_memory_requirements2,true, NULL, NULL},
{&vk.khr_dedicated_allocation, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, &vk_khr_dedicated_allocation, true, NULL, NULL},
{&vk.khr_push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, &vk_khr_push_descriptor, true, NULL, NULL},
{&vk.amd_rasterization_order, VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME, &vk_amd_rasterization_order, false, NULL, NULL},
};
size_t e;
@ -3959,6 +3910,17 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
uint32_t gpucount = 0, i;
uint32_t bestpri = ~0u, pri;
VkPhysicalDevice *devs;
char *s = info->subrenderer;
int wantdev = -1;
if (*s)
{
if (!Q_strncasecmp(s, "GPU", 3))
s += 3;
wantdev = strtoul(s, &s, 0);
if (*s) //its a named device.
wantdev = -1;
}
vkEnumeratePhysicalDevices(vk.instance, &gpucount, NULL);
if (!gpucount)
{
@ -3993,7 +3955,10 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
Con_DPrintf("Found Vulkan Device \"%s\"\n", props.deviceName);
if (!vk.gpu)
{
gpuidx = i;
vk.gpu = devs[i];
}
switch(props.deviceType)
{
default:
@ -4013,17 +3978,27 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
pri = 4;
break;
}
if (!Q_strcasecmp(props.deviceName, info->subrenderer))
pri = 0;
if (wantdev >= 0)
{
if (wantdev == i)
pri = 0;
}
else
{
if (!Q_strcasecmp(props.deviceName, info->subrenderer))
pri = 0;
}
if (pri < bestpri)
{
vk.gpu = devs[i];
gpuidx = i;
vk.gpu = devs[gpuidx];
bestpri = pri;
}
}
free(devs);
if (bestpri == ~0u)
if (!vk.gpu)
{
Con_Printf("vulkan: unable to pick a usable device\n");
return false;
@ -4037,7 +4012,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
switch(props.vendorID)
{
//explicit vendors
//explicit registered vendors
case 0x10001: vendor = "Vivante"; break;
case 0x10002: vendor = "VeriSilicon"; break;
@ -4053,6 +4028,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
case 0x1AEE: vendor = "Imagination";break;
case 0x1957: vendor = "Freescale"; break;
//I really have no idea who makes mobile gpus nowadays, but lets make some guesses.
case 0x1AE0: vendor = "Google"; break;
case 0x5333: vendor = "S3"; break;
case 0xA200: vendor = "NEC"; break;
@ -4076,8 +4052,8 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
case VK_PHYSICAL_DEVICE_TYPE_CPU: type = "software"; break;
}
Con_Printf("Vulkan %u.%u.%u: %s %s %s (%u.%u.%u)\n", VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion), VK_VERSION_PATCH(props.apiVersion),
type, vendor, props.deviceName,
Con_Printf("Vulkan %u.%u.%u: GPU%i %s %s %s (%u.%u.%u)\n", VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion), VK_VERSION_PATCH(props.apiVersion),
gpuidx, type, vendor, props.deviceName,
VK_VERSION_MAJOR(props.driverVersion), VK_VERSION_MINOR(props.driverVersion), VK_VERSION_PATCH(props.driverVersion)
);
}
@ -4205,7 +4181,7 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
Con_DPrintf("Using %s.\n", knowndevexts[e].name);
devextensions[numdevextensions++] = knowndevexts[e].name;
}
else if (knowndevexts[e].var->ival)
else if (knowndevexts[e].var && knowndevexts[e].var->ival)
Con_Printf("unable to enable %s extension.%s\n", knowndevexts[e].name, knowndevexts[e].warningtext?knowndevexts[e].warningtext:"");
else if (knowndevexts[e].supported)
Con_DPrintf("Ignoring %s.\n", knowndevexts[e].name);
@ -4255,7 +4231,43 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
devinf.ppEnabledExtensionNames = devextensions;
devinf.pEnabledFeatures = &features;
err = vkCreateDevice(vk.gpu, &devinf, NULL, &vk.device);
#if 0
if (vkEnumeratePhysicalDeviceGroupsKHR && vk_afr.ival)
{
//'Every physical device must be in exactly one device group'. So we can just use the first group that lists it and automatically get AFR.
uint32_t gpugroups = 0;
VkDeviceGroupDeviceCreateInfoKHX dgdci = {VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR};
VkPhysicalDeviceGroupPropertiesKHR *groups;
vkEnumeratePhysicalDeviceGroupsKHR(vk.instance, &gpugroups, NULL);
groups = malloc(sizeof(*groups)*gpugroups);
vkEnumeratePhysicalDeviceGroupsKHR(vk.instance, &gpugroups, groups);
for (i = 0; i < gpugroups; i++)
{
for (j = 0; j < groups[i].physicalDeviceCount; j++)
if (groups[i].physicalDevices[j] == vk.gpu)
{
dgdci.physicalDeviceCount = groups[i].physicalDeviceCount;
dgdci.pPhysicalDevices = groups[i].physicalDevices;
break;
}
}
if (dgdci.physicalDeviceCount > 1)
{
vk.subdevices = dgdci.physicalDeviceCount;
dgdci.pNext = devinf.pNext;
devinf.pNext = &dgdci;
}
err = vkCreateDevice(vk.gpu, &devinf, NULL, &vk.device);
free(groups);
}
else
#endif
err = vkCreateDevice(vk.gpu, &devinf, NULL, &vk.device);
switch(err)
{
case VK_ERROR_INCOMPATIBLE_DRIVER:
@ -4396,6 +4408,15 @@ void VK_Shutdown(void)
vkDestroyPipelineCache(vk.device, vk.pipelinecache, vkallocationcb);
}
while(vk.mempools)
{
void *l;
vkFreeMemory(vk.device, vk.mempools->memory, vkallocationcb);
l = vk.mempools;
vk.mempools = vk.mempools->next;
Z_Free(l);
}
if (vk.device)
vkDestroyDevice(vk.device, vkallocationcb);
if (vk_debugcallback)

View File

@ -58,6 +58,7 @@
//funcs specific to an instance
#define VKInst2Funcs \
VKFunc(EnumeratePhysicalDevices) \
VKFunc(EnumeratePhysicalDeviceGroupsKHX) \
VKFunc(EnumerateDeviceExtensionProperties) \
VKFunc(GetPhysicalDeviceProperties) \
VKFunc(GetPhysicalDeviceQueueFamilyProperties) \
@ -126,6 +127,7 @@
VKFunc(GetDeviceQueue) \
VKFunc(GetBufferMemoryRequirements) \
VKFunc(GetImageMemoryRequirements) \
VKFunc(GetImageMemoryRequirements2KHR) \
VKFunc(GetImageSubresourceLayout) \
VKFunc(CreateFramebuffer) \
VKFunc(DestroyFramebuffer) \
@ -193,10 +195,18 @@
#define VkWarnAssert(f) f
#endif
typedef struct
{
struct vk_mempool_s *pool;
VkDeviceMemory memory;
size_t size;
size_t offset;
} vk_poolmem_t;
typedef struct vk_image_s
{
VkImage image;
VkDeviceMemory memory;
vk_poolmem_t mem;
VkImageView view;
VkSampler sampler;
VkImageLayout layout;
@ -256,12 +266,12 @@ extern struct vulkaninfo_s
qboolean vsync;
qboolean allowsubmissionthread;
qboolean khr_swapchain; //aka: not headless. we're actually rendering stuff!
qboolean nv_glsl_shader; //we can load glsl shaders. probably missing lots of reflection info though, so this is probably too limited.
qboolean nv_dedicated_allocation; //nvidia-specific extension that provides hints that there's no memory aliasing going on.
qboolean khr_dedicated_allocation; //standardised version of the above where the driver decides whether a resource is worth a dedicated allocation.
qboolean khr_push_descriptor; //more efficient descriptor streaming
qboolean amd_rasterization_order; //allows primitives to draw in any order
qboolean khr_swapchain; //aka: not headless. we're actually rendering stuff!
qboolean nv_glsl_shader; //we can load glsl shaders. probably missing lots of reflection info though, so this is probably too limited.
qboolean khr_get_memory_requirements2; //slightly richer info
qboolean khr_dedicated_allocation; //standardised version of the above where the driver decides whether a resource is worth a dedicated allocation.
qboolean khr_push_descriptor; //more efficient descriptor streaming
qboolean amd_rasterization_order; //allows primitives to draw in any order
VkInstance instance;
VkDevice device;
@ -299,6 +309,19 @@ extern struct vulkaninfo_s
float max_anistophy;
float max_anistophy_limit;
struct vk_mempool_s
{
struct vk_mempool_s *next;
uint32_t memtype;
VkDeviceMemory memory;
//FIXME: replace with an ordered list of free blocks.
VkDeviceSize gaps;
VkDeviceSize memoryoffset;
VkDeviceSize memorysize;
} *mempools;
struct descpool
{
VkDescriptorPool pool;
@ -450,11 +473,15 @@ void VKBE_RT_End(struct vk_rendertarg *targ);
void VKBE_RT_Destroy(struct vk_rendertarg *targ);
qboolean VK_AllocatePoolMemory(uint32_t pooltype, VkDeviceSize memsize, VkDeviceSize poolalignment, vk_poolmem_t *mem);
void VK_ReleasePoolMemory(vk_poolmem_t *mem);
qboolean VK_AllocateImageMemory(VkImage image, qboolean dedicated, vk_poolmem_t *mem); //dedicated should normally be TRUE for render targets
void VK_AllocateBindImageMemory(vk_image_t *image, qboolean dedicated); //dedicated should normally be TRUE for render targets
struct stagingbuf
{
VkBuffer buf;
VkBuffer retbuf;
VkDeviceMemory memory;
vk_poolmem_t mem;
size_t size;
VkBufferUsageFlags usage;
};
@ -462,7 +489,7 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay
void set_image_layout(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout old_image_layout, VkAccessFlags srcaccess, VkPipelineStageFlagBits srcstagemask, VkImageLayout new_image_layout, VkAccessFlags dstaccess, VkPipelineStageFlagBits dststagemask);
void VK_CreateSampler(unsigned int flags, vk_image_t *img);
void *VKBE_CreateStagingBuffer(struct stagingbuf *n, size_t size, VkBufferUsageFlags usage);
VkBuffer VKBE_FinishStaging(struct stagingbuf *n, VkDeviceMemory *memptr);
VkBuffer VKBE_FinishStaging(struct stagingbuf *n, vk_poolmem_t *memptr);
void *VK_FencedBegin(void (*passed)(void *work), size_t worksize);
void VK_FencedSubmit(void *work);
void VK_FencedCheck(void);