diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index a9e5babc1d5f7f00c4eb627f47e5095825c21d13..41bb653f7a047b59c7b9be1613cd81644b30aace 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -477,6 +477,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
 	{
 		UINT8 *pdata = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE);
 		patch_t *realpatch = NULL;
+		boolean free_patch = true;
 
 #ifndef NO_PNG_LUMPS
 		size_t lumplength = W_LumpLengthPwad(patch->wad, patch->lump);
@@ -487,11 +488,21 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex)
 		if (texture->type == TEXTURETYPE_FLAT)
 			realpatch = (patch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_PATCH, 0, NULL, texture->width, texture->height, 0, 0, 0);
 		else
-			realpatch = (patch_t *)Picture_Convert(PICFMT_DOOMPATCH, pdata, PICFMT_PATCH, 0, NULL, 0, 0, 0, 0, 0);
+		{
+			// If this patch has already been loaded, we just use it from the cache.
+			realpatch = W_GetCachedPatchNumPwad(patch->wad, patch->lump);
+
+			// Otherwise, we convert it here.
+			if (realpatch == NULL)
+				realpatch = Patch_Create((softwarepatch_t *)pdata, NULL);
+			else
+				free_patch = false;
+		}
 
 		HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, texture, patch, realpatch);
 
-		Patch_Free(realpatch);
+		if (free_patch)
+			Patch_Free(realpatch);
 	}
 	//Hurdler: not efficient at all but I don't remember exactly how HWR_DrawPatchInCache works :(
 	if (format2bpp(grtex->mipmap.format)==4)
@@ -1096,7 +1107,7 @@ patch_t *HWR_GetCachedGLPatchPwad(UINT16 wadnum, UINT16 lumpnum)
 	if (!lumpcache[lumpnum])
 	{
 		void *ptr = Z_Calloc(sizeof(patch_t), PU_PATCH, &lumpcache[lumpnum]);
-		Patch_Create(NULL, 0, ptr);
+		Patch_Create(NULL, ptr);
 		Patch_AllocateHardwarePatch(ptr);
 	}
 	return (patch_t *)(lumpcache[lumpnum]);
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index fca3af217ececcf3a5d95c7df8559da24240f01b..5969e4ac96f0724a0c8f7f81d15d48f91d6bdbf9 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -377,7 +377,7 @@ static void md2_loadTexture(md2_t *model)
 			Z_Free(grPatch->mipmap->data);
 	}
 	else
-		model->grpatch = patch = Patch_Create(NULL, 0, NULL);
+		model->grpatch = patch = Patch_Create(NULL, NULL);
 
 	if (!patch->hardware)
 		Patch_AllocateHardwarePatch(patch);
@@ -442,7 +442,7 @@ static void md2_loadBlendTexture(md2_t *model)
 			Z_Free(grPatch->mipmap->data);
 	}
 	else
-		model->blendgrpatch = patch = Patch_Create(NULL, 0, NULL);
+		model->blendgrpatch = patch = Patch_Create(NULL, NULL);
 
 	if (!patch->hardware)
 		Patch_AllocateHardwarePatch(patch);
diff --git a/src/r_patch.c b/src/r_patch.c
index 863b7af531b81247200d82b1d39bd60d8c245398..46871e1e032c188965e97121b58e2f9c53ba8f88 100644
--- a/src/r_patch.c
+++ b/src/r_patch.c
@@ -24,14 +24,12 @@
 // Assumes a PU_PATCH zone memory tag and no user, but can always be set later
 //
 
-patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest)
+patch_t *Patch_Create(softwarepatch_t *source, void *dest)
 {
 	patch_t *patch = (dest == NULL) ? Z_Calloc(sizeof(patch_t), PU_PATCH, NULL) : (patch_t *)(dest);
 	if (!source)
 		return patch;
 
-	(void)srcsize;
-
 	patch->width      = SHORT(source->width);
 	patch->height     = SHORT(source->height);
 	patch->leftoffset = SHORT(source->leftoffset);
diff --git a/src/r_patch.h b/src/r_patch.h
index cea3b0fe51b6d3a8707bb1da3ca9d24af9228be6..640826e71e6a1c50949c1d6ca3fd040b5b130f7e 100644
--- a/src/r_patch.h
+++ b/src/r_patch.h
@@ -18,7 +18,7 @@
 #include "doomdef.h"
 
 // Patch functions
-patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest);
+patch_t *Patch_Create(softwarepatch_t *source, void *dest);
 void Patch_CalcDataSizes(softwarepatch_t *source, size_t *total_pixels, size_t *total_posts);
 void Patch_MakeColumns(softwarepatch_t *source, size_t num_columns, UINT8 *pixels, column_t *columns, post_t *posts, boolean flip);
 void Patch_Free(patch_t *patch);
diff --git a/src/r_picformats.c b/src/r_picformats.c
index eb561f2630829f7f72454e5c8643ce0cb0228e53..6f644557a7b4117a9587c09f151a33486eb49f2b 100644
--- a/src/r_picformats.c
+++ b/src/r_picformats.c
@@ -84,22 +84,148 @@ void *Picture_Convert(
 	else if (informat == outformat)
 		I_Error("Picture_Convert: input and output formats were the same!");
 
+	(void)insize;
+
 	if (Picture_IsPatchFormat(outformat))
-		return Picture_PatchConvert(informat, picture, outformat, insize, outsize, inwidth, inheight, inleftoffset, intopoffset, flags);
+		return Picture_PatchConvert(informat, picture, outformat, outsize, inwidth, inheight, inleftoffset, intopoffset, flags);
 	else if (Picture_IsFlatFormat(outformat))
-		return Picture_FlatConvert(informat, picture, outformat, insize, outsize, inwidth, inheight, inleftoffset, intopoffset, flags);
+		return Picture_FlatConvert(informat, picture, outformat, outsize, inwidth, intopoffset, flags);
 	else
 		I_Error("Picture_Convert: unsupported input format!");
 
 	return NULL;
 }
 
+static void *ReadPixelFunc_Patch(void *picture, pictureformat_t informat, INT32 x, INT32 y, INT32 inwidth, INT32 inheight, pictureflags_t flags)
+{
+	(void)inwidth;
+	(void)inheight;
+	return Picture_GetPatchPixel((patch_t*)picture, informat, x, y, flags);
+}
+
+static void *ReadPixelFunc_Flat_8bpp(void *picture, pictureformat_t informat, INT32 x, INT32 y, INT32 inwidth, INT32 inheight, pictureflags_t flags)
+{
+	(void)informat;
+	(void)flags;
+	(void)inheight;
+	return (UINT8 *)picture + ((y * inwidth) + x);
+}
+
+static void *ReadPixelFunc_Flat_16bpp(void *picture, pictureformat_t informat, INT32 x, INT32 y, INT32 inwidth, INT32 inheight, pictureflags_t flags)
+{
+	(void)informat;
+	(void)flags;
+	(void)inheight;
+	return (UINT16 *)picture + ((y * inwidth) + x);
+}
+
+static void *ReadPixelFunc_Flat_32bpp(void *picture, pictureformat_t informat, INT32 x, INT32 y, INT32 inwidth, INT32 inheight, pictureflags_t flags)
+{
+	(void)informat;
+	(void)flags;
+	(void)inheight;
+	return (UINT32 *)picture + ((y * inwidth) + x);
+}
+
+static UINT8 GetAlphaFunc_32bpp(void *input, pictureflags_t flags)
+{
+	(void)flags;
+	RGBA_t px = *(RGBA_t *)input;
+	return px.s.alpha;
+}
+
+static UINT8 GetAlphaFunc_16bpp(void *input, pictureflags_t flags)
+{
+	(void)flags;
+	UINT16 px = *(UINT16 *)input;
+	return (px & 0xFF00) >> 8;
+}
+
+static UINT8 GetAlphaFunc_8bpp(void *input, pictureflags_t flags)
+{
+	UINT8 px = *(UINT8 *)input;
+	if (px == TRANSPARENTPIXEL && (flags & PICFLAGS_USE_TRANSPARENTPIXEL))
+		return 0;
+	else
+		return 255;
+}
+
+// input 32bpp output 32bpp
+static void *WritePatchPixel_i32o32(void *ptr, void *input)
+{
+	RGBA_t px = *(RGBA_t *)input;
+	WRITEUINT32(ptr, px.rgba);
+	return ptr;
+}
+
+// input 16bpp output 32bpp
+static void *WritePatchPixel_i16o32(void *ptr, void *input)
+{
+	RGBA_t px = pMasterPalette[*((UINT16 *)input) & 0xFF];
+	WRITEUINT32(ptr, px.rgba);
+	return ptr;
+}
+
+// input 8bpp output 32bpp
+static void *WritePatchPixel_i8o32(void *ptr, void *input)
+{
+	RGBA_t px = pMasterPalette[*((UINT8 *)input) & 0xFF];
+	WRITEUINT32(ptr, px.rgba);
+	return ptr;
+}
+
+// input 32bpp output 16bpp
+static void *WritePatchPixel_i32o16(void *ptr, void *input)
+{
+	RGBA_t in = *(RGBA_t *)input;
+	UINT8 px = NearestColor(in.s.red, in.s.green, in.s.blue);
+	WRITEUINT16(ptr, (0xFF00 | px));
+	return ptr;
+}
+
+// input 16bpp output 16bpp
+static void *WritePatchPixel_i16o16(void *ptr, void *input)
+{
+	WRITEUINT16(ptr, *(UINT16 *)input);
+	return ptr;
+}
+
+// input 8bpp output 16bpp
+static void *WritePatchPixel_i8o16(void *ptr, void *input)
+{
+	WRITEUINT16(ptr, (0xFF00 | (*(UINT8 *)input)));
+	return ptr;
+}
+
+// input 32bpp output 8bpp
+static void *WritePatchPixel_i32o8(void *ptr, void *input)
+{
+	RGBA_t in = *(RGBA_t *)input;
+	UINT8 px = NearestColor(in.s.red, in.s.green, in.s.blue);
+	WRITEUINT8(ptr, px);
+	return ptr;
+}
+
+// input 16bpp output 8bpp
+static void *WritePatchPixel_i16o8(void *ptr, void *input)
+{
+	UINT16 px = *(UINT16 *)input;
+	WRITEUINT8(ptr, (px & 0xFF));
+	return ptr;
+}
+
+// input 8bpp output 8bpp
+static void *WritePatchPixel_i8o8(void *ptr, void *input)
+{
+	WRITEUINT8(ptr, *(UINT8 *)input);
+	return ptr;
+}
+
 /** Converts a picture to a patch.
   *
   * \param informat Input picture format.
   * \param picture Input picture data.
   * \param outformat Output picture format.
-  * \param insize Input picture size.
   * \param outsize Output picture size, as a pointer.
   * \param inwidth Input picture width.
   * \param inheight Input picture height.
@@ -110,16 +236,22 @@ void *Picture_Convert(
   */
 void *Picture_PatchConvert(
 	pictureformat_t informat, void *picture, pictureformat_t outformat,
-	size_t insize, size_t *outsize,
-	INT16 inwidth, INT16 inheight, INT16 inleftoffset, INT16 intopoffset,
+	size_t *outsize,
+	INT32 inwidth, INT32 inheight, INT32 inleftoffset, INT32 intopoffset,
 	pictureflags_t flags)
 {
+	// Shortcut: If converting a Doom patch into a regular patch, use Patch_Create
+	if (informat == PICFMT_DOOMPATCH && outformat == PICFMT_PATCH && flags == 0)
+	{
+		if (outsize != NULL)
+			*outsize = sizeof(patch_t);
+		return Patch_Create(picture, NULL);
+	}
+
 	INT32 outbpp = Picture_FormatBPP(outformat);
 	INT32 inbpp = Picture_FormatBPP(informat);
 	patch_t *inpatch = NULL;
 
-	(void)insize; // ignore
-
 	if (informat == PICFMT_NONE)
 		I_Error("Picture_PatchConvert: input format was PICFMT_NONE!");
 	else if (outformat == PICFMT_NONE)
@@ -155,6 +287,74 @@ void *Picture_PatchConvert(
 		}
 	}
 
+	void *(*readPixelFunc)(void *, pictureformat_t, INT32, INT32, INT32, INT32, pictureflags_t) = NULL;
+	UINT8 (*getAlphaFunc)(void *, pictureflags_t) = NULL;
+	void *(*writePatchPixel)(void *, void *) = NULL;
+
+	if (Picture_IsPatchFormat(informat))
+		readPixelFunc = ReadPixelFunc_Patch;
+	else if (Picture_IsFlatFormat(informat))
+	{
+		switch (informat)
+		{
+			case PICFMT_FLAT32:
+				readPixelFunc = ReadPixelFunc_Flat_32bpp;
+				break;
+			case PICFMT_FLAT16:
+				readPixelFunc = ReadPixelFunc_Flat_16bpp;
+				break;
+			case PICFMT_FLAT:
+				readPixelFunc = ReadPixelFunc_Flat_8bpp;
+				break;
+			default:
+				I_Error("Picture_PatchConvert: unsupported flat input format!");
+				break;
+		}
+	}
+	else
+		I_Error("Picture_PatchConvert: unsupported input format!");
+
+	if (inbpp == PICDEPTH_32BPP)
+		getAlphaFunc = GetAlphaFunc_32bpp;
+	else if (inbpp == PICDEPTH_16BPP)
+		getAlphaFunc = GetAlphaFunc_16bpp;
+	else if (inbpp == PICDEPTH_8BPP)
+		getAlphaFunc = GetAlphaFunc_8bpp;
+
+	switch (outformat)
+	{
+		case PICFMT_PATCH32:
+		case PICFMT_DOOMPATCH32:
+		{
+			if (inbpp == PICDEPTH_32BPP)
+				writePatchPixel = WritePatchPixel_i32o32;
+			else if (inbpp == PICDEPTH_16BPP)
+				writePatchPixel = WritePatchPixel_i16o32;
+			else // PICFMT_PATCH
+				writePatchPixel = WritePatchPixel_i8o32;
+			break;
+		}
+		case PICFMT_PATCH16:
+		case PICFMT_DOOMPATCH16:
+			if (inbpp == PICDEPTH_32BPP)
+				writePatchPixel = WritePatchPixel_i32o16;
+			else if (inbpp == PICDEPTH_16BPP)
+				writePatchPixel = WritePatchPixel_i16o16;
+			else // PICFMT_PATCH
+				writePatchPixel = WritePatchPixel_i8o16;
+			break;
+		default: // PICFMT_PATCH
+		{
+			if (inbpp == PICDEPTH_32BPP)
+				writePatchPixel = WritePatchPixel_i32o8;
+			else if (inbpp == PICDEPTH_16BPP)
+				writePatchPixel = WritePatchPixel_i16o8;
+			else // PICFMT_PATCH
+				writePatchPixel = WritePatchPixel_i8o8;
+			break;
+		}
+	}
+
 	patch_t *out = Z_Calloc(sizeof(patch_t), PU_PATCH, NULL);
 
 	out->width = inwidth;
@@ -174,7 +374,7 @@ void *Picture_PatchConvert(
 	size_t *column_posts = Z_Calloc(sizeof(size_t) * inwidth, PU_STATIC, NULL);
 
 	// Write columns
-	for (INT16 x = 0; x < inwidth; x++)
+	for (INT32 x = 0; x < inwidth; x++)
 	{
 		post_t *post;
 		size_t post_data_offset = 0;
@@ -188,59 +388,16 @@ void *Picture_PatchConvert(
 		column_posts[x] = (size_t)-1;
 
 		// Write pixels
-		for (INT16 y = 0; y < inheight; y++)
+		for (INT32 y = 0; y < inheight; y++)
 		{
-			void *input = NULL;
 			boolean opaque = false;
 
 			// Read pixel
-			if (Picture_IsPatchFormat(informat))
-				input = Picture_GetPatchPixel(inpatch, informat, x, y, flags);
-			else if (Picture_IsFlatFormat(informat))
-			{
-				size_t offs = ((y * inwidth) + x);
-				switch (informat)
-				{
-					case PICFMT_FLAT32:
-						input = (UINT32 *)picture + offs;
-						break;
-					case PICFMT_FLAT16:
-						input = (UINT16 *)picture + offs;
-						break;
-					case PICFMT_FLAT:
-						input = (UINT8 *)picture + offs;
-						break;
-					default:
-						I_Error("Picture_PatchConvert: unsupported flat input format!");
-						break;
-				}
-			}
-			else
-				I_Error("Picture_PatchConvert: unsupported input format!");
+			void *input = readPixelFunc(picture, informat, x, y, inwidth, inheight, flags);
 
 			// Determine opacity
 			if (input != NULL)
-			{
-				UINT8 alpha = 0xFF;
-				if (inbpp == PICDEPTH_32BPP)
-				{
-					RGBA_t px = *(RGBA_t *)input;
-					alpha = px.s.alpha;
-				}
-				else if (inbpp == PICDEPTH_16BPP)
-				{
-					UINT16 px = *(UINT16 *)input;
-					alpha = (px & 0xFF00) >> 8;
-				}
-				else if (inbpp == PICDEPTH_8BPP)
-				{
-					UINT8 px = *(UINT8 *)input;
-					if (px == TRANSPARENTPIXEL)
-						alpha = 0;
-				}
-
-				opaque = alpha > 1;
-			}
+				opaque = getAlphaFunc(input, flags) > 0;
 
 			// End span if we have a transparent pixel
 			if (!opaque)
@@ -266,62 +423,11 @@ void *Picture_PatchConvert(
 			was_opaque = true;
 
 			// Write the pixel
-			switch (outformat)
-			{
-				case PICFMT_PATCH32:
-				case PICFMT_DOOMPATCH32:
-				{
-					if (inbpp == PICDEPTH_32BPP)
-					{
-						RGBA_t px = *(RGBA_t *)input;
-						WRITEUINT32(imgptr, px.rgba);
-					}
-					else if (inbpp == PICDEPTH_16BPP)
-					{
-						RGBA_t px = pMasterPalette[*((UINT16 *)input) & 0xFF];
-						WRITEUINT32(imgptr, px.rgba);
-					}
-					else // PICFMT_PATCH
-					{
-						RGBA_t px = pMasterPalette[*((UINT8 *)input) & 0xFF];
-						WRITEUINT32(imgptr, px.rgba);
-					}
-					break;
-				}
-				case PICFMT_PATCH16:
-				case PICFMT_DOOMPATCH16:
-					if (inbpp == PICDEPTH_32BPP)
-					{
-						RGBA_t in = *(RGBA_t *)input;
-						UINT8 px = NearestColor(in.s.red, in.s.green, in.s.blue);
-						WRITEUINT16(imgptr, (0xFF00 | px));
-					}
-					else if (inbpp == PICDEPTH_16BPP)
-						WRITEUINT16(imgptr, *(UINT16 *)input);
-					else // PICFMT_PATCH
-						WRITEUINT16(imgptr, (0xFF00 | (*(UINT8 *)input)));
-					break;
-				default: // PICFMT_PATCH
-				{
-					if (inbpp == PICDEPTH_32BPP)
-					{
-						RGBA_t in = *(RGBA_t *)input;
-						UINT8 px = NearestColor(in.s.red, in.s.green, in.s.blue);
-						WRITEUINT8(imgptr, px);
-					}
-					else if (inbpp == PICDEPTH_16BPP)
-					{
-						UINT16 px = *(UINT16 *)input;
-						WRITEUINT8(imgptr, (px & 0xFF));
-					}
-					else // PICFMT_PATCH
-						WRITEUINT8(imgptr, *(UINT8 *)input);
-					break;
-				}
-			}
+			UINT8 *last_ptr = imgptr;
+			imgptr = writePatchPixel(last_ptr, input);
 
 			post->length++;
-			post_data_offset += imgptr - column->pixels;
+			post_data_offset += imgptr - last_ptr;
 		}
 	}
 
@@ -333,8 +439,10 @@ void *Picture_PatchConvert(
 	for (INT16 x = 0; x < inwidth; x++)
 	{
 		column_t *column = &out->columns[x];
-		column->posts = &out->posts[column_posts[x]];
-		column->pixels = out->pixels + (column->pixels - old_pixels);
+		if (column->num_posts > 0)
+			column->posts = &out->posts[column_posts[x]];
+		if (old_pixels != out->pixels)
+			column->pixels = out->pixels + (column->pixels - old_pixels);
 	}
 
 	Z_Free(column_posts);
@@ -350,19 +458,16 @@ void *Picture_PatchConvert(
   * \param informat Input picture format.
   * \param picture Input picture data.
   * \param outformat Output picture format.
-  * \param insize Input picture size.
   * \param outsize Output picture size, as a pointer.
   * \param inwidth Input picture width.
   * \param inheight Input picture height.
-  * \param inleftoffset Input picture left offset, for patches.
-  * \param intopoffset Input picture top offset, for patches.
   * \param flags Input picture flags.
   * \return A pointer to the converted picture.
   */
 void *Picture_FlatConvert(
 	pictureformat_t informat, void *picture, pictureformat_t outformat,
-	size_t insize, size_t *outsize,
-	INT16 inwidth, INT16 inheight, INT16 inleftoffset, INT16 intopoffset,
+	size_t *outsize,
+	INT32 inwidth, INT32 inheight,
 	pictureflags_t flags)
 {
 	void *outflat;
@@ -372,10 +477,6 @@ void *Picture_FlatConvert(
 	INT32 x, y;
 	size_t size;
 
-	(void)insize; // ignore
-	(void)inleftoffset; // ignore
-	(void)intopoffset; // ignore
-
 	if (informat == PICFMT_NONE)
 		I_Error("Picture_FlatConvert: input format was PICFMT_NONE!");
 	else if (outformat == PICFMT_NONE)
@@ -1280,7 +1381,7 @@ void *Picture_PNGConvert(
 		}
 
 		// Now, convert it!
-		converted = Picture_PatchConvert(informat, flat, outformat, insize, outsize, (INT16)width, (INT16)height, *leftoffset, *topoffset, flags);
+		converted = Picture_PatchConvert(informat, flat, outformat, outsize, (INT32)width, (INT32)height, *leftoffset, *topoffset, flags);
 		Z_Free(flat);
 		return converted;
 	}
diff --git a/src/r_picformats.h b/src/r_picformats.h
index c8a5b5d26414cc4d97ca64cc711427e9c0154177..20fe57330d699f9bce8a73a2ae0bd67fa94a2602 100644
--- a/src/r_picformats.h
+++ b/src/r_picformats.h
@@ -42,8 +42,9 @@ typedef enum
 
 typedef enum
 {
-	PICFLAGS_XFLIP = 1,
-	PICFLAGS_YFLIP = 1<<1
+	PICFLAGS_XFLIP                = 1,
+	PICFLAGS_YFLIP                = 1<<1,
+	PICFLAGS_USE_TRANSPARENTPIXEL = 1<<2
 } pictureflags_t;
 
 enum
@@ -62,13 +63,13 @@ void *Picture_Convert(
 
 void *Picture_PatchConvert(
 	pictureformat_t informat, void *picture, pictureformat_t outformat,
-	size_t insize, size_t *outsize,
-	INT16 inwidth, INT16 inheight, INT16 inleftoffset, INT16 intopoffset,
+	size_t *outsize,
+	INT32 inwidth, INT32 inheight, INT32 inleftoffset, INT32 intopoffset,
 	pictureflags_t flags);
 void *Picture_FlatConvert(
 	pictureformat_t informat, void *picture, pictureformat_t outformat,
-	size_t insize, size_t *outsize,
-	INT16 inwidth, INT16 inheight, INT16 inleftoffset, INT16 intopoffset,
+	size_t *outsize,
+	INT32 inwidth, INT32 inheight,
 	pictureflags_t flags);
 void *Picture_GetPatchPixel(
 	patch_t *patch, pictureformat_t informat,
diff --git a/src/r_textures.c b/src/r_textures.c
index cc5e020abc2017ba3aa6e3f2fbbfe9e473a40dab..8c15e9ea1bbc4feea8a76cc599d7cdee4a5a3830 100644
--- a/src/r_textures.c
+++ b/src/r_textures.c
@@ -367,6 +367,7 @@ UINT8 *R_GenerateTexture(size_t texnum)
 		lumpnum_t lumpnum = patch->lump;
 		UINT8 *pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
 		patch_t *realpatch = NULL;
+		boolean free_patch = true;
 
 #ifndef NO_PNG_LUMPS
 		size_t lumplength = W_LumpLengthPwad(wadnum, lumpnum);
@@ -377,7 +378,16 @@ UINT8 *R_GenerateTexture(size_t texnum)
 		if (texture->type == TEXTURETYPE_FLAT)
 			realpatch = (patch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_PATCH, 0, NULL, texture->width, texture->height, 0, 0, 0);
 		else
-			realpatch = (patch_t *)Picture_Convert(PICFMT_DOOMPATCH, pdata, PICFMT_PATCH, 0, NULL, 0, 0, 0, 0, 0);
+		{
+			// If this patch has already been loaded, we just use it from the cache.
+			realpatch = W_GetCachedPatchNumPwad(wadnum, lumpnum);
+
+			// Otherwise, we convert it here.
+			if (realpatch == NULL)
+				realpatch = Patch_Create((softwarepatch_t *)pdata, NULL);
+			else
+				free_patch = false;
+		}
 
 		x1 = patch->originx;
 		width = realpatch->width;
@@ -386,13 +396,15 @@ UINT8 *R_GenerateTexture(size_t texnum)
 
 		if (x1 > texture->width || x2 < 0)
 		{
-			Patch_Free(realpatch);
+			if (free_patch)
+				Patch_Free(realpatch);
 			continue; // patch not located within texture's x bounds, ignore
 		}
 
 		if (patch->originy > texture->height || (patch->originy + height) < 0)
 		{
-			Patch_Free(realpatch);
+			if (free_patch)
+				Patch_Free(realpatch);
 			continue; // patch not located within texture's y bounds, ignore
 		}
 
@@ -417,10 +429,12 @@ UINT8 *R_GenerateTexture(size_t texnum)
 			else
 				patchcol = &realpatch->columns[x-x1];
 
-			columnDrawer(patchcol, columns[x].pixels, patch, texture->height, height);
+			if (patchcol->num_posts > 0)
+				columnDrawer(patchcol, columns[x].pixels, patch, texture->height, height);
 		}
 
-		Patch_Free(realpatch);
+		if (free_patch)
+			Patch_Free(realpatch);
 	}
 
 done:
diff --git a/src/w_wad.c b/src/w_wad.c
index 099b9381df992fff1da00ae2f22b310dd630f22c..d8226a0090c26b5f58acc6bbcb5df200ecc880c2 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -1987,8 +1987,7 @@ boolean W_IsLumpCached(lumpnum_t lumpnum, void *ptr)
 // If a patch is already cached return true, otherwise
 // return false.
 //
-// no outside code uses the PWAD form, for now
-static boolean W_IsPatchCachedPWAD(UINT16 wad, UINT16 lump, void *ptr)
+boolean W_IsPatchCachedPwad(UINT16 wad, UINT16 lump, void *ptr)
 {
 	void *lcache;
 
@@ -2010,7 +2009,7 @@ static boolean W_IsPatchCachedPWAD(UINT16 wad, UINT16 lump, void *ptr)
 
 boolean W_IsPatchCached(lumpnum_t lumpnum, void *ptr)
 {
-	return W_IsPatchCachedPWAD(WADFILENUM(lumpnum),LUMPNUM(lumpnum), ptr);
+	return W_IsPatchCachedPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum), ptr);
 }
 
 // ==========================================================================
@@ -2065,7 +2064,7 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
 #endif
 
 		dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]);
-		Patch_Create(ptr, len, dest);
+		Patch_Create(ptr, dest);
 		Z_Free(ptr);
 	}
 	else
@@ -2105,6 +2104,14 @@ void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag)
 	return W_CachePatchNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum),tag);
 }
 
+void *W_GetCachedPatchNumPwad(UINT16 wad, UINT16 lump)
+{
+	if (!TestValidLump(wad, lump))
+		return NULL;
+
+	return wadfiles[wad]->patchcache[lump];
+}
+
 void W_UnlockCachedPatch(void *patch)
 {
 	if (!patch)
diff --git a/src/w_wad.h b/src/w_wad.h
index ffb9095ba21c9e1d79049adadaa893953b097260..4c0f9b31465967458334d37c7d7babc2ef2daa4b 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -210,15 +210,15 @@ void *W_CacheLumpNumForce(lumpnum_t lumpnum, INT32 tag);
 
 boolean W_IsLumpCached(lumpnum_t lump, void *ptr);
 boolean W_IsPatchCached(lumpnum_t lump, void *ptr);
+boolean W_IsPatchCachedPwad(UINT16 wad, UINT16 lump, void *ptr);
 
 void *W_CacheLumpName(const char *name, INT32 tag);
 void *W_CachePatchName(const char *name, INT32 tag);
 void *W_CachePatchLongName(const char *name, INT32 tag);
 
-// Returns either a Software patch, or an OpenGL patch.
-// Performs any necessary conversions from PNG images.
 void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag);
 void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag);
+void *W_GetCachedPatchNumPwad(UINT16 wad, UINT16 lump);
 
 // Returns a Software patch.
 // Performs any necessary conversions from PNG images.