fixed memory leak, added minor details

This commit is contained in:
codeimp 2007-10-26 18:04:54 +00:00
parent 5e53809f96
commit f970c82d3f
15 changed files with 305 additions and 193 deletions

View file

@ -70,6 +70,7 @@
<Compile Include="Controls\ActionManager.cs" />
<Compile Include="Config\CompilerInfo.cs" />
<Compile Include="Config\ConfigurationInfo.cs" />
<Compile Include="General\Clock.cs" />
<Compile Include="General\MapManager.cs" />
<Compile Include="Controls\SpecialKeys.cs" />
<Compile Include="Config\NodebuilderInfo.cs" />

View file

@ -261,21 +261,24 @@ namespace CodeImp.DoomBuilder.Data
// This stops background loading
private void StopBackgroundLoader()
{
// Stop the thread and wait for it to end
General.WriteLogLine("Stopping background resource loading...");
backgroundloader.Interrupt();
backgroundloader.Join();
if(backgroundloader != null)
{
// Stop the thread and wait for it to end
backgroundloader.Interrupt();
backgroundloader.Join();
// Done
backgroundloader = null;
// Done
backgroundloader = null;
}
}
// The background loader
private void BackgroundLoad()
{
int loadedtextures;
int loadedflats;
int loadedsprites;
int loadedtextures, loadedflats, loadedsprites;
int starttime = General.Clock.GetCurrentTime();
int deltatime;
try
{
@ -290,10 +293,9 @@ namespace CodeImp.DoomBuilder.Data
}
// Done
General.WriteLogLine("Background resource loading completed");
General.WriteLogLine("Loaded textures: " + loadedtextures + " / " + textures.Count);
General.WriteLogLine("Loaded flats: " + loadedflats + " / " + flats.Count);
General.WriteLogLine("Loaded sprites: " + loadedsprites + " / " + sprites.Count);
deltatime = General.Clock.GetCurrentTime() - starttime;
General.WriteLogLine("Background resource loading completed in " + deltatime + "ms");
General.WriteLogLine("Loaded " + loadedtextures + " textures, " + loadedflats + " flats, " + loadedsprites + " sprites");
}
// This loads a list of ImageData

View file

@ -10,18 +10,6 @@ namespace CodeImp.DoomBuilder.Data
{
public sealed class FlatImage : ImageData
{
#region ================== Constants
#endregion
#region ================== Variables
#endregion
#region ================== Properties
#endregion
#region ================== Constructor / Disposer
// Constructor
@ -34,19 +22,6 @@ namespace CodeImp.DoomBuilder.Data
GC.SuppressFinalize(this);
}
// Diposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Done
base.Dispose();
}
}
#endregion
#region ================== Methods

View file

@ -67,9 +67,9 @@ namespace CodeImp.DoomBuilder.Data
public string Name { get { return name; } }
public long LongName { get { return longname; } }
public PixelColor* PixelData { get { return pixeldata; } }
public Bitmap Bitmap { get { return bitmap; } }
public Texture Texture { get { return texture; } }
public PixelColor* PixelData { get { lock(this) { return pixeldata; } } }
public Bitmap Bitmap { get { lock(this) { return bitmap; } } }
public Texture Texture { get { lock(this) { return texture; } } }
public bool IsLoaded { get { return (bitmap != null); } }
public bool IsDisposed { get { return isdisposed; } }
public int Width { get { return width; } }
@ -133,10 +133,10 @@ namespace CodeImp.DoomBuilder.Data
{
BitmapData bmpdata;
// Only do this when data is not created yet
if((pixeldata == null) && IsLoaded)
lock(this)
{
lock(this)
// Only do this when data is not created yet
if((pixeldata == null) && IsLoaded)
{
// Clean up old memory if reserved
if(pixeldata != null)
@ -162,10 +162,10 @@ namespace CodeImp.DoomBuilder.Data
{
MemoryStream memstream;
// Only do this when texture is not created yet
if((texture == null) && IsLoaded)
lock(this)
{
lock(this)
// Only do this when texture is not created yet
if((texture == null) && IsLoaded)
{
// Write to memory stream and read from memory
memstream = new MemoryStream();

View file

@ -73,7 +73,7 @@ namespace CodeImp.DoomBuilder.Data
for(uint i = 0; i < length; i++)
{
byte[] bytes = reader.ReadBytes(8);
pnames[i] = Lump.MakeNormalName(bytes, WAD.ENCODING);
pnames[i] = Lump.MakeNormalName(bytes, WAD.ENCODING).ToUpperInvariant();
}
}

View file

@ -33,18 +33,6 @@ namespace CodeImp.DoomBuilder.Data
{
public class ResourceImage : ImageData
{
#region ================== Constants
#endregion
#region ================== Variables
#endregion
#region ================== Properties
#endregion
#region ================== Constructor / Disposer
// Constructor
@ -57,19 +45,6 @@ namespace CodeImp.DoomBuilder.Data
GC.SuppressFinalize(this);
}
// Diposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Done
base.Dispose();
}
}
#endregion
#region ================== Methods

View file

@ -10,18 +10,6 @@ namespace CodeImp.DoomBuilder.Data
{
public sealed class SpriteImage : ImageData
{
#region ================== Constants
#endregion
#region ================== Variables
#endregion
#region ================== Properties
#endregion
#region ================== Constructor / Disposer
// Constructor
@ -34,19 +22,6 @@ namespace CodeImp.DoomBuilder.Data
GC.SuppressFinalize(this);
}
// Diposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Done
base.Dispose();
}
}
#endregion
#region ================== Methods

View file

@ -33,10 +33,6 @@ namespace CodeImp.DoomBuilder.Data
{
public sealed unsafe class TextureImage : ImageData
{
#region ================== Constants
#endregion
#region ================== Variables
private List<TexturePatch> patches;
@ -45,10 +41,6 @@ namespace CodeImp.DoomBuilder.Data
#endregion
#region ================== Properties
#endregion
#region ================== Constructor / Disposer
// Constructor
@ -68,19 +60,6 @@ namespace CodeImp.DoomBuilder.Data
GC.SuppressFinalize(this);
}
// Diposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Done
base.Dispose();
}
}
#endregion
#region ================== Methods
@ -128,7 +107,7 @@ namespace CodeImp.DoomBuilder.Data
patchdata.Read(membytes, 0, (int)patchdata.Length);
mem = new MemoryStream(membytes);
mem.Seek(0, SeekOrigin.Begin);
// Get a reader for the data
reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMPICTURE, General.Map.Data.Palette);
if(reader is UnknownImageReader)

View file

@ -176,14 +176,18 @@ namespace CodeImp.DoomBuilder.Data
// Go for all lumps between start and end exclusive
for(int i = startindex + 1; i < endindex; i++)
{
// Make the image object
image = new TextureImage(file.Lumps[i].Name, 0, 0, defaultscale, defaultscale);
// Lump not zero length?
if(file.Lumps[i].Length > 0)
{
// Make the image object
image = new TextureImage(file.Lumps[i].Name, 0, 0, defaultscale, defaultscale);
// Add single patch
image.AddPatch(new TexturePatch(file.Lumps[i].Name, 0, 0));
// Add image to collection
images.Add(image);
// Add single patch
image.AddPatch(new TexturePatch(file.Lumps[i].Name, 0, 0));
// Add image to collection
images.Add(image);
}
}
// Find the next start
@ -355,20 +359,25 @@ namespace CodeImp.DoomBuilder.Data
{
// Find end index
endindex = file.FindLumpIndex(endlump, startindex + 1);
if(endindex == -1) endindex = file.Lumps.Count - 1;
// Go for all lumps between start and end exclusive
for(int i = startindex + 1; i < endindex; i++)
if(endindex > -1)
{
// Make the image object
image = new FlatImage(file.Lumps[i].Name);
// Go for all lumps between start and end exclusive
for(int i = startindex + 1; i < endindex; i++)
{
// Lump not zero-length?
if(file.Lumps[i].Length > 0)
{
// Make the image object
image = new FlatImage(file.Lumps[i].Name);
// Add image to collection
images.Add(image);
// Add image to collection
images.Add(image);
}
}
}
// Find the next start
startindex = file.FindLumpIndex(startlump, endindex);
startindex = file.FindLumpIndex(startlump, startindex + 1);
}
}

162
Source/General/Clock.cs Normal file
View file

@ -0,0 +1,162 @@
#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
#endregion
namespace CodeImp.DoomBuilder
{
public class Clock : IDisposable
{
#region ================== Declarations
//#if !LINUX
[DllImport("kernel32.dll")]
private static extern short QueryPerformanceCounter(ref long x);
[DllImport("kernel32.dll")]
private static extern short QueryPerformanceFrequency(ref long x);
//#endif
#endregion
#region ================== Constants
// Set to true enable QPC if possible
private const bool USE_QPC = true;
// Frequency indicating QPC unavailable
private const long FREQ_NO_QPC = -1;
#endregion
#region ================== Variables
// Settings
private long timefrequency = FREQ_NO_QPC;
private double timescale;
private int currenttime;
// Disposing
private bool isdisposed = false;
#endregion
#region ================== Properties
// Settings
public bool IsUsingQPC { get { return (timefrequency != FREQ_NO_QPC); } }
public int CurrentTime { get { return currenttime; } }
// Disposing
public bool IsDisposed { get { return isdisposed; } }
#endregion
#region ================== Constructor / Disposer
// Constructor
public Clock()
{
// Only windows has QPC
//#if !LINUX
if(Environment.OSVersion.Platform != PlatformID.Unix)
{
// Get the high resolution clock frequency
if((QueryPerformanceFrequency(ref timefrequency) == 0) || !USE_QPC)
{
// No high resolution clock available
timefrequency = FREQ_NO_QPC;
}
else
{
// Calculate the time scale
timescale = (1d / (double)timefrequency) * 1000d;
}
}
//#endif
// We have no destructor
GC.SuppressFinalize(this);
}
// Diposer
public void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Done
isdisposed = true;
}
}
#endregion
#region ================== Methods
// This queries the system for the current time
public int GetCurrentTime()
{
// Only windows has QPC
//#if !LINUX
long timecount = 0;
// High resolution clock available?
if(timefrequency != FREQ_NO_QPC)
{
// Get the high resolution count
QueryPerformanceCounter(ref timecount);
// Calculate high resolution time in milliseconds
currenttime = (int)((double)timecount * timescale);
}
else
{
// Use standard clock
currenttime = Environment.TickCount;
}
/*
#else
// In LINUX always use standard clock
currenttime = Environment.TickCount;
#endif
*/
// Return the current time
return currenttime;
}
#endregion
}
}

View file

@ -108,6 +108,7 @@ namespace CodeImp.DoomBuilder
private static MapManager map;
private static ActionManager actions;
private static ColorCollection colors;
private static Clock clock;
// Configurations
private static List<ConfigurationInfo> configs;
@ -131,6 +132,7 @@ namespace CodeImp.DoomBuilder
public static List<CompilerInfo> Compilers { get { return compilers; } }
public static MapManager Map { get { return map; } }
public static ActionManager Actions { get { return actions; } }
public static Clock Clock { get { return clock; } }
#endregion
@ -437,6 +439,10 @@ namespace CodeImp.DoomBuilder
General.WriteLogLine("Loading color settings...");
colors = new ColorCollection(settings);
// Create application clock
General.WriteLogLine("Creating application clock...");
clock = new Clock();
// Run application from the main window
General.WriteLogLine("Startup done");
mainwindow.DisplayReady();
@ -519,6 +525,7 @@ namespace CodeImp.DoomBuilder
if(map != null) map.Dispose();
mainwindow.Dispose();
actions.Dispose();
clock.Dispose();
// Save colors
colors.SaveColors(settings);

View file

@ -105,15 +105,15 @@ namespace CodeImp.DoomBuilder.IO
// Done
bmp.UnlockBits(bitmapdata);
// Free memory
General.VirtualFree((void*)pixeldata, new UIntPtr((uint)(width * height * sizeof(PixelColor))), General.MEM_RELEASE);
}
else
{
// Failed loading picture
bmp = null;
}
// Free memory
General.VirtualFree((void*)pixeldata, new UIntPtr((uint)(width * height * sizeof(PixelColor))), General.MEM_RELEASE);
// Return result
return bmp;
@ -161,7 +161,7 @@ namespace CodeImp.DoomBuilder.IO
// This creates pixel color data from the given data
// Returns null on failure
public PixelColor* ReadAsPixelData(Stream stream, out int width, out int height)
private PixelColor* ReadAsPixelData(Stream stream, out int width, out int height)
{
BinaryReader reader = new BinaryReader(stream);
PixelColor* pixeldata = null;

View file

@ -121,6 +121,9 @@ namespace CodeImp.DoomBuilder.IO
// Done
bmp.UnlockBits(bitmapdata);
// Free memory
General.VirtualFree((void*)pixeldata, new UIntPtr((uint)(width * height * sizeof(PixelColor))), General.MEM_RELEASE);
}
else
{
@ -128,9 +131,6 @@ namespace CodeImp.DoomBuilder.IO
bmp = null;
}
// Free memory
General.VirtualFree((void*)pixeldata, new UIntPtr((uint)(width * height * sizeof(PixelColor))), General.MEM_RELEASE);
// Return result
return bmp;
}
@ -163,12 +163,15 @@ namespace CodeImp.DoomBuilder.IO
}
}
}
// Free memory
General.VirtualFree((void*)pixeldata, new UIntPtr((uint)(width * height * sizeof(PixelColor))), General.MEM_RELEASE);
}
}
// This creates pixel color data from the given data
// Returns null on failure
public PixelColor* ReadAsPixelData(Stream stream, out int width, out int height, out int offsetx, out int offsety)
private PixelColor* ReadAsPixelData(Stream stream, out int width, out int height, out int offsetx, out int offsety)
{
BinaryReader reader = new BinaryReader(stream);
PixelColor* pixeldata = null;

View file

@ -103,10 +103,14 @@ namespace CodeImp.DoomBuilder.Rendering
if(!isdisposed)
{
// Clean up
foreach(ID3DResource res in resources) res.UnloadResource();
if(shaders != null) shaders.Dispose();
renderer2d.Dispose();
renderer3d.Dispose();
device.Dispose();
rendertarget = null;
if(backbuffer != null) backbuffer.Dispose();
if(depthbuffer != null) depthbuffer.Dispose();
device.Dispose();
Direct3D.Terminate();
// Done
@ -313,6 +317,8 @@ namespace CodeImp.DoomBuilder.Rendering
// Unload all Direct3D resources
foreach(ID3DResource res in resources) res.UnloadResource();
if(shaders != null) shaders.Dispose();
if(backbuffer != null) backbuffer.Dispose();
if(depthbuffer != null) depthbuffer.Dispose();
// Make present parameters
displaypp = CreatePresentParameters(adapter);
@ -343,7 +349,7 @@ namespace CodeImp.DoomBuilder.Rendering
#region ================== Rendering
// This begins a drawing session
public bool StartRendering(int backcolor)
public bool StartRendering(bool clear, int backcolor)
{
CooperativeLevel coopresult;
@ -367,7 +373,7 @@ namespace CodeImp.DoomBuilder.Rendering
}
// Clear the screen
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, backcolor, 1f, 0);
if(clear) device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, backcolor, 1f, 0);
// Ready to render
device.BeginScene();
@ -381,7 +387,7 @@ namespace CodeImp.DoomBuilder.Rendering
}
// This ends a drawing session
public void FinishRendering()
public void FinishRendering(bool present)
{
try
{
@ -389,7 +395,7 @@ namespace CodeImp.DoomBuilder.Rendering
device.EndScene();
// Display the scene
device.Present();
if(present) device.Present();
}
// Errors are not a problem here
catch(Exception) { }

View file

@ -130,6 +130,7 @@ namespace CodeImp.DoomBuilder.Rendering
{
// Destroy rendertargets
DestroyRendertargets();
thingtexture.Dispose();
// Done
base.Dispose();
@ -144,7 +145,7 @@ namespace CodeImp.DoomBuilder.Rendering
public void Present()
{
// Start drawing
if(graphics.StartRendering(General.Colors.Background.ToInt()))
if(graphics.StartRendering(true, General.Colors.Background.ToInt()))
{
// Renderstates that count for this whole sequence
graphics.Device.SetRenderState(RenderState.CullMode, Cull.None);
@ -165,7 +166,8 @@ namespace CodeImp.DoomBuilder.Rendering
// Draw the lines and vertices texture
graphics.Shaders.Display2D.Begin();
graphics.Shaders.Display2D.BeginPass(0);
try { graphics.Device.DrawUserPrimitives<FlatVertex>(PrimitiveType.TriangleStrip, 0, 2, structverts); } catch(Exception) { }
//try { graphics.Device.DrawUserPrimitives<FlatVertex>(PrimitiveType.TriangleStrip, 0, 2, structverts); } catch(Exception) { }
graphics.Device.DrawUserPrimitives<FlatVertex>(PrimitiveType.TriangleStrip, 0, 2, structverts);
graphics.Shaders.Display2D.EndPass();
graphics.Shaders.Display2D.End();
@ -173,7 +175,7 @@ namespace CodeImp.DoomBuilder.Rendering
if(thingsfront) PresentThings(1f);
// Done
graphics.FinishRendering();
graphics.FinishRendering(true);
}
}
@ -196,7 +198,8 @@ namespace CodeImp.DoomBuilder.Rendering
// Draw the lines and vertices texture
graphics.Shaders.Display2D.Begin();
graphics.Shaders.Display2D.BeginPass(0);
try { graphics.Device.DrawUserPrimitives<FlatVertex>(PrimitiveType.TriangleStrip, 0, 2, thingsverts); } catch(Exception) { }
//try { graphics.Device.DrawUserPrimitives<FlatVertex>(PrimitiveType.TriangleStrip, 0, 2, thingsverts); } catch(Exception) { }
graphics.Device.DrawUserPrimitives<FlatVertex>(PrimitiveType.TriangleStrip, 0, 2, thingsverts);
graphics.Shaders.Display2D.EndPass();
graphics.Shaders.Display2D.End();
}
@ -382,7 +385,7 @@ namespace CodeImp.DoomBuilder.Rendering
if(thingsvertices != null) thingsvertices.Dispose();
// Create new buffer
thingsvertices = new VertexBuffer(graphics.Device, newmaxthings * 12 * FlatVertex.Stride, Usage.Dynamic, VertexFormat.None, Pool.Default);
thingsvertices = new VertexBuffer(graphics.Device, newmaxthings * 12 * FlatVertex.Stride, Usage.None, VertexFormat.None, Pool.Managed);
maxthings = newmaxthings;
}
else
@ -510,21 +513,26 @@ namespace CodeImp.DoomBuilder.Rendering
// This draws a set of things
private void RenderThingsBatch(int offset, int count)
{
// Set renderstates for things rendering
graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, false);
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, true);
graphics.Device.SetRenderState(RenderState.AlphaFunc, Compare.GreaterEqual);
graphics.Device.SetRenderState(RenderState.AlphaRef, 0x0000007F);
graphics.Device.SetTexture(0, thingtexture.Texture);
graphics.Shaders.Things2D.Texture1 = thingtexture.Texture;
graphics.Device.SetStreamSource(0, thingsvertices, 0, FlatVertex.Stride);
// Draw the things batched
graphics.Shaders.Things2D.Begin();
graphics.Shaders.Things2D.BeginPass(0);
try { graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, offset * 12, count * 4); } catch(Exception) { }
graphics.Shaders.Things2D.EndPass();
graphics.Shaders.Things2D.End();
// Anything to render?
if(count > 0)
{
// Set renderstates for things rendering
graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, false);
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, true);
graphics.Device.SetRenderState(RenderState.AlphaFunc, Compare.GreaterEqual);
graphics.Device.SetRenderState(RenderState.AlphaRef, 0x0000007F);
graphics.Device.SetTexture(0, thingtexture.Texture);
graphics.Shaders.Things2D.Texture1 = thingtexture.Texture;
graphics.Device.SetStreamSource(0, thingsvertices, 0, FlatVertex.Stride);
// Draw the things batched
graphics.Shaders.Things2D.Begin();
graphics.Shaders.Things2D.BeginPass(0);
//try { graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, offset * 12, count * 4); } catch(Exception) { }
graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, offset * 12, count * 4);
graphics.Shaders.Things2D.EndPass();
graphics.Shaders.Things2D.End();
}
}
#endregion
@ -603,30 +611,33 @@ namespace CodeImp.DoomBuilder.Rendering
plotter = new Plotter((PixelColor*)structlocked.Data.DataPointer.ToPointer(), structlocked.Pitch / sizeof(PixelColor), structsize.Height, structsize.Width, structsize.Height);
if(clearstructs) plotter.Clear();
// Set the rendertarget to the things texture
thingssurface = thingstex.GetSurfaceLevel(0);
graphics.Device.SetDepthStencilSurface(null);
graphics.Device.SetRenderTarget(0, thingssurface);
// Clear the things?
if(clearthings)
{
// Clear rendertarget
graphics.Device.Clear(ClearFlags.Target, 0, 1f, 0);
}
// Always trash things batch buffer
if(thingsvertices != null) thingsvertices.Dispose();
thingsvertices = null;
numthings = 0;
maxthings = 0;
// Ready for rendering
return true;
// Set the rendertarget to the things texture
thingssurface = thingstex.GetSurfaceLevel(0);
graphics.Device.SetDepthStencilSurface(null);
graphics.Device.SetRenderTarget(0, thingssurface);
if(clearthings) graphics.Device.Clear(ClearFlags.Target, 0, 1f, 0);
if(graphics.StartRendering(false, 0))
{
// Ready for rendering
return true;
}
else
{
// Can't render!
FinishRendering();
return false;
}
}
else
{
// Can't render!
FinishRendering();
return false;
}
}
@ -634,17 +645,24 @@ namespace CodeImp.DoomBuilder.Rendering
// This ends a drawing session
public void FinishRendering()
{
// Unlock memory
structtex.UnlockRectangle(0);
structlocked.Data.Dispose();
plotter = null;
// Stop rendering
graphics.FinishRendering(false);
// Release rendertarget
graphics.Device.SetDepthStencilSurface(graphics.DepthBuffer);
graphics.Device.SetRenderTarget(0, graphics.BackBuffer);
thingssurface.Dispose();
thingssurface = null;
try
{
graphics.Device.SetDepthStencilSurface(graphics.DepthBuffer);
graphics.Device.SetRenderTarget(0, graphics.BackBuffer);
}
catch(Exception) { }
// Clean up
if(structtex != null) structtex.UnlockRectangle(0);
if(structlocked.Data != null) structlocked.Data.Dispose();
if(thingssurface != null) thingssurface.Dispose();
thingssurface = null;
plotter = null;
// Present new image
Present();
}