public static ITexture2D LoadTexture(string filename, bool generateMips = false) { Assure.NotNull(filename); lock (staticMutationLock) { if (loadedTextures.ContainsKey(filename)) { ++textureRefCounts[filename]; return(loadedTextures[filename]); } } string fullFilePath = Path.Combine(MaterialsDir, filename); if (!File.Exists(fullFilePath)) { throw new FileNotFoundException("Given texture file '" + filename + "' is not in the materials folder."); } ITexture2D loadedTex = null; GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(2, GCCollectionMode.Forced, true); if (generateMips) { var mipmapFilePath = Path.Combine(MaterialsDir, "Mipmaps\\", Path.GetFileNameWithoutExtension(filename)) + ".mipmap"; if (File.Exists(mipmapFilePath)) { byte[] dataBytes = File.ReadAllBytes(mipmapFilePath); int texelTypeID; uint width, height; using (MemoryStream ms = new MemoryStream(dataBytes)) { BinaryReader br = new BinaryReader(ms); texelTypeID = br.ReadInt32(); width = br.ReadUInt32(); height = br.ReadUInt32(); } Type texelType = TexelFormat.AllFormats.First(kvp => kvp.Value.ResourceFormatIndex == texelTypeID).Key; var createTex2DMethod = typeof(TextureFactory) .GetMethod("NewTexture2D", BindingFlags.Public | BindingFlags.Static) .MakeGenericMethod(texelType); dynamic builder = createTex2DMethod.Invoke(null, new object[0]); loadedTex = builder.WithPermittedBindings(GPUBindings.ReadableShaderResource) .WithUsage(ResourceUsage.Immutable) .WithMipAllocation(true) .WithWidth(width) .WithHeight(height) .WithInitialData(new ArraySlice <byte>(dataBytes, 4U)) .Create(); } else { Logger.Log("No mipmap data found for file '" + fullFilePath + "'; "); LosgapSystem.InvokeOnMaster(() => { ITexture2D singleTex = TextureFactory.LoadTexture2D().WithFilePath(fullFilePath) .WithPermittedBindings(GPUBindings.None) .WithUsage(ResourceUsage.StagingReadWrite) .Create(); ITexture2D mipGenTarget = ((dynamic)singleTex).Clone(false) .WithMipAllocation(true) .WithMipGenerationTarget(true) .WithPermittedBindings(GPUBindings.RenderTarget | GPUBindings.ReadableShaderResource) .WithUsage(ResourceUsage.Write) .Create(); singleTex.GetType().GetMethod( "CopyTo", new[] { singleTex.GetType(), typeof(SubresourceBox), typeof(UInt32), typeof(UInt32), typeof(UInt32), typeof(UInt32) } ).Invoke( singleTex, new object[] { mipGenTarget, new SubresourceBox(0U, singleTex.Width, 0U, singleTex.Height), 0U, 0U, 0U, 0U } ); mipGenTarget.GenerateMips(); ITexture2D stagingTex = ((dynamic)mipGenTarget).Clone(false) .WithPermittedBindings(GPUBindings.None) .WithUsage(ResourceUsage.StagingReadWrite) .WithMipGenerationTarget(false) .Create(); mipGenTarget.CopyTo(stagingTex); using (MemoryStream ms = new MemoryStream()) { BinaryWriter bw = new BinaryWriter(ms); bw.Write(TexelFormat.AllFormats[mipGenTarget.TexelFormat].ResourceFormatIndex); bw.Write(stagingTex.Width); bw.Write(stagingTex.Height); bw.Write(stagingTex.ReadRaw()); ms.Seek(0L, SeekOrigin.Begin); File.WriteAllBytes(mipmapFilePath, ms.ToArray()); } loadedTex = ((dynamic)stagingTex).Clone(true) .WithPermittedBindings(GPUBindings.ReadableShaderResource) .WithUsage(ResourceUsage.Immutable) .Create(); singleTex.Dispose(); mipGenTarget.Dispose(); stagingTex.Dispose(); }); } } else { loadedTex = TextureFactory.LoadTexture2D().WithFilePath(fullFilePath) .WithPermittedBindings(GPUBindings.ReadableShaderResource) .WithUsage(ResourceUsage.Immutable) .Create(); } lock (staticMutationLock) { loadedTextures[filename] = loadedTex; textureRefCounts[filename] = 1U; } GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(2, GCCollectionMode.Forced, true); return(loadedTex); }