diff --git a/lib/RefreshCS b/lib/RefreshCS
index 610698f..98c590a 160000
--- a/lib/RefreshCS
+++ b/lib/RefreshCS
@@ -1 +1 @@
-Subproject commit 610698fcd63f4c135fc0f60f38ccc8707ce568eb
+Subproject commit 98c590ae77c3b6a64a370bac439f20728959a8b6
diff --git a/src/Graphics/RefreshEnums.cs b/src/Graphics/RefreshEnums.cs
index 03fd4bc..12d70c8 100644
--- a/src/Graphics/RefreshEnums.cs
+++ b/src/Graphics/RefreshEnums.cs
@@ -67,6 +67,7 @@ namespace MoonWorks.Graphics
 		BC1,
 		BC2,
 		BC3,
+		BC7,
 		R8G8_SNORM,
 		R8G8B8A8_SNORM,
 		A2R10G10B10,
diff --git a/src/Graphics/Resources/Texture.cs b/src/Graphics/Resources/Texture.cs
index e604a78..86d5f07 100644
--- a/src/Graphics/Resources/Texture.cs
+++ b/src/Graphics/Resources/Texture.cs
@@ -1,4 +1,5 @@
 using System;
+using System.IO;
 using RefreshCS;
 
 namespace MoonWorks.Graphics
@@ -56,6 +57,9 @@ namespace MoonWorks.Graphics
 			return texture;
 		}
 
+		/// 
+		/// Saves RGBA or BGRA pixel data to a file in PNG format.
+		/// 
 		public unsafe static void SavePNG(string path, int width, int height, TextureFormat format, byte[] pixels)
 		{
 			if (format != TextureFormat.R8G8B8A8 && format != TextureFormat.B8G8R8A8)
@@ -69,6 +73,34 @@ namespace MoonWorks.Graphics
 			}
 		}
 
+		public static Texture LoadDDS(GraphicsDevice graphicsDevice, CommandBuffer commandBuffer, System.IO.Stream stream)
+		{
+			using (var reader = new BinaryReader(stream))
+			{
+				ParseDDS(reader, out var format, out var width, out var height, out var levels);
+				Texture texture = CreateTexture2D(graphicsDevice, (uint) width, (uint) height, format, TextureUsageFlags.Sampler, SampleCount.One, (uint) levels);
+
+				for (int i = 0; i < levels; i += 1)
+				{
+					var levelWidth = width >> i;
+					var levelHeight = height >> i;
+
+					var pixels = reader.ReadBytes(
+						Texture.CalculateDDSLevelSize(
+							levelWidth,
+							levelHeight,
+							format
+						)
+					);
+
+					var textureSlice = new TextureSlice(texture, new Rect(0, 0, levelWidth, levelHeight), 0, 0, (uint) i);
+					commandBuffer.SetTextureData(textureSlice, pixels);
+				}
+
+				return texture;
+			}
+		}
+
 		/// 
 		/// Creates a 2D texture.
 		/// 
@@ -222,5 +254,202 @@ namespace MoonWorks.Graphics
 			LevelCount = 1;
 			UsageFlags = TextureUsageFlags.ColorTarget;
 		}
+
+		// DDS loading extension, based on MojoDDS
+		// Taken from https://github.com/FNA-XNA/FNA/blob/1e49f868f595f62bc6385db45949a03186a7cd7f/src/Graphics/Texture.cs#L194
+		private static void ParseDDS(
+			BinaryReader reader,
+			out TextureFormat format,
+			out int width,
+			out int height,
+			out int levels
+		) {
+			// A whole bunch of magic numbers, yay DDS!
+			const uint DDS_MAGIC = 0x20534444;
+			const uint DDS_HEADERSIZE = 124;
+			const uint DDS_PIXFMTSIZE = 32;
+			const uint DDSD_CAPS = 0x1;
+			const uint DDSD_HEIGHT = 0x2;
+			const uint DDSD_WIDTH = 0x4;
+			const uint DDSD_PITCH = 0x8;
+			const uint DDSD_FMT = 0x1000;
+			const uint DDSD_LINEARSIZE = 0x80000;
+			const uint DDSD_REQ = (
+				DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_FMT
+			);
+			const uint DDSCAPS_MIPMAP = 0x400000;
+			const uint DDSCAPS_TEXTURE = 0x1000;
+			const uint DDSCAPS2_CUBEMAP = 0x200;
+			const uint DDPF_FOURCC = 0x4;
+			const uint DDPF_RGB = 0x40;
+			const uint FOURCC_DXT1 = 0x31545844;
+			const uint FOURCC_DXT3 = 0x33545844;
+			const uint FOURCC_DXT5 = 0x35545844;
+			const uint FOURCC_BPTC = 0x30315844;
+			// const uint FOURCC_DX10 = 0x30315844;
+			const uint pitchAndLinear = (
+				DDSD_PITCH | DDSD_LINEARSIZE
+			);
+
+			// File should start with 'DDS '
+			if (reader.ReadUInt32() != DDS_MAGIC)
+			{
+				throw new NotSupportedException("Not a DDS!");
+			}
+
+			// Texture info
+			uint size = reader.ReadUInt32();
+			if (size != DDS_HEADERSIZE)
+			{
+				throw new NotSupportedException("Invalid DDS header!");
+			}
+			uint flags = reader.ReadUInt32();
+			if ((flags & DDSD_REQ) != DDSD_REQ)
+			{
+				throw new NotSupportedException("Invalid DDS flags!");
+			}
+			if ((flags & pitchAndLinear) == pitchAndLinear)
+			{
+				throw new NotSupportedException("Invalid DDS flags!");
+			}
+			height = reader.ReadInt32();
+			width = reader.ReadInt32();
+			reader.ReadUInt32(); // dwPitchOrLinearSize, unused
+			reader.ReadUInt32(); // dwDepth, unused
+			levels = reader.ReadInt32();
+
+			// "Reserved"
+			reader.ReadBytes(4 * 11);
+
+			// Format info
+			uint formatSize = reader.ReadUInt32();
+			if (formatSize != DDS_PIXFMTSIZE)
+			{
+				throw new NotSupportedException("Bogus PIXFMTSIZE!");
+			}
+			uint formatFlags = reader.ReadUInt32();
+			uint formatFourCC = reader.ReadUInt32();
+			uint formatRGBBitCount = reader.ReadUInt32();
+			uint formatRBitMask = reader.ReadUInt32();
+			uint formatGBitMask = reader.ReadUInt32();
+			uint formatBBitMask = reader.ReadUInt32();
+			uint formatABitMask = reader.ReadUInt32();
+
+			// dwCaps "stuff"
+			uint caps = reader.ReadUInt32();
+			if ((caps & DDSCAPS_TEXTURE) == 0)
+			{
+				throw new NotSupportedException("Not a texture!");
+			}
+			uint caps2 = reader.ReadUInt32();
+			if (	caps2 != 0 &&
+				(caps2 & DDSCAPS2_CUBEMAP) != DDSCAPS2_CUBEMAP	)
+			{
+				throw new NotSupportedException("Invalid caps2!");
+			}
+			reader.ReadUInt32(); // dwCaps3, unused
+			reader.ReadUInt32(); // dwCaps4, unused
+
+			// "Reserved"
+			reader.ReadUInt32();
+
+			// Mipmap sanity check
+			if ((caps & DDSCAPS_MIPMAP) != DDSCAPS_MIPMAP)
+			{
+				levels = 1;
+			}
+
+			// Determine texture format
+			if ((formatFlags & DDPF_FOURCC) == DDPF_FOURCC)
+			{
+				switch (formatFourCC)
+				{
+					case 0x71:
+						format = TextureFormat.R16G16B16A16_SFLOAT;
+						break;
+					case 0x74:
+						format = TextureFormat.R32G32B32A32_SFLOAT;
+						break;
+					case FOURCC_DXT1:
+						format = TextureFormat.BC1;
+						break;
+					case FOURCC_DXT3:
+						format = TextureFormat.BC2;
+						break;
+					case FOURCC_DXT5:
+						format = TextureFormat.BC3;
+						break;
+					case FOURCC_BPTC:
+						format = TextureFormat.BC7;
+						// These next 5 uints are part of the DX10 DDS header.
+						// They contain a little extra information but aren't that important.
+						uint dxgiFormat = reader.ReadUInt32();
+						uint resourceDimension = reader.ReadUInt32();
+						uint miscFlag = reader.ReadUInt32();
+						uint arraySize = reader.ReadUInt32();
+						reader.ReadUInt32(); // reserved
+						break;
+					default:
+						throw new NotSupportedException(
+							"Unsupported DDS texture format"
+						);
+				}
+			}
+			else if ((formatFlags & DDPF_RGB) == DDPF_RGB)
+			{
+				if (	formatRGBBitCount != 32 ||
+					formatRBitMask != 0x00FF0000 ||
+					formatGBitMask != 0x0000FF00 ||
+					formatBBitMask != 0x000000FF ||
+					formatABitMask != 0xFF000000	)
+				{
+					throw new NotSupportedException(
+						"Unsupported DDS texture format"
+					);
+				}
+
+				format = TextureFormat.B8G8R8A8;
+			}
+			else
+			{
+				throw new NotSupportedException(
+					"Unsupported DDS texture format"
+				);
+			}
+		}
+
+		private static int CalculateDDSLevelSize(
+			int width,
+			int height,
+			TextureFormat format
+		) {
+			if (format == TextureFormat.R8G8B8A8)
+			{
+				return (((width * 32) + 7) / 8) * height;
+			}
+			else if (format == TextureFormat.R16G16B16A16_SFLOAT)
+			{
+				return (((width * 64) + 7) / 8) * height;
+			}
+			else if (format == TextureFormat.R32G32B32A32_SFLOAT)
+			{
+				return (((width * 128) + 7) / 8) * height;
+			}
+			else
+			{
+				int blockSize = 16;
+				if (format == TextureFormat.BC1)
+				{
+					blockSize = 8;
+				}
+				width = System.Math.Max(width, 1);
+				height = System.Math.Max(height, 1);
+				return (
+					((width + 3) / 4) *
+					((height + 3) / 4) *
+					blockSize
+				);
+			}
+		}
 	}
 }