diff --git a/src/console.c b/src/console.c
index 826153ff00245a82caa99c7d0918d316feb5acd5..6dd3fadfffb1c6208600a1f4d03feefabb52d6a7 100644
--- a/src/console.c
+++ b/src/console.c
@@ -1585,12 +1585,15 @@ void CON_Drawer(void)
 
 	if (needpatchrecache)
 	{
-		W_FlushCachedPatches();
+		Z_FlushCachedPatches();
 		HU_LoadGraphics();
 	}
 
 	if (con_recalc)
+	{
 		CON_RecalcSize();
+		CON_ClearHUD();
+	}
 
 	if (con_curlines > 0)
 		CON_DrawConsole();
diff --git a/src/f_finale.c b/src/f_finale.c
index 58d57948b764eb83d39f2f4e0543892e5207bc31..b97a6206e7314d48ea29162cf2f7a6a820b9281a 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -1451,21 +1451,21 @@ void F_GameEndTicker(void)
 // ==============
 static void F_CacheTitleScreen(void)
 {
-	ttbanner = W_CachePatchName("TTBANNER", PU_LEVEL);
-	ttwing = W_CachePatchName("TTWING", PU_LEVEL);
-	ttsonic = W_CachePatchName("TTSONIC", PU_LEVEL);
-	ttswave1 = W_CachePatchName("TTSWAVE1", PU_LEVEL);
-	ttswave2 = W_CachePatchName("TTSWAVE2", PU_LEVEL);
-	ttswip1 = W_CachePatchName("TTSWIP1", PU_LEVEL);
-	ttsprep1 = W_CachePatchName("TTSPREP1", PU_LEVEL);
-	ttsprep2 = W_CachePatchName("TTSPREP2", PU_LEVEL);
-	ttspop1 = W_CachePatchName("TTSPOP1", PU_LEVEL);
-	ttspop2 = W_CachePatchName("TTSPOP2", PU_LEVEL);
-	ttspop3 = W_CachePatchName("TTSPOP3", PU_LEVEL);
-	ttspop4 = W_CachePatchName("TTSPOP4", PU_LEVEL);
-	ttspop5 = W_CachePatchName("TTSPOP5", PU_LEVEL);
-	ttspop6 = W_CachePatchName("TTSPOP6", PU_LEVEL);
-	ttspop7 = W_CachePatchName("TTSPOP7", PU_LEVEL);
+	ttbanner = W_CachePatchName("TTBANNER", PU_PATCH);
+	ttwing = W_CachePatchName("TTWING", PU_PATCH);
+	ttsonic = W_CachePatchName("TTSONIC", PU_PATCH);
+	ttswave1 = W_CachePatchName("TTSWAVE1", PU_PATCH);
+	ttswave2 = W_CachePatchName("TTSWAVE2", PU_PATCH);
+	ttswip1 = W_CachePatchName("TTSWIP1", PU_PATCH);
+	ttsprep1 = W_CachePatchName("TTSPREP1", PU_PATCH);
+	ttsprep2 = W_CachePatchName("TTSPREP2", PU_PATCH);
+	ttspop1 = W_CachePatchName("TTSPOP1", PU_PATCH);
+	ttspop2 = W_CachePatchName("TTSPOP2", PU_PATCH);
+	ttspop3 = W_CachePatchName("TTSPOP3", PU_PATCH);
+	ttspop4 = W_CachePatchName("TTSPOP4", PU_PATCH);
+	ttspop5 = W_CachePatchName("TTSPOP5", PU_PATCH);
+	ttspop6 = W_CachePatchName("TTSPOP6", PU_PATCH);
+	ttspop7 = W_CachePatchName("TTSPOP7", PU_PATCH);
 }
 
 void F_StartTitleScreen(void)
diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c
index 21fd85a33ce753b248774a66ba06acc4b224ba40..f8bf84c9a80cdee85e1733673996a50cd2888499 100644
--- a/src/hardware/hw_bsp.c
+++ b/src/hardware/hw_bsp.c
@@ -835,8 +835,10 @@ static INT32 SolveTProblem(void)
 		return 0;
 
 	CONS_Debug(DBG_RENDER, "Solving T-joins. This may take a while. Please wait...\n");
+#ifdef HWR_LOADING_SCREEN
 	CON_Drawer(); //let the user know what we are doing
 	I_FinishUpdate(); // page flip or blit buffer
+#endif
 
 	numsplitpoly = 0;
 
@@ -963,9 +965,9 @@ void HWR_CreatePlanePolygons(INT32 bspnum)
 	CONS_Debug(DBG_RENDER, "Creating polygons, please wait...\n");
 #ifdef HWR_LOADING_SCREEN
 	ls_count = ls_percent = 0; // reset the loading status
-#endif
 	CON_Drawer(); //let the user know what we are doing
 	I_FinishUpdate(); // page flip or blit buffer
+#endif
 
 	HWR_ClearPolys();
 
diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index 3857ad5d7264f5dabe527f0e5f6b7c92b67c4add..0716a130f253f2adba25e84b9f5eae2a9a9aac18 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -571,9 +571,18 @@ static void FreeMipmapColormap(INT32 patchnum, void *patch)
 	}
 }
 
-void HWR_FreeTextureCache(void)
+void HWR_FreeColormaps(void)
 {
 	INT32 i;
+
+	// Alam: free the Z_Blocks before freeing it's users
+	// free all skin after each level: must be done after pfnClearMipMapCache!
+	for (i = 0; i < numwadfiles; i++)
+		M_AATreeIterate(wadfiles[i]->hwrcache, FreeMipmapColormap);
+}
+
+void HWR_FreeTextureCache(void)
+{
 	// free references to the textures
 	HWD.pfnClearMipMapCache();
 
@@ -582,15 +591,6 @@ void HWR_FreeTextureCache(void)
 	Z_FreeTags(PU_HWRCACHE, PU_HWRCACHE);
 	Z_FreeTags(PU_HWRCACHE_UNLOCKED, PU_HWRCACHE_UNLOCKED);
 
-	// Alam: free the Z_Blocks before freeing it's users
-
-	// free all skin after each level: must be done after pfnClearMipMapCache!
-	// temp fix, idk why this crashes
-	// is it because the colormaps were already freed anyway?
-	if (!needpatchrecache)
-		for (i = 0; i < numwadfiles; i++)
-			M_AATreeIterate(wadfiles[i]->hwrcache, FreeMipmapColormap);
-
 	// now the heap don't have any 'user' pointing to our
 	// texturecache info, we can free it
 	if (gr_textures)
@@ -713,7 +713,7 @@ void HWR_GetFlat(lumpnum_t flatlumpnum)
 	GLMipmap_t *grmip;
 
 	if (needpatchflush)
-		W_FlushCachedPatches();
+		Z_FlushCachedPatches();
 
 	grmip = &HWR_GetCachedGLPatch(flatlumpnum)->mipmap;
 
@@ -752,7 +752,7 @@ static void HWR_LoadMappedPatch(GLMipmap_t *grmip, GLPatch_t *gpatch)
 void HWR_GetPatch(GLPatch_t *gpatch)
 {
 	if (needpatchflush)
-		W_FlushCachedPatches();
+		Z_FlushCachedPatches();
 
 	// is it in hardware cache
 	if (!gpatch->mipmap.downloaded && !gpatch->mipmap.grInfo.data)
@@ -782,7 +782,7 @@ void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap)
 	GLMipmap_t *grmip, *newmip;
 
 	if (needpatchflush)
-		W_FlushCachedPatches();
+		Z_FlushCachedPatches();
 
 	if (colormap == colormaps || colormap == NULL)
 	{
@@ -910,7 +910,7 @@ GLPatch_t *HWR_GetPic(lumpnum_t lumpnum)
 	GLPatch_t *grpatch;
 
 	if (needpatchflush)
-		W_FlushCachedPatches();
+		Z_FlushCachedPatches();
 
 	grpatch = HWR_GetCachedGLPatch(lumpnum);
 
@@ -1110,7 +1110,7 @@ void HWR_GetFadeMask(lumpnum_t fademasklumpnum)
 	GLMipmap_t *grmip;
 
 	if (needpatchflush)
-		W_FlushCachedPatches();
+		Z_FlushCachedPatches();
 
 	grmip = &HWR_GetCachedGLPatch(fademasklumpnum)->mipmap;
 
diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h
index bdf21946468b687344318c1ae84185c6f2df7d18..eb00802a38397d447c69d77375f6423f7b26f864 100644
--- a/src/hardware/hw_glob.h
+++ b/src/hardware/hw_glob.h
@@ -98,6 +98,7 @@ void HWR_FreePolyPool(void);
 // --------
 void HWR_InitTextureCache(void);
 void HWR_FreeTextureCache(void);
+void HWR_FreeColormaps(void);
 void HWR_FreeExtraSubsectors(void);
 
 void HWR_GetFlat(lumpnum_t flatlumpnum);
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 4f31b262a7c7c90275403db6bc562de767c8dc77..bcda8361e10932c5f16bb66f95cc474f763fa947 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -6461,6 +6461,7 @@ void HWR_Shutdown(void)
 	HWR_FreeExtraSubsectors();
 	HWR_FreePolyPool();
 	HWR_FreeTextureCache();
+	HWR_FreeColormaps();
 	HWD.pfnFlushScreenTextures();
 }
 
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 353e49f8112c63c9b0fe937d3a33c8775f8668b3..72ea8a4cfa4b7b3a4f9cfb020d44bae11e4d1134 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -857,7 +857,7 @@ void HWR_InitMD2(void)
 			}
 		}
 		// no sprite/player skin name found?!?
-		CONS_Printf("Unknown sprite/player skin %s detected in md2.dat\n", name);
+		//CONS_Printf("Unknown sprite/player skin %s detected in md2.dat\n", name);
 md2found:
 		// move on to next line...
 		continue;
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index b16125395a98fbd29aaf87078169bb0b8041da6e..ba8b3a6d92b0efff7b8fecd7e122c587f18a983d 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -334,7 +334,7 @@ static int libd_patchExists(lua_State *L)
 static int libd_cachePatch(lua_State *L)
 {
 	HUDONLY
-	LUA_PushUserdata(L, W_CachePatchName(luaL_checkstring(L, 1), PU_STATIC), META_PATCH);
+	LUA_PushUserdata(L, W_CachePatchName(luaL_checkstring(L, 1), PU_PATCH), META_PATCH);
 	return 1;
 }
 
diff --git a/src/m_menu.c b/src/m_menu.c
index 8ae341e3130a7addd7df605aadcee83f0335ac5c..9a55ced4b367eb46890973d55f545f03383545d2 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -2481,6 +2481,9 @@ void M_Drawer(void)
 	if (currentMenu == &MessageDef)
 		menuactive = true;
 
+	if (needpatchrecache)
+		R_ReloadHUDGraphics();
+
 	if (menuactive)
 	{
 		// now that's more readable with a faded background (yeah like Quake...)
@@ -5709,7 +5712,7 @@ static void M_DrawLevelStats(void)
 	V_DrawCenteredString(BASEVIDWIDTH/2, 24, V_YELLOWMAP, "PAGE 2 OF 2");
 
 	V_DrawString(72, 48, 0, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems));
-	V_DrawScaledPatch(40, 48-4, 0, W_CachePatchName("EMBLICON", PU_STATIC));
+	V_DrawScaledPatch(40, 48-4, 0, W_CachePatchName("EMBLICON", PU_PATCH));
 
 	M_DrawStatsMaps(statsLocation);
 }
diff --git a/src/p_setup.c b/src/p_setup.c
index 0058f7defa587c6f94ca16c04b1bf13c2019766a..82b9eb691cffcf318d1836c42a6bf74a65028332 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1424,7 +1424,6 @@ static void P_LoadRawSideDefs2(void *data)
 			case 606: //SoM: 4/4/2000: Just colormap transfer
 				// SoM: R_CreateColormap will only create a colormap in software mode...
 				// Perhaps we should just call it instead of doing the calculations here.
-				if (rendermode == render_soft || rendermode == render_none)
 				{
 					if (msd->toptexture[0] == '#' || msd->bottomtexture[0] == '#')
 					{
@@ -1447,11 +1446,6 @@ static void P_LoadRawSideDefs2(void *data)
 						else
 							sd->bottomtexture = num;
 					}
-					break;
-				}
-#ifdef HWRENDER
-				else
-				{
 					// for now, full support of toptexture only
 					if ((msd->toptexture[0] == '#' && msd->toptexture[1] && msd->toptexture[2] && msd->toptexture[3] && msd->toptexture[4] && msd->toptexture[5] && msd->toptexture[6])
 						|| (msd->bottomtexture[0] == '#' && msd->bottomtexture[1] && msd->bottomtexture[2] && msd->bottomtexture[3] && msd->bottomtexture[4] && msd->bottomtexture[5] && msd->bottomtexture[6]))
@@ -1503,26 +1497,8 @@ static void P_LoadRawSideDefs2(void *data)
 #undef ALPHA2INT
 #undef HEX2INT
 					}
-					else
-					{
-						if ((num = R_CheckTextureNumForName(msd->toptexture)) == -1)
-							sd->toptexture = 0;
-						else
-							sd->toptexture = num;
-
-						if ((num = R_CheckTextureNumForName(msd->midtexture)) == -1)
-							sd->midtexture = 0;
-						else
-							sd->midtexture = num;
-
-						if ((num = R_CheckTextureNumForName(msd->bottomtexture)) == -1)
-							sd->bottomtexture = 0;
-						else
-							sd->bottomtexture = num;
-					}
 					break;
 				}
-#endif
 
 			case 413: // Change music
 			{
@@ -2967,6 +2943,12 @@ boolean P_SetupLevel(boolean skipprecip)
 	globalweather = mapheaderinfo[gamemap-1]->weather;
 
 #ifdef HWRENDER // not win32 only 19990829 by Kin
+	// gotta free this regardless of rendermode.
+	// maybe we're not in opengl anymore.......
+	if (extrasubsectors)
+		free(extrasubsectors);
+	extrasubsectors = NULL;
+	// stuff like HWR_CreatePlanePolygons is called there
 	if (rendermode == render_opengl)
 		HWR_SetupLevel();
 #endif
@@ -3116,7 +3098,10 @@ boolean P_SetupLevel(boolean skipprecip)
 	// preload graphics
 #ifdef HWRENDER // not win32 only 19990829 by Kin
 	if (rendermode == render_opengl)
+	{
 		HWR_PrepLevelCache(numtextures);
+		//HWR_FreeColormaps();
+	}
 #endif
 
 	P_MapEnd();
@@ -3180,7 +3165,9 @@ void HWR_SetupLevel(void)
 #endif
 	// Correct missing sidedefs & deep water trick
 	HWR_CorrectSWTricks();
-	HWR_CreatePlanePolygons((INT32)numnodes - 1);
+	// don't do it twice...
+	if (!extrasubsectors)
+		HWR_CreatePlanePolygons((INT32)numnodes - 1);
 }
 #endif
 
diff --git a/src/r_data.c b/src/r_data.c
index cd50272b03b92894d197520fdb7731caa49dcbee..a487601a350734ae88411a532af3576d188f5455 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -95,8 +95,6 @@ size_t numspritelumps, max_spritelumps;
 
 // textures
 INT32 numtextures = 0; // total number of textures found,
-boolean needpatchflush = false;
-boolean needpatchrecache = false;
 // size of following tables
 
 texture_t **textures = NULL;
diff --git a/src/r_data.h b/src/r_data.h
index e6229d6c8ccbe896c53c758fc014aa94fd503368..5de51ccd4981708b77614c6af9cb699644dc10ec 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -96,7 +96,5 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3);
 const char *R_ColormapNameForNum(INT32 num);
 
 extern INT32 numtextures;
-extern boolean needpatchflush;
-extern boolean needpatchrecache;
 
 #endif
diff --git a/src/r_main.c b/src/r_main.c
index f7678b928c5648bce88c7fa1072af69a24f2f566..d7196427c037614ae2f3d44d25a49be41beca22b 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1353,7 +1353,7 @@ void R_InitHardwareMode(void)
 
 void R_ReloadHUDGraphics(void)
 {
-	W_FlushCachedPatches();
+	Z_FlushCachedPatches();
 	ST_LoadGraphics();
 	HU_LoadGraphics();
 	ST_ReloadSkinFaceGraphics();
diff --git a/src/screen.c b/src/screen.c
index d485a6367c6c2997ec176e2ece86443f6a5bd5da..7c8bfb14aee8cafa365b3627339ba012bb3904a2 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -72,11 +72,12 @@ consvar_t cv_scr_depth = {"scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NUL
 #endif
 consvar_t cv_renderview = {"renderview", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
-static void SCR_ChangeRenderer (void);
+static void SCR_ChangeRenderer(void);
+static void SCR_ActuallyChangeRenderer(void);
 static CV_PossibleValue_t cv_renderer_t[] = {{1, "Software"}, {2, "OpenGL"}, {0, NULL}};
-consvar_t cv_renderer = {"renderer", "Software", CV_CALL, cv_renderer_t, SCR_ChangeRenderer, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_renderer = {"renderer", "Software", CV_SAVE|CV_CALL, cv_renderer_t, SCR_ChangeRenderer, 0, NULL, NULL, 0, 0, NULL};
 
-static void SCR_ChangeFullscreen (void);
+static void SCR_ChangeFullscreen(void);
 
 consvar_t cv_fullscreen = {"fullscreen", "Yes", CV_SAVE|CV_CALL, CV_YesNo, SCR_ChangeFullscreen, 0, NULL, NULL, 0, 0, NULL};
 
@@ -376,6 +377,8 @@ void SCR_CheckDefaultMode(void)
 		// see note above
 		setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value) + 1;
 	}
+
+	SCR_ActuallyChangeRenderer();
 }
 
 // sets the modenum as the new default video mode to be saved in the config file
@@ -405,12 +408,28 @@ void SCR_ChangeFullscreen(void)
 #endif
 }
 
+static int target_renderer = 0;
+
+void SCR_ActuallyChangeRenderer(void)
+{
+	setrenderneeded = target_renderer;
+	// setting the same renderer twice WILL crash your game, so let's not, please
+	if (rendermode == setrenderneeded)
+		setrenderneeded = 0;
+}
+
 void SCR_ChangeRenderer(void)
 {
 	setrenderneeded = 0;
 
 	if (con_startup)
 	{
+		target_renderer = cv_renderer.value;
+		if (M_CheckParm("-opengl"))
+			target_renderer = rendermode = render_opengl;
+		else if (M_CheckParm("-software"))
+			target_renderer = rendermode = render_soft;
+		// set cv_renderer back
 		if (rendermode == render_soft)
 			CV_StealthSetValue(&cv_renderer, 1);
 		else if (rendermode == render_opengl)
@@ -419,13 +438,10 @@ void SCR_ChangeRenderer(void)
 	}
 
 	if (cv_renderer.value == 1)
-		setrenderneeded = render_soft;
+		target_renderer = render_soft;
 	else if (cv_renderer.value == 2)
-		setrenderneeded = render_opengl;
-
-	// setting the same renderer twice WILL crash your game, so let's not, please
-	if (rendermode == setrenderneeded)
-		setrenderneeded = 0;
+		target_renderer = render_opengl;
+	SCR_ActuallyChangeRenderer();
 }
 
 boolean SCR_IsAspectCorrect(INT32 width, INT32 height)
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 163e650b9fe1b522eb207b174a529e9da85263a0..7c068205d42f34953b5251fb9ed2d769eed9b982 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -139,7 +139,6 @@ static       SDL_bool    borderlesswindow = SDL_FALSE;
 // SDL2 vars
 SDL_Window   *window;
 SDL_Renderer *renderer;
-static int renderflags;
 static SDL_Texture  *texture;
 static SDL_bool      havefocus = SDL_TRUE;
 static const char *fallback_resolution_name = "Fallback";
@@ -1261,7 +1260,7 @@ void VID_PrepareModeList(void)
 #endif
 }
 
-static SDL_bool Impl_CreateContext(int flags)
+static SDL_bool Impl_CreateContext(void)
 {
 	// Renderer-specific stuff
 #ifdef HWRENDER
@@ -1280,7 +1279,7 @@ static SDL_bool Impl_CreateContext(int flags)
 #endif
 	if (rendermode == render_soft)
 	{
-		flags = 0; // Use this to set SDL_RENDERER_* flags now
+		int flags = 0; // Use this to set SDL_RENDERER_* flags now
 		if (usesdl2soft)
 			flags |= SDL_RENDERER_SOFTWARE;
 		else if (cv_vidwait.value)
@@ -1300,10 +1299,13 @@ static SDL_bool Impl_CreateContext(int flags)
 
 void VID_CheckRenderer(void)
 {
+	if (dedicated)
+		return;
+
 	if (setrenderneeded)
 	{
 		rendermode = setrenderneeded;
-		Impl_CreateContext(renderflags);
+		Impl_CreateContext();
 	}
 
 	SDLSetMode(vid.width, vid.height, USE_FULLSCREEN);
@@ -1335,29 +1337,15 @@ INT32 VID_SetMode(INT32 modeNum)
 	vid.recalc = 1;
 	vid.bpp = 1;
 
-	if (modeNum >= 0 && modeNum < MAXWINMODES)
-	{
-		vid.width = windowedModes[modeNum][0];
-		vid.height = windowedModes[modeNum][1];
-		vid.modenum = modeNum;
-	}
-	else
-	{
-		// just set the desktop resolution as a fallback
-		SDL_DisplayMode mode;
-		SDL_GetWindowDisplayMode(window, &mode);
-		if (mode.w >= 2048)
-		{
-			vid.width = 1920;
-			vid.height = 1200;
-		}
-		else
-		{
-			vid.width = mode.w;
-			vid.height = mode.h;
-		}
-		vid.modenum = -1;
-	}
+	if (modeNum < 0)
+		modeNum = 0;
+	if (modeNum >= MAXWINMODES)
+		modeNum = MAXWINMODES-1;
+
+	vid.width = windowedModes[modeNum][0];
+	vid.height = windowedModes[modeNum][1];
+	vid.modenum = modeNum;
+
 	//Impl_SetWindowName("SRB2 "VERSIONSTRING);
 	VID_CheckRenderer();
 	return SDL_TRUE;
@@ -1394,8 +1382,7 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
 		return SDL_FALSE;
 	}
 
-	renderflags = flags;
-	return Impl_CreateContext(flags);
+	return Impl_CreateContext();
 }
 
 /*
diff --git a/src/w_wad.c b/src/w_wad.c
index 00797b87d66b36386676a1569e388a9e08d4312c..96381635ae64ecd52393a34b015c67685e7641d2 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -831,7 +831,10 @@ void W_UnloadWadFile(UINT16 num)
 	numwadfiles--;
 #ifdef HWRENDER
 	if (rendermode != render_soft && rendermode != render_none)
+	{
 		HWR_FreeTextureCache();
+		HWR_FreeColormaps();
+	}
 	M_AATreeFree(delwad->hwrcache);
 #endif
 	if (*lumpcache)
@@ -1503,21 +1506,6 @@ void *W_CacheLumpName(const char *name, INT32 tag)
 // Cache a patch into heap memory, convert the patch format as necessary
 //
 
-void W_FlushCachedPatches(void)
-{
-	if (needpatchflush)
-	{
-		Z_FreeTag(PU_CACHE);
-		Z_FreeTag(PU_PATCH);
-		Z_FreeTag(PU_HUDGFX);
-		Z_FreeTag(PU_HWRPATCHINFO);
-		Z_FreeTag(PU_HWRPATCHCOLMIPMAP);
-		Z_FreeTag(PU_HWRCACHE);
-		Z_FreeTags(PU_HWRCACHE_UNLOCKED, PU_HWRPATCHINFO_UNLOCKED);
-	}
-	needpatchflush = false;
-}
-
 // Software-only compile cache the data without conversion
 #ifdef HWRENDER
 static inline void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
@@ -1525,7 +1513,7 @@ static inline void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
 	GLPatch_t *grPatch;
 
 	if (needpatchflush)
-		W_FlushCachedPatches();
+		Z_FlushCachedPatches();
 
 	if (rendermode == render_soft || rendermode == render_none)
 		return W_CacheLumpNumPwad(wad, lump, tag);
diff --git a/src/w_wad.h b/src/w_wad.h
index 84e921e755c5b1f3d6943cd683141d7764acd8ee..87566c3ee8c103d33d554199d520cee4a501c91b 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -183,7 +183,6 @@ void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag); // return a patch_t
 #endif
 
 void W_UnlockCachedPatch(void *patch);
-void W_FlushCachedPatches(void);
 
 void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5);
 
diff --git a/src/y_inter.c b/src/y_inter.c
index ab0af490d3242b6328d66a774b9b020533522470..ab27a00fe210777f40b785593b1652fe75dc7190 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -144,6 +144,7 @@ static patch_t *interpic = NULL;    // custom picture defined in map header
 static boolean usetile;
 boolean usebuffer = false;
 static boolean useinterpic;
+static boolean safetorender = true;
 static INT32 timer;
 
 static INT32 intertic;
@@ -158,6 +159,7 @@ static void Y_CalculateTimeRaceWinners(void);
 static void Y_CalculateMatchWinners(void);
 static void Y_FollowIntermission(void);
 static void Y_UnloadData(void);
+static void Y_CleanupData(void);
 
 // Stuff copy+pasted from st_stuff.c
 static INT32 SCX(INT32 x)
@@ -187,31 +189,41 @@ void Y_IntermissionDrawer(void)
 	if (intertype == int_none || rendermode == render_none)
 		return;
 
-	if (!usebuffer)
+	if (needpatchrecache)
+	{
+		Y_CleanupData();
+		R_ReloadHUDGraphics();
+		safetorender = false;
+	}
+
+	if (!usebuffer || !safetorender)
 		V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
 
-	if (useinterpic)
-		V_DrawScaledPatch(0, 0, 0, interpic);
-	else if (!usetile)
+	if (safetorender)
 	{
-		if (rendermode == render_soft && usebuffer)
-			VID_BlitLinearScreen(screens[1], screens[0], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
-#ifdef HWRENDER
-		else if(rendermode != render_soft && usebuffer)
+		if (useinterpic)
+			V_DrawScaledPatch(0, 0, 0, interpic);
+		else if (!usetile)
 		{
-			HWR_DrawIntermissionBG();
-		}
+			if (rendermode == render_soft && usebuffer)
+				VID_BlitLinearScreen(screens[1], screens[0], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
+#ifdef HWRENDER
+			else if(rendermode != render_soft && usebuffer)
+			{
+				HWR_DrawIntermissionBG();
+			}
 #endif
-		else
-		{
-			if (widebgpatch && rendermode == render_soft && vid.width / vid.dupx == 400)
-				V_DrawScaledPatch(0, 0, V_SNAPTOLEFT, widebgpatch);
 			else
-				V_DrawScaledPatch(0, 0, 0, bgpatch);
+			{
+				if (widebgpatch && rendermode == render_soft && vid.width / vid.dupx == 400)
+					V_DrawScaledPatch(0, 0, V_SNAPTOLEFT, widebgpatch);
+				else
+					V_DrawScaledPatch(0, 0, 0, bgpatch);
+			}
 		}
+		else
+			V_DrawPatchFill(bgtile);
 	}
-	else
-		V_DrawPatchFill(bgtile);
 
 	if (intertype == int_coop)
 	{
@@ -249,19 +261,22 @@ void Y_IntermissionDrawer(void)
 		V_DrawLevelTitle(data.coop.passedx1, 49, 0, data.coop.passed1);
 		V_DrawLevelTitle(data.coop.passedx2, 49+V_LevelNameHeight(data.coop.passed2)+2, 0, data.coop.passed2);
 
-		if (mapheaderinfo[gamemap-1]->actnum)
+		if (mapheaderinfo[gamemap-1]->actnum && safetorender)
 			V_DrawScaledPatch(244, 57, 0, data.coop.ttlnum);
 
 		bonusy = 150;
 		// Total
-		V_DrawScaledPatch(152, bonusy, 0, data.coop.ptotal);
-		V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.total);
+		if (safetorender)
+		{
+			V_DrawScaledPatch(152, bonusy, 0, data.coop.ptotal);
+			V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.total);
+		}
 		bonusy -= (3*SHORT(tallnum[0]->height)/2) + 1;
 
 		// Draw bonuses
 		for (i = 3; i >= 0; --i)
 		{
-			if (data.coop.bonuses[i].display)
+			if (data.coop.bonuses[i].display && safetorender)
 			{
 				V_DrawScaledPatch(152, bonusy, 0, data.coop.bonuspatches[i]);
 				V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.bonuses[i].points);
@@ -340,13 +355,16 @@ void Y_IntermissionDrawer(void)
 			}
 		}
 
-		V_DrawScaledPatch(152, 108, 0, data.spec.bonuspatch);
-		V_DrawTallNum(BASEVIDWIDTH - 68, 109, 0, data.spec.bonus.points);
-		V_DrawScaledPatch(152, 124, 0, data.spec.pscore);
-		V_DrawTallNum(BASEVIDWIDTH - 68, 125, 0, data.spec.score);
+		if (safetorender)
+		{
+			V_DrawScaledPatch(152, 108, 0, data.spec.bonuspatch);
+			V_DrawTallNum(BASEVIDWIDTH - 68, 109, 0, data.spec.bonus.points);
+			V_DrawScaledPatch(152, 124, 0, data.spec.pscore);
+			V_DrawTallNum(BASEVIDWIDTH - 68, 125, 0, data.spec.score);
+		}
 
 		// Draw continues!
-		if (!multiplayer /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay
+		if (!multiplayer && safetorender /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay
 		{
 			UINT8 continues = data.spec.continues & 0x7F;
 
@@ -368,7 +386,8 @@ void Y_IntermissionDrawer(void)
 		char strtime[10];
 
 		// draw the header
-		V_DrawScaledPatch(112, 2, 0, data.match.result);
+		if (safetorender)
+			V_DrawScaledPatch(112, 2, 0, data.match.result);
 
 		// draw the level name
 		V_DrawCenteredString(BASEVIDWIDTH/2, 20, 0, data.match.levelstring);
@@ -959,6 +978,8 @@ void Y_StartIntermission(void)
 		I_Error("endtic is dirty");
 #endif
 
+	safetorender = true;
+
 	if (!multiplayer)
 	{
 		timer = 0;
@@ -1057,9 +1078,9 @@ void Y_StartIntermission(void)
 			// get act number
 			if (mapheaderinfo[prevmap]->actnum)
 				data.coop.ttlnum = W_CachePatchName(va("TTL%.2d", mapheaderinfo[prevmap]->actnum),
-					PU_STATIC);
+					PU_PATCH);
 			else
-				data.coop.ttlnum = W_CachePatchName("TTL01", PU_STATIC);
+				data.coop.ttlnum = W_CachePatchName("TTL01", PU_PATCH);
 
 			// get background patches
 			widebgpatch = W_CachePatchName("INTERSCW", PU_PATCH);
@@ -1178,7 +1199,7 @@ void Y_StartIntermission(void)
 				data.spec.cemerald = W_CachePatchName("GOTEMALL", PU_PATCH);
 				data.spec.headx = 70;
 				data.spec.nowsuper = players[consoleplayer].skin
-					? NULL : W_CachePatchName("NOWSUPER", PU_STATIC);
+					? NULL : W_CachePatchName("NOWSUPER", PU_PATCH);
 			}
 			else
 			{
@@ -1835,7 +1856,8 @@ static void Y_FollowIntermission(void)
 	G_AfterIntermission();
 }
 
-#define UNLOAD(x) Z_ChangeTag(x, PU_CACHE); x = NULL
+#define UNLOAD(x) if (x) {Z_ChangeTag(x, PU_CACHE);} x = NULL;
+#define CLEANUP(x) x = NULL;
 
 //
 // Y_UnloadData
@@ -1886,5 +1908,47 @@ static void Y_UnloadData(void)
 			//are not handled
 			break;
 	}
+}
 
+static void Y_CleanupData(void)
+{
+	// unload the background patches
+	CLEANUP(bgpatch);
+	CLEANUP(widebgpatch);
+	CLEANUP(bgtile);
+	CLEANUP(interpic);
+
+	switch (intertype)
+	{
+		case int_coop:
+			// unload the coop and single player patches
+			CLEANUP(data.coop.ttlnum);
+			CLEANUP(data.coop.bonuspatches[3]);
+			CLEANUP(data.coop.bonuspatches[2]);
+			CLEANUP(data.coop.bonuspatches[1]);
+			CLEANUP(data.coop.bonuspatches[0]);
+			CLEANUP(data.coop.ptotal);
+			break;
+		case int_spec:
+			// unload the special stage patches
+			//CLEANUP(data.spec.cemerald);
+			//CLEANUP(data.spec.nowsuper);
+			CLEANUP(data.spec.bonuspatch);
+			CLEANUP(data.spec.pscore);
+			CLEANUP(data.spec.pcontinues);
+			break;
+		case int_match:
+		case int_race:
+			CLEANUP(data.match.result);
+			break;
+		case int_ctf:
+			CLEANUP(data.match.blueflag);
+			CLEANUP(data.match.redflag);
+			break;
+		default:
+			//without this default,
+			//int_none, int_tag, int_chaos, and int_classicrace
+			//are not handled
+			break;
+	}
 }
diff --git a/src/z_zone.c b/src/z_zone.c
index a3e13422f9bed1d569a84eb25f9419993ed66309..add18b5682318aa3e1aac529e4e766da517574eb 100644
--- a/src/z_zone.c
+++ b/src/z_zone.c
@@ -411,6 +411,26 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag)
 	}
 }
 
+// for renderer switching, free a bunch of stuff
+boolean needpatchflush = false;
+boolean needpatchrecache = false;
+
+void Z_FlushCachedPatches(void)
+{
+	if (needpatchflush)
+	{
+		Z_FreeTag(PU_CACHE);
+		Z_FreeTag(PU_PATCH);
+		Z_FreeTag(PU_HUDGFX);
+		Z_FreeTag(PU_HWRPATCHINFO);
+		Z_FreeTag(PU_HWRPATCHCOLMIPMAP);
+		Z_FreeTag(PU_HWRCACHE);
+		Z_FreeTag(PU_HWRCACHE_UNLOCKED);
+		Z_FreeTag(PU_HWRPATCHINFO_UNLOCKED);
+	}
+	needpatchflush = false;
+}
+
 //
 // Z_CheckMemCleanup
 //
diff --git a/src/z_zone.h b/src/z_zone.h
index edf4c79baf22c5aac03b51dc9fa2700748e4737e..700e3a1d55640f2191acf6eaf8da067836b16c89 100644
--- a/src/z_zone.h
+++ b/src/z_zone.h
@@ -70,6 +70,11 @@ void Z_ChangeTag2(void *ptr, INT32 tag, const char *file, INT32 line);
 void Z_ChangeTag2(void *ptr, INT32 tag);
 #endif
 
+// for renderer switching, free a bunch of stuff
+extern boolean needpatchflush;
+extern boolean needpatchrecache;
+void Z_FlushCachedPatches(void);
+
 #ifdef PARANOIA
 void Z_SetUser2(void *ptr, void **newuser, const char *file, INT32 line);
 #else