diff --git a/include/renderer_mtl/pica_to_mtl.hpp b/include/renderer_mtl/pica_to_mtl.hpp
index 715088b4..beb63b17 100644
--- a/include/renderer_mtl/pica_to_mtl.hpp
+++ b/include/renderer_mtl/pica_to_mtl.hpp
@@ -10,6 +10,8 @@ namespace PICA {
 		size_t bytesPerTexel;
 	};
 
+// iOS, at least on simulator, doesn't support a lot of more "exotic" texture formats, so we avoid them tehre
+#ifndef PANDA3DS_IOS
 	constexpr PixelFormatInfo pixelFormatInfos[14] = {
 		{MTL::PixelFormatRGBA8Unorm, 4},   // RGBA8
 		{MTL::PixelFormatRGBA8Unorm, 4},   // RGB8
@@ -26,6 +28,24 @@ namespace PICA {
 		{MTL::PixelFormatRGBA8Unorm, 4},   // ETC1
 		{MTL::PixelFormatRGBA8Unorm, 4},   // ETC1A4
 	};
+#else
+	constexpr PixelFormatInfo pixelFormatInfos[14] = {
+		{MTL::PixelFormatRGBA8Unorm, 4},   // RGBA8
+		{MTL::PixelFormatRGBA8Unorm, 4},   // RGB8
+		{MTL::PixelFormatBGR5A1Unorm, 2},  // RGBA5551
+		{MTL::PixelFormatRGBA8Unorm, 4},   // RGB565
+		{MTL::PixelFormatRGBA8Unorm, 4},   // RGBA4
+		{MTL::PixelFormatRGBA8Unorm, 4},   // IA8
+		{MTL::PixelFormatRG8Unorm, 2},     // RG8
+		{MTL::PixelFormatRGBA8Unorm, 4},   // I8
+		{MTL::PixelFormatA8Unorm, 1},      // A8
+		{MTL::PixelFormatRGBA8Unorm, 4},   // IA4
+		{MTL::PixelFormatRGBA8Unorm, 4},   // I4
+		{MTL::PixelFormatA8Unorm, 1},      // A4
+		{MTL::PixelFormatRGBA8Unorm, 4},   // ETC1
+		{MTL::PixelFormatRGBA8Unorm, 4},   // ETC1A4
+	};
+#endif
 
 	inline PixelFormatInfo getPixelFormatInfo(TextureFmt format) { return pixelFormatInfos[static_cast<int>(format)]; }
 
@@ -35,7 +55,11 @@ namespace PICA {
 			case ColorFmt::RGB8: return MTL::PixelFormatRGBA8Unorm;
 			case ColorFmt::RGBA5551: return MTL::PixelFormatRGBA8Unorm;  // TODO: use MTL::PixelFormatBGR5A1Unorm?
 			case ColorFmt::RGB565: return MTL::PixelFormatRGBA8Unorm;    // TODO: use MTL::PixelFormatB5G6R5Unorm?
+#ifdef PANDA3DS_IOS
+			case ColorFmt::RGBA4: return MTL::PixelFormatRGBA8Unorm; // IOS + Metal doesn't support AGBR4 properly, at least on simulator
+#else
 			case ColorFmt::RGBA4: return MTL::PixelFormatABGR4Unorm;
+#endif
 		}
 	}
 
diff --git a/src/core/renderer_mtl/mtl_texture.cpp b/src/core/renderer_mtl/mtl_texture.cpp
index 149fea26..a110b88f 100644
--- a/src/core/renderer_mtl/mtl_texture.cpp
+++ b/src/core/renderer_mtl/mtl_texture.cpp
@@ -251,6 +251,53 @@ namespace Metal {
 				return (alpha << 24) | (b << 16) | (g << 8) | r;
 			}
 
+			case PICA::TextureFmt::ETC1: return getTexelETC(false, u, v, size.u(), data);
+			case PICA::TextureFmt::ETC1A4: return getTexelETC(true, u, v, size.u(), data);
+
+			case PICA::TextureFmt::RGBA4: {
+				u32 offset = getSwizzledOffset(u, v, size.u(), 2);
+				u16 texel = u16(data[offset]) | (u16(data[offset + 1]) << 8);
+
+				u8 alpha = Colour::convert4To8Bit(getBits<0, 4, u8>(texel));
+				u8 b = Colour::convert4To8Bit(getBits<4, 4, u8>(texel));
+				u8 g = Colour::convert4To8Bit(getBits<8, 4, u8>(texel));
+				u8 r = Colour::convert4To8Bit(getBits<12, 4, u8>(texel));
+
+				return (alpha << 24) | (b << 16) | (g << 8) | r;
+			}
+
+			case PICA::TextureFmt::I4: {
+				u32 offset = getSwizzledOffset_4bpp(u, v, size.u());
+
+				// For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates
+				u8 intensity = data[offset] >> ((u % 2) ? 4 : 0);
+				intensity = Colour::convert4To8Bit(getBits<0, 4>(intensity));
+
+				// Intensity formats just copy the intensity value to every colour channel
+				return (0xff << 24) | (intensity << 16) | (intensity << 8) | intensity;
+			}
+
+			case PICA::TextureFmt::IA4: {
+				const u32 offset = getSwizzledOffset(u, v, size.u(), 1);
+				const u8 texel = data[offset];
+				const u8 alpha = Colour::convert4To8Bit(texel & 0xf);
+				const u8 intensity = Colour::convert4To8Bit(texel >> 4);
+
+				// Intensity formats just copy the intensity value to every colour channel
+				return (alpha << 24) | (intensity << 16) | (intensity << 8) | intensity;
+			}
+
+			case PICA::TextureFmt::A4: {
+				const u32 offset = getSwizzledOffset_4bpp(u, v, size.u());
+
+				// For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates
+				u8 alpha = data[offset] >> ((u % 2) ? 4 : 0);
+				alpha = Colour::convert4To8Bit(getBits<0, 4>(alpha));
+
+				// A8 sets RGB to 0
+				return (alpha << 24) | (0 << 16) | (0 << 8) | 0;
+			}
+
 			case PICA::TextureFmt::I8: {
 				u32 offset = getSwizzledOffset(u, v, size.u(), 1);
 				const u8 intensity = data[offset];
@@ -270,8 +317,16 @@ namespace Metal {
 				return (alpha << 24) | (intensity << 16) | (intensity << 8) | intensity;
 			}
 
-			case PICA::TextureFmt::ETC1: return getTexelETC(false, u, v, size.u(), data);
-			case PICA::TextureFmt::ETC1A4: return getTexelETC(true, u, v, size.u(), data);
+			case PICA::TextureFmt::RGB565: {
+				const u32 offset = getSwizzledOffset(u, v, size.u(), 2);
+				const u16 texel = u16(data[offset]) | (u16(data[offset + 1]) << 8);
+
+				const u8 b = Colour::convert5To8Bit(getBits<0, 5, u8>(texel));
+				const u8 g = Colour::convert6To8Bit(getBits<5, 6, u8>(texel));
+				const u8 r = Colour::convert5To8Bit(getBits<11, 5, u8>(texel));
+
+				return (0xff << 24) | (b << 16) | (g << 8) | r;
+			}
 
 			default: Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast<int>(fmt));
 		}
diff --git a/src/ios_driver.mm b/src/ios_driver.mm
index e3fd9342..d9a0d544 100644
--- a/src/ios_driver.mm
+++ b/src/ios_driver.mm
@@ -23,9 +23,9 @@ IOS_EXPORT void iosCreateEmulator() {
 	emulator->initGraphicsContext(nullptr);
 
 	// auto path = emulator->getAppDataRoot() / "Kirb Demo.3ds";
-	// auto path = emulator->getAppDataRoot() / "Kirb Demo.3ds";
+	auto path = emulator->getAppDataRoot() / "Kirb Demo.3ds";
 
-	auto path = emulator->getAppDataRoot() / "toon_shading.elf";
+	//auto path = emulator->getAppDataRoot() / "toon_shading.elf";
 	emulator->loadROM(path);
 	printf("Created emulator\n");
 }