fixed minor memory leaks in main_window. when the nds core sets execution to false, an error message is now displayed to let the user know that emulation has stopped. video output frame rate is now limited, which makes the gui more responsive especially when emulation is provided new frames as fast or faster than they can be blitted to the screen
This commit is contained in:
parent
e42186683d
commit
6f92277993
|
@ -27,7 +27,6 @@ Based on work by yopyop and the DeSmuME team!
|
||||||
#import "preferences.h"
|
#import "preferences.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
FIXME: When cross-platform (core) components end emulation due to error - pause should be called (set the menu checkmark)
|
|
||||||
FIXME: .nds.gba support?
|
FIXME: .nds.gba support?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -114,11 +114,11 @@ NSMenuItem *screenshot_to_file_item;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{//fixme non leaky exception handling
|
{
|
||||||
//Create the NDS
|
//Create the NDS
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
if(self == nil)return nil;
|
if(self == nil)return nil; //superclass will display it's own error messages if needed
|
||||||
|
|
||||||
//
|
//
|
||||||
NSRect rect;
|
NSRect rect;
|
||||||
|
@ -139,6 +139,14 @@ NSMenuItem *screenshot_to_file_item;
|
||||||
backing:NSBackingStoreBuffered defer:NO screen:nil])==nil)
|
backing:NSBackingStoreBuffered defer:NO screen:nil])==nil)
|
||||||
{
|
{
|
||||||
messageDialog(NSLocalizedString(@"Error", nil), @"Couldn't create window");
|
messageDialog(NSLocalizedString(@"Error", nil), @"Couldn't create window");
|
||||||
|
|
||||||
|
//release the superclass (this will probably call our own destructor, so set nil members)
|
||||||
|
controller = nil;
|
||||||
|
video_output_view = nil;
|
||||||
|
status_view = nil;
|
||||||
|
input = nil;
|
||||||
|
[super release];
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
[window setTitle:NSLocalizedString(@"DeSmuME Emulator", nil)];
|
[window setTitle:NSLocalizedString(@"DeSmuME Emulator", nil)];
|
||||||
|
@ -148,7 +156,8 @@ NSMenuItem *screenshot_to_file_item;
|
||||||
rect.origin.y = status_bar_height;
|
rect.origin.y = status_bar_height;
|
||||||
rect.size.width = DS_SCREEN_WIDTH;
|
rect.size.width = DS_SCREEN_WIDTH;
|
||||||
rect.size.height = DS_SCREEN_HEIGHT_COMBINED;
|
rect.size.height = DS_SCREEN_HEIGHT_COMBINED;
|
||||||
video_output_view = [[VideoOutputView alloc] initWithFrame:rect]; //no nil check - will do it's own error messages
|
//video_output_view = [[VideoOutputView alloc] initWithFrame:rect]; //no nil check - will do it's own error messages
|
||||||
|
video_output_view = nil;
|
||||||
[video_output_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; //view will automatically resize with the window
|
[video_output_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; //view will automatically resize with the window
|
||||||
|
|
||||||
[[window contentView] addSubview:video_output_view];
|
[[window contentView] addSubview:video_output_view];
|
||||||
|
@ -167,7 +176,7 @@ NSMenuItem *screenshot_to_file_item;
|
||||||
[window setDelegate:self]; //we do this after making the ouput/statusbar incase some delegate method gets called suddenly
|
[window setDelegate:self]; //we do this after making the ouput/statusbar incase some delegate method gets called suddenly
|
||||||
[controller = [[NSWindowController alloc] initWithWindow:window] showWindow:nil];
|
[controller = [[NSWindowController alloc] initWithWindow:window] showWindow:nil];
|
||||||
|
|
||||||
//Create the input manager
|
//Create the input manager and insert it into the cocoa responder chain
|
||||||
input = [[InputHandler alloc] initWithWindow:(id)self];
|
input = [[InputHandler alloc] initWithWindow:(id)self];
|
||||||
NSResponder *temp = [window nextResponder];
|
NSResponder *temp = [window nextResponder];
|
||||||
[window setNextResponder:input];
|
[window setNextResponder:input];
|
||||||
|
@ -178,11 +187,11 @@ NSMenuItem *screenshot_to_file_item;
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
|
[controller release];
|
||||||
|
[window release];
|
||||||
[video_output_view release];
|
[video_output_view release];
|
||||||
[status_view release];
|
[status_view release];
|
||||||
|
[input release];
|
||||||
[self retain]; //see the comment in init after we initialize the window controller
|
|
||||||
[controller release];
|
|
||||||
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
|
@ -472,14 +472,26 @@ struct NDS_fw_config_data firmware;
|
||||||
|
|
||||||
- (void)reset
|
- (void)reset
|
||||||
{
|
{
|
||||||
[execution_lock lock];
|
//note that the execution_lock method would probably be a little better
|
||||||
|
|
||||||
|
//but the NDS_Reset() function sets execution to false for some reason
|
||||||
|
//we treat execution == false as an emulation error
|
||||||
|
//pausing allows the other thread to not think theres an emulation error
|
||||||
|
|
||||||
|
//[execution_lock lock];
|
||||||
|
bool old_run = run;
|
||||||
|
if(old_run)
|
||||||
|
{
|
||||||
|
run = false;
|
||||||
|
while(!paused){}
|
||||||
|
}
|
||||||
|
|
||||||
NDS_Reset();
|
NDS_Reset();
|
||||||
|
|
||||||
[execution_lock unlock];
|
//[execution_lock unlock];
|
||||||
|
run = old_run;
|
||||||
|
|
||||||
//set the execute variable incase
|
//if there was a previous emulation error, clear it, since we reset
|
||||||
//of a previous emulation error
|
|
||||||
execute = true;
|
execute = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1186,7 +1198,7 @@ struct NDS_fw_config_data firmware;
|
||||||
if(!run)paused = true;
|
if(!run)paused = true;
|
||||||
|
|
||||||
//run the emulator
|
//run the emulator
|
||||||
while(run)
|
while(run && execute) //run controls when the emulator runs, execute prevents it from continuing execution if there are errors
|
||||||
{
|
{
|
||||||
|
|
||||||
paused = false;
|
paused = false;
|
||||||
|
@ -1198,7 +1210,9 @@ struct NDS_fw_config_data firmware;
|
||||||
cycles = NDS_exec((560190<<1)-cycles, FALSE);
|
cycles = NDS_exec((560190<<1)-cycles, FALSE);
|
||||||
|
|
||||||
[sound_lock lock];
|
[sound_lock lock];
|
||||||
SPU_Emulate();
|
int x;
|
||||||
|
for(x = 0; x <= frames_to_skip; x++)
|
||||||
|
SPU_Emulate();
|
||||||
[sound_lock unlock];
|
[sound_lock unlock];
|
||||||
|
|
||||||
[execution_lock unlock];
|
[execution_lock unlock];
|
||||||
|
@ -1227,40 +1241,39 @@ struct NDS_fw_config_data firmware;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//update the screen
|
//update the screen (and limit frame rate of video output)
|
||||||
ScreenState *new_screen_data = [[ScreenState alloc] init];
|
static long long last_video_update = 0;
|
||||||
[new_screen_data setColorData:GPU_screen];
|
if(frame_end_time - last_video_update > 10000)
|
||||||
if(timer_based)
|
|
||||||
{
|
{
|
||||||
[video_update_lock lock];
|
last_video_update = frame_end_time;
|
||||||
[current_screen release];
|
|
||||||
current_screen = new_screen_data;
|
ScreenState *new_screen_data = [[ScreenState alloc] init];
|
||||||
[video_update_lock unlock];
|
[new_screen_data setColorData:GPU_screen];
|
||||||
} else
|
|
||||||
{
|
if(timer_based)
|
||||||
//this will generate a warning when compiling on tiger or earlier, but it should
|
{ //for tiger compatibility
|
||||||
//be ok since the purpose of the if statement is to check if this will work
|
[video_update_lock lock];
|
||||||
[self performSelector:@selector(videoUpdateHelper:) onThread:gui_thread withObject:new_screen_data waitUntilDone:NO];
|
[current_screen release];
|
||||||
[new_screen_data release]; //performSelector will auto retain the screen data while the other thread displays
|
current_screen = new_screen_data;
|
||||||
|
[video_update_lock unlock];
|
||||||
|
} else
|
||||||
|
{ //for leopard and later
|
||||||
|
|
||||||
|
//this will generate a warning when compiling on tiger or earlier, but it should
|
||||||
|
//be ok since the purpose of the if statement is to check if this will work
|
||||||
|
[self performSelector:@selector(videoUpdateHelper:) onThread:gui_thread withObject:new_screen_data waitUntilDone:NO];
|
||||||
|
[new_screen_data release]; //performSelector will auto retain the screen data while the other thread displays
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
/* FIXME
|
|
||||||
//execute is set to false sometimes by the emulation core
|
//execute is set to false sometimes by the emulation core
|
||||||
//when there is an error, if this happens notify the other
|
//when there is an error, if this happens notify the other thread that emulation has stopped.
|
||||||
//thread that emulation has stopped.
|
|
||||||
if(!execute)
|
if(!execute)
|
||||||
{
|
if(!timer_based) //wont display an error on tiger or earlier
|
||||||
run = false; //stop executing
|
[error_object performSelector:error_func onThread:gui_thread withObject:nil waitUntilDone:YES];
|
||||||
execute = true; //reset the var, so if someone tries to execute again, we get the error again
|
|
||||||
|
|
||||||
[self performSelector:@selector(pause) onThread:gui_thread withObject:nil
|
|
||||||
waitUntilDone:NO modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
|
|
||||||
|
|
||||||
[error_object performSelector:error_func onThread:gui_thread withObject:nil
|
|
||||||
waitUntilDone:NO modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//when emulation is paused, return CPU time to the OS
|
//when emulation is paused, return CPU time to the OS
|
||||||
|
|
Loading…
Reference in New Issue