From c5447f0cddab41462c4d8be23803970ea09666cc Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@users.noreply.github.com>
Date: Wed, 12 Dec 2018 18:39:38 +0100
Subject: [PATCH] - continued work on texture management.

---
 src/f_wipe.cpp                            |  5 +-
 src/gl/renderer/gl_renderer.cpp           |  4 +-
 src/gl/renderer/gl_renderstate.cpp        |  4 +-
 src/gl/system/gl_framebuffer.cpp          | 11 +---
 src/gl/system/gl_framebuffer.h            |  1 -
 src/gl/textures/gl_hwtexture.cpp          | 23 -------
 src/gl/textures/gl_hwtexture.h            |  1 -
 src/hwrenderer/textures/hw_ihwtexture.h   |  1 -
 src/hwrenderer/textures/hw_material.cpp   | 78 +++++++----------------
 src/hwrenderer/textures/hw_material.h     | 22 +------
 src/hwrenderer/textures/hw_precache.cpp   |  9 +--
 src/hwrenderer/textures/hw_texcontainer.h | 15 +++--
 src/hwrenderer/utility/hw_cvars.cpp       |  4 +-
 src/textures/hires/hqresize.cpp           |  8 +--
 src/textures/texture.cpp                  |  4 +-
 src/textures/texturemanager.cpp           | 25 ++++++++
 src/textures/textures.h                   |  3 +
 src/v_video.h                             |  1 -
 18 files changed, 79 insertions(+), 140 deletions(-)

diff --git a/src/f_wipe.cpp b/src/f_wipe.cpp
index cb5544b685..80e5761007 100644
--- a/src/f_wipe.cpp
+++ b/src/f_wipe.cpp
@@ -372,9 +372,8 @@ bool Wiper_Burn::Run(int ticks)
 		Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density);
 		done = (Density < 0);
 	}
-	
-	auto mat = FMaterial::ValidateTexture(BurnTexture, false);
-	mat->Clean(true);
+
+	BurnTexture->SystemTextures.Clean(true, true);
 	const uint8_t *src = BurnArray;
 	uint32_t *dest = (uint32_t *)BurnTexture->GetBuffer();
 	for (int y = HEIGHT; y != 0; --y)
diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp
index 79ae7655f7..44422ad2d0 100644
--- a/src/gl/renderer/gl_renderer.cpp
+++ b/src/gl/renderer/gl_renderer.cpp
@@ -117,7 +117,7 @@ FGLRenderer::~FGLRenderer()
 {
 	FlushModels();
 	AActor::DeleteAllAttachedLights();
-	FMaterial::FlushAll();
+	TexMan.FlushAll();
 	if (mShaderManager != nullptr) delete mShaderManager;
 	if (mSamplerManager != nullptr) delete mSamplerManager;
 	if (mFBID != 0) glDeleteFramebuffers(1, &mFBID);
@@ -288,7 +288,7 @@ sector_t *FGLRenderer::RenderView(player_t* player)
 
 void FGLRenderer::BindToFrameBuffer(FMaterial *mat)
 {
-	auto BaseLayer = static_cast<FHardwareTexture*>(mat->GetLayer(0));
+	auto BaseLayer = static_cast<FHardwareTexture*>(mat->GetLayer(0, 0));
 
 	if (BaseLayer == nullptr)
 	{
diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp
index 30a2918998..0cc80d073c 100644
--- a/src/gl/renderer/gl_renderstate.cpp
+++ b/src/gl/renderer/gl_renderstate.cpp
@@ -332,14 +332,14 @@ void FGLRenderState::ApplyMaterial(FMaterial *mat, int clampmode, int translatio
 	// Textures that are already scaled in the texture lump will not get replaced by hires textures.
 	int flags = mat->isExpanded() ? CTF_Expand : (gl_texture_usehires && !tex->isScaled() && clampmode <= CLAMP_XY) ? CTF_CheckHires : 0;
 	int numLayers = mat->GetLayers();
-	auto base = static_cast<FHardwareTexture*>(mat->GetLayer(0));
+	auto base = static_cast<FHardwareTexture*>(mat->GetLayer(0, translation));
 
 	if (base->BindOrCreate(tex, 0, clampmode, translation, flags))
 	{
 		for (int i = 1; i<numLayers; i++)
 		{
 			FTexture *layer;
-			auto systex = static_cast<FHardwareTexture*>(mat->GetLayer(i, &layer));
+			auto systex = static_cast<FHardwareTexture*>(mat->GetLayer(i, 0, &layer));
 			systex->BindOrCreate(layer, i, clampmode, 0, mat->isExpanded() ? CTF_Expand : 0);
 			maxbound = i;
 		}
diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp
index fda8ae9df1..8573a21ddb 100644
--- a/src/gl/system/gl_framebuffer.cpp
+++ b/src/gl/system/gl_framebuffer.cpp
@@ -339,14 +339,14 @@ void OpenGLFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation)
 	// Textures that are already scaled in the texture lump will not get replaced by hires textures.
 	int flags = mat->isExpanded() ? CTF_Expand : (gl_texture_usehires && !tex->isScaled()) ? CTF_CheckHires : 0;
 	int numLayers = mat->GetLayers();
-	auto base = static_cast<FHardwareTexture*>(mat->GetLayer(0));
+	auto base = static_cast<FHardwareTexture*>(mat->GetLayer(0, translation));
 
 	if (base->BindOrCreate(tex, 0, CLAMP_NONE, translation, flags))
 	{
 		for (int i = 1; i < numLayers; i++)
 		{
 			FTexture *layer;
-			auto systex = static_cast<FHardwareTexture*>(mat->GetLayer(i, &layer));
+			auto systex = static_cast<FHardwareTexture*>(mat->GetLayer(i, 0, &layer));
 			systex->BindOrCreate(layer, i, CLAMP_NONE, 0, mat->isExpanded() ? CTF_Expand : 0);
 		}
 	}
@@ -354,13 +354,6 @@ void OpenGLFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation)
 	FHardwareTexture::UnbindAll();
 }
 
-bool OpenGLFrameBuffer::CheckPrecacheMaterial(FMaterial *mat)
-{
-	if (!mat->tex->GetImage()) return true;
-	auto base = static_cast<FHardwareTexture*>(mat->GetLayer(0));
-	return base->Exists(0);
-}
-
 FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli)
 {
 	return new FGLModelRenderer(nullptr, gl_RenderState, mli);
diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h
index 5ebc586b0d..c77b3af670 100644
--- a/src/gl/system/gl_framebuffer.h
+++ b/src/gl/system/gl_framebuffer.h
@@ -35,7 +35,6 @@ public:
 	void SetTextureFilterMode() override;
 	IHardwareTexture *CreateHardwareTexture() override;
 	void PrecacheMaterial(FMaterial *mat, int translation) override;
-	bool CheckPrecacheMaterial(FMaterial *mat) override;
 	FModelRenderer *CreateModelRenderer(int mli) override;
 	void TextureFilterChanged() override;
 	void BeginFrame() override;
diff --git a/src/gl/textures/gl_hwtexture.cpp b/src/gl/textures/gl_hwtexture.cpp
index 7f4093af87..b9034b101e 100644
--- a/src/gl/textures/gl_hwtexture.cpp
+++ b/src/gl/textures/gl_hwtexture.cpp
@@ -265,29 +265,6 @@ void FHardwareTexture::Clean(bool all)
 	glDepthID = 0;
 }
 
-//===========================================================================
-// 
-// Deletes all allocated resources and considers translations
-// This will only be called for sprites
-//
-//===========================================================================
-
-void FHardwareTexture::CleanUnused(SpriteHits &usedtranslations)
-{
-	if (usedtranslations.CheckKey(0) == nullptr)
-	{
-		glDefTex.Delete();
-	}
-	for (int i = glTex_Translated.Size()-1; i>= 0; i--)
-	{
-		if (usedtranslations.CheckKey(glTex_Translated[i].translation) == nullptr)
-		{
-			glTex_Translated[i].Delete();
-			glTex_Translated.Delete(i);
-		}
-	}
-}
-
 //===========================================================================
 // 
 //	Destroys the texture
diff --git a/src/gl/textures/gl_hwtexture.h b/src/gl/textures/gl_hwtexture.h
index f864d073b4..46e9cfde4b 100644
--- a/src/gl/textures/gl_hwtexture.h
+++ b/src/gl/textures/gl_hwtexture.h
@@ -91,7 +91,6 @@ public:
 	unsigned int GetTextureHandle(int translation);
 
 	void Clean(bool all);
-	void CleanUnused(SpriteHits &usedtranslations);
 };
 
 }
diff --git a/src/hwrenderer/textures/hw_ihwtexture.h b/src/hwrenderer/textures/hw_ihwtexture.h
index 10447e5b1e..07486e147f 100644
--- a/src/hwrenderer/textures/hw_ihwtexture.h
+++ b/src/hwrenderer/textures/hw_ihwtexture.h
@@ -26,7 +26,6 @@ public:
 	virtual unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) = 0;
 
 	virtual void Clean(bool all) = 0;
-	virtual void CleanUnused(SpriteHits &usedtranslations) = 0;
 
 	void Resize(int swidth, int sheight, int width, int height, unsigned char *src_data, unsigned char *dst_data);
 };
diff --git a/src/hwrenderer/textures/hw_material.cpp b/src/hwrenderer/textures/hw_material.cpp
index 9c0769b226..13cd9298e9 100644
--- a/src/hwrenderer/textures/hw_material.cpp
+++ b/src/hwrenderer/textures/hw_material.cpp
@@ -128,26 +128,6 @@ void IHardwareTexture::Resize(int swidth, int sheight, int width, int height, un
 	}
 }
 
-//===========================================================================
-//
-//
-//
-//===========================================================================
-IHardwareTexture * FMaterial::ValidateSysTexture(FTexture * tex, int translation, bool expand)
-{
-	if (tex	&& tex->UseType!=ETextureType::Null)
-	{
-		IHardwareTexture *gltex = tex->SystemTextures.GetHardwareTexture(0, expand);
-		if (gltex == nullptr) 
-		{
-			tex->SystemTextures.AddHardwareTexture(0, expand, screen->CreateHardwareTexture());
-			gltex = tex->SystemTextures.GetHardwareTexture(0, expand);
-		}
-		return gltex;
-	}
-	return nullptr;
-}
-
 //===========================================================================
 //
 // Constructor
@@ -183,7 +163,6 @@ FMaterial::FMaterial(FTexture * tx, bool expanded)
 		{
 			for (auto &texture : { tx->Normal, tx->Specular })
 			{
-				ValidateSysTexture(texture, 0, expanded);
 				mTextureLayers.Push(texture);
 			}
 			mShaderIndex = SHADER_Specular;
@@ -192,7 +171,6 @@ FMaterial::FMaterial(FTexture * tx, bool expanded)
 		{
 			for (auto &texture : { tx->Normal, tx->Metallic, tx->Roughness, tx->AmbientOcclusion })
 			{
-				ValidateSysTexture(texture, 0, expanded);
 				mTextureLayers.Push(texture);
 			}
 			mShaderIndex = SHADER_PBR;
@@ -201,7 +179,6 @@ FMaterial::FMaterial(FTexture * tx, bool expanded)
 		tx->CreateDefaultBrightmap();
 		if (tx->Brightmap)
 		{
-			ValidateSysTexture(tx->Brightmap, 0, expanded);
 			mTextureLayers.Push(tx->Brightmap);
 			if (mShaderIndex == SHADER_Specular)
 				mShaderIndex = SHADER_SpecularBrightmap;
@@ -219,16 +196,12 @@ FMaterial::FMaterial(FTexture * tx, bool expanded)
 				for (auto &texture : tx->CustomShaderTextures)
 				{
 					if (texture == nullptr) continue;
-					ValidateSysTexture(texture, 0, expanded);
 					mTextureLayers.Push(texture);
 				}
 				mShaderIndex = tx->shaderindex;
 			}
 		}
 	}
-	mBaseLayer = ValidateSysTexture(tx, 0, expanded);
-
-
 	mWidth = tx->GetWidth();
 	mHeight = tx->GetHeight();
 	mLeftOffset = tx->GetLeftOffset(0);	// These only get used by decals and decals should not use renderer-specific offsets.
@@ -423,6 +396,27 @@ outl:
 	return true;
 }
 
+//===========================================================================
+//
+//
+//
+//===========================================================================
+
+IHardwareTexture *FMaterial::GetLayer(int i, int translation, FTexture **pLayer)
+{
+	FTexture *texture = i == 0 ? tex : mTextureLayers[i - 1];
+	if (pLayer) *pLayer = tex;
+
+	auto hwtex = tex->SystemTextures.GetHardwareTexture(translation, mExpanded);
+	if (hwtex == nullptr)
+	{
+		hwtex = screen->CreateHardwareTexture();
+		// Fixme: This needs to create the texture here and not implicitly in BindOrCreate!
+		tex->SystemTextures.AddHardwareTexture(translation, mExpanded, hwtex);
+	}
+	return hwtex;
+}
+
 //===========================================================================
 //
 //
@@ -440,7 +434,7 @@ void FMaterial::Precache()
 //===========================================================================
 void FMaterial::PrecacheList(SpriteHits &translations)
 {
-	if (mBaseLayer != nullptr) mBaseLayer->CleanUnused(translations);
+	tex->SystemTextures.CleanUnused(translations, mExpanded);
 	SpriteHits::Iterator it(translations);
 	SpriteHits::Pair *pair;
 	while(it.NextPair(pair)) screen->PrecacheMaterial(this, pair->Key);
@@ -510,31 +504,3 @@ FMaterial * FMaterial::ValidateTexture(FTextureID no, bool expand, bool translat
 {
 	return ValidateTexture(TexMan.GetTexture(no, translate), expand, create);
 }
-
-
-//==========================================================================
-//
-// Flushes all hardware dependent data.
-// Thia must not, under any circumstances, delete the wipe textures, because
-// all CCMDs triggering a flush can be executed while a wipe is in progress
-//
-//==========================================================================
-
-void FMaterial::FlushAll()
-{
-	for(int i=TexMan.NumTextures()-1;i>=0;i--)
-	{
-		for (int j = 0; j < 2; j++)
-		{
-			TexMan.ByIndex(i)->SystemTextures.Clean(true);
-		}
-	}
-	// This must also delete the software renderer's canvas.
-}
-
-void FMaterial::Clean(bool f)
-{
-	// This somehow needs to deal with the other layers as well, but they probably need some form of reference counting to work properly...
-	mBaseLayer->Clean(f);
-}
-
diff --git a/src/hwrenderer/textures/hw_material.h b/src/hwrenderer/textures/hw_material.h
index b4d24d8a8f..33bf0f9d3f 100644
--- a/src/hwrenderer/textures/hw_material.h
+++ b/src/hwrenderer/textures/hw_material.h
@@ -39,7 +39,6 @@ class FMaterial
 	static TArray<FMaterial *> mMaterials;
 	static int mMaxBound;
 
-	IHardwareTexture *mBaseLayer;	
 	TArray<FTexture*> mTextureLayers;
 	int mShaderIndex;
 
@@ -68,7 +67,6 @@ public:
 	void Precache();
 	void PrecacheList(SpriteHits &translations);
 	int GetShaderIndex() const { return mShaderIndex; }
-	IHardwareTexture * ValidateSysTexture(FTexture * tex, int translation, bool expand);
 	void AddTextureLayer(FTexture *tex)
 	{
 		ValidateTexture(tex, false);
@@ -93,23 +91,7 @@ public:
 		return tex->isHardwareCanvas();
 	}
 
-	IHardwareTexture *GetLayer(int i, FTexture **pLayer = nullptr)
-	{
-		if (i == 0)
-		{
-			if (pLayer) *pLayer = tex;
-			return mBaseLayer;
-		}
-		else
-		{
-			i--;
-			FTexture *layer = mTextureLayers[i];
-			if (pLayer) *pLayer = layer;
-			return ValidateSysTexture(layer, 0, isExpanded());
-		}
-	}
-
-	void Clean(bool f);
+	IHardwareTexture *GetLayer(int i, int translation, FTexture **pLayer = nullptr);
 
 	// Patch drawing utilities
 
@@ -168,8 +150,6 @@ public:
 	float GetSpriteVB() const { return mSpriteV[1]; }
 
 
-	static void DeleteAll();
-	static void FlushAll();
 	static FMaterial *ValidateTexture(FTexture * tex, bool expand, bool create = true);
 	static FMaterial *ValidateTexture(FTextureID no, bool expand, bool trans, bool create = true);
 };
diff --git a/src/hwrenderer/textures/hw_precache.cpp b/src/hwrenderer/textures/hw_precache.cpp
index b927463a26..dc6829dd60 100644
--- a/src/hwrenderer/textures/hw_precache.cpp
+++ b/src/hwrenderer/textures/hw_precache.cpp
@@ -177,13 +177,11 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
 		{
 			if (!texhitlist[i])
 			{
-				auto mat = FMaterial::ValidateTexture(tex, false, false);
-				if (mat) mat->Clean(true);
+				tex->SystemTextures.Clean(true, false);
 			}
 			if (spritehitlist[i] == nullptr || (*spritehitlist[i]).CountUsed() == 0)
 			{
-				auto mat = FMaterial::ValidateTexture(tex, true, false);
-				if (mat) mat->Clean(true);
+				tex->SystemTextures.Clean(false, true);
 			}
 		}
 	}
@@ -200,8 +198,7 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
 			{
 				if (texhitlist[i] & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky))
 				{
-					FMaterial * gltex = FMaterial::ValidateTexture(tex, false);
-					if (gltex && !screen->CheckPrecacheMaterial(gltex))
+					if (tex->GetImage() && tex->SystemTextures.GetHardwareTexture(0, false) == nullptr)
 					{
 						FImageSource::RegisterForPrecache(tex->GetImage());
 					}
diff --git a/src/hwrenderer/textures/hw_texcontainer.h b/src/hwrenderer/textures/hw_texcontainer.h
index 96cd8fa3c9..65f3561151 100644
--- a/src/hwrenderer/textures/hw_texcontainer.h
+++ b/src/hwrenderer/textures/hw_texcontainer.h
@@ -65,15 +65,15 @@ private:
 
 public:
 
-	void Clean(bool all)
+	void Clean(bool cleannormal, bool cleanexpanded)
 	{
-		if (all)
+		if (cleannormal) hwDefTex[0].Delete();
+		if (cleanexpanded) hwDefTex[1].Delete();
+		for (int i = hwTex_Translated.Size() - 1; i >= 0; i--)
 		{
-			hwDefTex[0].Delete();
-			hwDefTex[1].Delete();
+			if (cleannormal && hwTex_Translated[i].translation > 0) hwTex_Translated.Delete(i);
+			else if (cleanexpanded && hwTex_Translated[i].translation < 0) hwTex_Translated.Delete(i);
 		}
-		hwTex_Translated.Clear();
-			
 	}
 	
 	IHardwareTexture * GetHardwareTexture(int translation, bool expanded)
@@ -102,9 +102,10 @@ public:
 		{
 			hwDefTex[expanded].Delete();
 		}
+		int fac = expanded ? -1 : 1;
 		for (int i = hwTex_Translated.Size()-1; i>= 0; i--)
 		{
-			if (usedtranslations.CheckKey(hwTex_Translated[i].translation) == nullptr)
+			if (usedtranslations.CheckKey(hwTex_Translated[i].translation * fac) == nullptr)
 			{
 				hwTex_Translated.Delete(i);
 			}
diff --git a/src/hwrenderer/utility/hw_cvars.cpp b/src/hwrenderer/utility/hw_cvars.cpp
index f0a0f8c834..1d11e24b19 100644
--- a/src/hwrenderer/utility/hw_cvars.cpp
+++ b/src/hwrenderer/utility/hw_cvars.cpp
@@ -92,7 +92,7 @@ CUSTOM_CVAR(Float,gl_texture_filter_anisotropic,8.0f,CVAR_ARCHIVE|CVAR_GLOBALCON
 
 CCMD(gl_flush)
 {
-	FMaterial::FlushAll();
+	TexMan.FlushAll();
 }
 
 CUSTOM_CVAR(Int, gl_texture_filter, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
@@ -103,7 +103,7 @@ CUSTOM_CVAR(Int, gl_texture_filter, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINI
 
 CUSTOM_CVAR(Bool, gl_texture_usehires, true, CVAR_ARCHIVE|CVAR_NOINITCALL)
 {
-	FMaterial::FlushAll();
+	TexMan.FlushAll();
 }
 
 CVAR(Bool, gl_precache, false, CVAR_ARCHIVE)
diff --git a/src/textures/hires/hqresize.cpp b/src/textures/hires/hqresize.cpp
index cc8a65678b..e6acb49119 100644
--- a/src/textures/hires/hqresize.cpp
+++ b/src/textures/hires/hqresize.cpp
@@ -52,7 +52,7 @@ CUSTOM_CVAR(Int, gl_texture_hqresizemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG |
 		self = 0;
 	if ((gl_texture_hqresizemult > 4) && (self < 4) && (self > 0))
 		gl_texture_hqresizemult = 4;
-	FMaterial::FlushAll();
+	TexMan.FlushAll();
 }
 
 CUSTOM_CVAR(Int, gl_texture_hqresizemult, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
@@ -61,18 +61,18 @@ CUSTOM_CVAR(Int, gl_texture_hqresizemult, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG |
 		self = 1;
 	if ((self > 4) && (gl_texture_hqresizemode < 4) && (gl_texture_hqresizemode > 0))
 		self = 4;
-	FMaterial::FlushAll();
+	TexMan.FlushAll();
 }
 
 CUSTOM_CVAR(Int, gl_texture_hqresize_maxinputsize, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
 {
 	if (self > 1024) self = 1024;
-	FMaterial::FlushAll();
+	TexMan.FlushAll();
 }
 
 CUSTOM_CVAR(Int, gl_texture_hqresize_targets, 7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
 {
-	FMaterial::FlushAll();
+	TexMan.FlushAll();
 }
 
 CVAR (Flag, gl_texture_hqresize_textures, gl_texture_hqresize_targets, 1);
diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp
index 7dfd004843..f8069393ed 100644
--- a/src/textures/texture.cpp
+++ b/src/textures/texture.cpp
@@ -790,7 +790,9 @@ FWrapperTexture::FWrapperTexture(int w, int h, int bits)
 	Format = bits;
 	UseType = ETextureType::SWCanvas;
 	bNoCompress = true;
-	SystemTextures.AddHardwareTexture(0, false, screen->CreateHardwareTexture());
+	auto hwtex = screen->CreateHardwareTexture();
+	// todo: Initialize here.
+	SystemTextures.AddHardwareTexture(0, false, hwtex);
 }
 
 //===========================================================================
diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp
index 558a6243c6..bb2fe50f2d 100644
--- a/src/textures/texturemanager.cpp
+++ b/src/textures/texturemanager.cpp
@@ -141,6 +141,31 @@ void FTextureManager::DeleteAll()
 	BuildTileData.Clear();
 }
 
+//==========================================================================
+//
+// Flushes all hardware dependent data.
+// Thia must not, under any circumstances, delete the wipe textures, because
+// all CCMDs triggering a flush can be executed while a wipe is in progress
+//
+// This now also deletes the software textures because having the software
+// renderer use the texture scalers is a planned feature and that is the
+// main reason to call this outside of the destruction code.
+//
+//==========================================================================
+
+void FTextureManager::FlushAll()
+{
+	for (int i = TexMan.NumTextures() - 1; i >= 0; i--)
+	{
+		for (int j = 0; j < 2; j++)
+		{
+			TexMan.ByIndex(i)->SystemTextures.Clean(true, true);
+			delete TexMan.ByIndex(i)->SoftwareTexture;
+		}
+	}
+	// This must also delete the software renderer's canvas.
+}
+
 //==========================================================================
 //
 // FTextureManager :: CheckForTexture
diff --git a/src/textures/textures.h b/src/textures/textures.h
index 199ce0be88..90d12c0c2e 100644
--- a/src/textures/textures.h
+++ b/src/textures/textures.h
@@ -345,7 +345,9 @@ protected:
 	FTextureID id;
 
 	FMaterial *Material[2] = { nullptr, nullptr };
+public:
 	FHardwareTextureContainer SystemTextures;
+protected:
 	//IHardwareTexture *SystemTexture[2] = { nullptr, nullptr };
 	FSoftwareTexture *SoftwareTexture = nullptr;
 
@@ -540,6 +542,7 @@ public:
 	}
 	FTexture *FindTexture(const char *texname, ETextureType usetype = ETextureType::MiscPatch, BITFIELD flags = TEXMAN_TryAny);
 
+	void FlushAll();
 
 
 //public:
diff --git a/src/v_video.h b/src/v_video.h
index bbbcb71f96..216fa2d313 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -425,7 +425,6 @@ public:
 	virtual void CleanForRestart() {}
 	virtual void SetTextureFilterMode() {}
 	virtual IHardwareTexture *CreateHardwareTexture() { return nullptr; }
-	virtual bool CheckPrecacheMaterial(FMaterial *mat) { return true; }
 	virtual void PrecacheMaterial(FMaterial *mat, int translation) {}
 	virtual FModelRenderer *CreateModelRenderer(int mli) { return nullptr; }
 	virtual void UnbindTexUnit(int no) {}