浏览代码

added 8MB emulated cache for recent I/O : optimize for HMD models multiple reads and textures double-read

ncannasse 7 年之前
父节点
当前提交
7150753f22
共有 1 个文件被更改,包括 58 次插入4 次删除
  1. 58 4
      hxd/fmt/pak/FileSystem.hx

+ 58 - 4
hxd/fmt/pak/FileSystem.hx

@@ -26,17 +26,21 @@ class FileInput extends haxe.io.BytesInput {
 #end
 
 @:allow(hxd.fmt.pak.FileSystem)
+@:access(hxd.fmt.pak.FileSystem)
 private class PakEntry extends FileEntry {
 
+	var fs : FileSystem;
 	var parent : PakEntry;
 	var file : Data.File;
 	var pak : FileInput;
 	var subs : Array<PakEntry>;
 
 	var openedBytes : haxe.io.Bytes;
+	var cachedBytes : haxe.io.Bytes;
 	var bytesPosition : Int;
 
-	public function new(parent, f, p) {
+	public function new(fs, parent, f, p) {
+		this.fs = fs;
 		this.file = f;
 		this.pak = p;
 		this.parent = parent;
@@ -58,23 +62,36 @@ private class PakEntry extends FileEntry {
 
 	override function getSign() {
 		pak.seek(file.dataPosition, SeekBegin);
+		fs.totalReadBytes += 4;
+		fs.totalReadCount++;
 		return pak.readInt32();
 	}
 
 	override function getBytes() {
+		if( cachedBytes != null )
+			return cachedBytes;
 		pak.seek(file.dataPosition, SeekBegin);
+		fs.totalReadBytes += file.dataSize;
+		fs.totalReadCount++;
 		return pak.read(file.dataSize);
 	}
 
 	override function getTmpBytes() {
+		// don't use cacheBytes
 		pak.seek(file.dataPosition, SeekBegin);
 		var tmp = hxd.impl.Tmp.getBytes(file.dataSize);
+		fs.totalReadBytes += file.dataSize;
+		fs.totalReadCount++;
 		pak.readFullBytes(tmp, 0, file.dataSize);
 		return tmp;
 	}
 
 	override function open() {
+		if( openedBytes == null )
+			openedBytes = fs.getCached(this);
 		if( openedBytes == null ) {
+			fs.totalReadBytes += file.dataSize;
+			fs.totalReadCount++;
 			openedBytes = hxd.impl.Tmp.getBytes(file.dataSize);
 			pak.seek(file.dataPosition, SeekBegin);
 			pak.readBytes(openedBytes, 0, file.dataSize);
@@ -84,7 +101,7 @@ private class PakEntry extends FileEntry {
 
 	override function close() {
 		if( openedBytes != null ) {
-			hxd.impl.Tmp.saveBytes(openedBytes);
+			fs.saveCached(this);
 			openedBytes = null;
 		}
 	}
@@ -157,6 +174,11 @@ class FileSystem implements hxd.fs.FileSystem {
 	var root : PakEntry;
 	var dict : Map<String,PakEntry>;
 	var files : Array<FileInput>;
+	var readCache : Array<PakEntry> = [];
+	var currentCacheSize = 0;
+	public var readCacheSize = 8 << 20; // 8 MB of emulated cache
+	public var totalReadBytes = 0;
+	public var totalReadCount = 0;
 
 	public function new() {
 		dict = new Map();
@@ -165,7 +187,7 @@ class FileSystem implements hxd.fs.FileSystem {
 		f.isDirectory = true;
 		f.content = [];
 		files = [];
-		root = new PakEntry(null, f, null);
+		root = new PakEntry(this, null, f, null);
 	}
 
 	public function loadPak( file : String ) {
@@ -192,13 +214,45 @@ class FileSystem implements hxd.fs.FileSystem {
 		files = [];
 	}
 
+	function getCached( e : PakEntry ) {
+		if( readCacheSize == 0 )
+			return null;
+		var index = readCache.lastIndexOf(e);
+		if( index < 0 )
+			return null;
+		if( index != readCache.length - 1 ) {
+			readCache.splice(index, 1);
+			readCache.push(e);
+		}
+		return e.cachedBytes;
+	}
+
+	function saveCached( e : PakEntry ) {
+		if( readCacheSize == 0 )
+			return;
+		var index = readCache.lastIndexOf(e);
+		if( index < 0 ) {
+			// don't cache if too big wrt our size
+			if( e.openedBytes.length >= (readCacheSize >> 1) )
+				return;
+			readCache.push(e);
+			e.cachedBytes = e.openedBytes;
+			currentCacheSize += e.cachedBytes.length;
+		}
+		while( currentCacheSize > readCacheSize ) {
+			var e = readCache.shift();
+			currentCacheSize -= e.cachedBytes.length;
+			e.cachedBytes = null;
+		}
+	}
+
 	function addRec( parent : PakEntry, path : String, f : Data.File, pak : FileInput, delta : Int ) {
 		var ent = dict.get(path);
 		if( ent != null ) {
 			ent.file = f;
 			ent.pak = pak;
 		} else {
-			ent = new PakEntry(parent, f, pak);
+			ent = new PakEntry(this, parent, f, pak);
 			dict.set(path, ent);
 			parent.subs.push(ent);
 		}